📄 epicreaderprocess.java
字号:
/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: EpicReaderProcess.java * Input/output tool: external reader for EPIC output (.out) * * Copyright (c) 2005 Sun Microsystems and Static Free Software * * Electric(tm) 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. * * Electric(tm) 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 Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */package com.sun.electric.tool.io.input;import java.io.BufferedOutputStream;import java.io.DataOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.net.URL;import java.net.URLConnection;import java.util.ArrayList;import java.util.HashMap;import java.util.regex.Pattern;/** * This class is a launched in external JVM to read Epic output file. * It doesn't import other Electric modules. * Waveforms are stored in temporary file. * Signal names are passed to std out using the following syntax: * StdOut :== signames resolutions signalInfo* fileName * signames :== ( up | down | signal )* 'F' * up :== 'U' * down :== 'D' stringRef * signal :== ( 'V' | 'I' ) stringRef * stringRef= INT [ UDF ] * resolutions :== timeResolution voltageResolution currentResolution timeMax * timeResolution :== DOUBLE * voltageResolution :== DOUBLE * currentResolution :== DOUBLE * timeMax :== DOUBLE * signalInfo :== minV maxV packedLength * minV :== INT * maxV :== INT * packedLength :== INT * fileName :== UDF * * Inititially current context i sempty. * 'D' pushes a string to it. * 'U' pops a string. * 'V' and 'I' use the current context. * * stringRef starts with a number. If this number is a new number then it is followed by definition of this string, * otherwise it is reference of previously defined string. * Number of signalInfo is equal to number of defined signals. * fileName is a name of temporary file on local machine with packed waveform data. * length in signalInfo is a number of bytes occupied in the file by this signal. */class EpicReaderProcess { /** Input stream with Epic data. */ private InputStream inputStream; /** File length of inputStream. */ private long fileLength; /** Number of bytes read from stream to buffer. */ private long byteCount; /** Buffer for parsing. */ private byte[] buf = new byte[65536]; /** Count of valid bytes in buffer. */ private int bufL; /** Count of parsed bytes in buffer. */ private int bufP; /** Count of parsed lines. */ private int lineNum; /** String builder to build input line. */ private StringBuilder builder = new StringBuilder(); /** Pattern used to split input line into pieces. */ private Pattern whiteSpace = Pattern.compile("[ \t]+"); /** Last value of progress indicater (percents(.*/ private byte lastProgress; /** A map from Strings to Integer ids. */ private HashMap<String,Integer> stringIds = new HashMap<String,Integer>(); /** Chronological list of signals. */ private ArrayList<EpicReaderSignal> signals = new ArrayList<EpicReaderSignal>(); /** Sparce list to access signals by their Epic indices. */ private ArrayList<EpicReaderSignal> signalsByEpicIndex = new ArrayList<EpicReaderSignal>(); /** Time resolution from input file. */ private double timeResolution; /** Voltage resolution from input file. */ private double voltageResolution; /** Current resolution from input file. */ private double currentResolution; /** Current time (in integer units). */ private int curTime = 0; /** A stack of signal context pieces. */ private ArrayList<String> contextStack = new ArrayList<String>(); /** Count of timepoints for statistics. */ private int timesC = 0; /** Count of signal events for statistics. */ private int eventsC = 0; /* DataOutputStream view of standard output. */ private DataOutputStream stdOut = new DataOutputStream(System.out); /** Epic format we are able to read. */ private static final String VERSION_STRING = ";! output_format 5.3"; /** Epic separator char. */ private static final char separator = '.'; /** Private constructor. */ private EpicReaderProcess() {} /** * Main program of external JVM for reading Epic files. */ public static void main(String args[]) { try { EpicReaderProcess process = new EpicReaderProcess(); try { process.readEpic(args[0]); } catch (IOException e) { System.err.println("Failed to read " + args[0]); e.printStackTrace(System.err); System.exit(1); } process.writeOut(); } catch (OutOfMemoryError e) { System.err.println("Out of memory. Increase memory limit in preferences."); e.printStackTrace(System.err); System.exit(2); } catch (Throwable e) { e.printStackTrace(System.err); System.exit(3); } } /** * Reads Epic file into memory. * Writes signal names to stdout. * @param urlName url name of Epic file. */ private void readEpic(String urlName) throws IOException { URL fileURL = new URL(urlName); long startTime = System.currentTimeMillis(); URLConnection urlCon = fileURL.openConnection(); urlCon.setConnectTimeout(10000); urlCon.setReadTimeout(1000); String contentLength = urlCon.getHeaderField("content-length"); fileLength = -1; try { fileLength = Long.parseLong(contentLength); } catch (Exception e) {} inputStream = urlCon.getInputStream(); byteCount = 0; String firstLine = getLine(); if (firstLine == null || !firstLine.equals(VERSION_STRING)) { message("Unknown Epic Version: " + firstLine); } for (;;) { if (bufP >= bufL && readBuf()) break; int startLine = bufP; if (parseNumLineFast()) continue; bufP = startLine; String line = getLine(); assert bufP <= bufL; if (line == null) break; parseNumLine(line); } writeContext(""); inputStream.close(); long stopTime = System.currentTimeMillis(); System.err.println((stopTime - startTime)/1000.0 + " sec to read " + byteCount + " bytes " + signals.size() + " signals " + stringIds.size() + " strings " + timesC + " timepoints " + eventsC + " events from " + urlName); } /** * Parses line from Epic file. */ private void parseNumLine(String line) throws IOException { if (line.length() == 0) return; char ch = line.charAt(0); if (ch == '.') { String[] split = whiteSpace.split(line); if (split[0].equals(".index") && split.length == 4) { byte type; if (split[3].equals("v")) type = 'V'; else if (split[3].equals("i")) type = 'I'; else { message("Unknown waveform type: " + line); return; } String name = split[1]; int sigNum = atoi(split[2]); while (signalsByEpicIndex.size() <= sigNum) signalsByEpicIndex.add(null); EpicReaderSignal s = signalsByEpicIndex.get(sigNum); if (s == null) { s = new EpicReaderSignal(); signalsByEpicIndex.set(sigNum, s); signals.add(s); } // name the signal if (name.startsWith("v(") && name.endsWith(")")) { name = name.substring(2, name.length() - 1); } else if (name.startsWith("i(") && name.endsWith(")")) { name = name.substring(2, name.length() - 1); } else if (name.startsWith("i1(") && name.endsWith(")")) { name = name.substring(3, name.length() - 1); } int lastSlashPos = name.lastIndexOf(separator); String contextName = ""; if (lastSlashPos > 0) { contextName = name.substring(0, lastSlashPos + 1); } name = name.substring(lastSlashPos + 1); if (type == 'I') name = "i(" + name + ")"; writeContext(contextName); stdOut.writeByte(type); writeString(name); } else if (split[0].equals(".vdd") && split.length == 2) { } else if (split[0].equals(".time_resolution") && split.length == 2) { timeResolution = atof(split[1]) * 1e-9; } else if (split[0].equals(".current_resolution") && split.length == 2) { currentResolution = atof(split[1]); } else if (split[0].equals(".voltage_resolution") && split.length == 2) { voltageResolution = atof(split[1]); } else if (split[0].equals(".high_threshold") && split.length == 2) { } else if (split[0].equals(".low_threshold") && split.length == 2) { } else if (split[0].equals(".nnodes") && split.length == 2) { } else if (split[0].equals(".nelems") && split.length == 2) { } else if (split[0].equals(".extra_nodes") && split.length == 2) { } else if (split[0].equals(".bus_notation") && split.length == 4) { } else if (split[0].equals(".hier_separator") && split.length == 2) { } else if (split[0].equals(".case") && split.length == 2) { } else { message("Unrecognized Epic line: " + line); } } else if (ch >= '0' && ch <= '9') { String[] split = whiteSpace.split(line); int num = atoi(split[0]); if (split.length > 1) { putValue(num, atoi(split[1])); } else { putTime(num); } } else if (ch == ';' || Character.isSpaceChar(ch)) { } else { message("Unrecognized Epic line: " + line); } } /** * Writes new context as diff to previous context. * @param s string with new context. */ private void writeContext(String s) throws IOException { int matchSeps = 0; int pos = 0; matchLoop: while (matchSeps < contextStack.size()) { String si = contextStack.get(matchSeps); if (pos < s.length() && s.charAt(pos) == 'x') pos++; if (pos + si.length() >= s.length() || s.charAt(pos + si.length()) != separator) break; for (int k = 0; k < si.length(); k++) if (s.charAt(pos + k) != si.charAt(k)) break matchLoop; matchSeps++; pos += si.length() + 1; } while (contextStack.size() > matchSeps) { stdOut.writeByte('U'); contextStack.remove(contextStack.size() - 1); } assert contextStack.size() == matchSeps; while (pos < s.length()) { int indexOfSep = s.indexOf(separator, pos); assert indexOfSep >= pos; stdOut.writeByte('D'); if (pos < indexOfSep && s.charAt(pos) == 'x') pos++; String si = s.substring(pos, indexOfSep); writeString(si); contextStack.add(si); pos = indexOfSep + 1; } assert pos == s.length(); } /** * Writes string to stdOut. * It writes its chronological number. * It writes string itself, if it is a new string. * @param s string to write. */ private void writeString(String s) throws IOException { if (s == null) { stdOut.writeInt(-1); return; } Integer i = stringIds.get(s); if (i != null) { stdOut.writeInt(i.intValue()); return; } stdOut.writeInt(stringIds.size()); i = new Integer(stringIds.size()); s = new String(s); // To avoid long char array of substrings stringIds.put(s, i); stdOut.writeUTF(s); } /** * Fast routine to parse a line from buffer. * It either recognizes a simple line or rejects. * @return true if this method recognized a line. */ private boolean parseNumLineFast() { final int MAX_DIGITS = 9; if (bufP + (MAX_DIGITS*2 + 4) >= bufL) return false; int ch = buf[bufP++]; if (ch < '0' || ch > '9') return false; int num1 = ch - '0'; ch = buf[bufP++]; for (int lim = bufP + (MAX_DIGITS - 1); '0' <= ch && ch <= '9' && bufP < lim; ch = buf[bufP++]) num1 = num1*10 + (ch - '0'); boolean twoNumbers = false; int num2 = 0; if (ch == ' ') { ch = buf[bufP++]; boolean sign = false; if (ch == '-') { sign = true; ch = buf[bufP++]; } if (ch < '0' || ch > '9') return false; num2 = ch - '0'; ch = buf[bufP++]; for (int lim = bufP + (MAX_DIGITS - 1); '0' <= ch && ch <= '9' && bufP < lim; ch = buf[bufP++]) num2 = num2*10 + (ch - '0'); if (sign) num2 = -num2; twoNumbers = true; } if (ch == '\n') { } else if (ch == '\r') { if (buf[bufP] == '\n')
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -