mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-14 15:26:52 -04:00
first wortking stats dialog
This commit is contained in:
parent
47a0eaba90
commit
0655de855d
@ -762,4 +762,11 @@ public final class Keys {
|
||||
*/
|
||||
public static final Key<Boolean> MIDI_PROG_CHANGE =
|
||||
new Key<>("midiProgChange", false);
|
||||
|
||||
public static final Key<Integer> TRANSISTORS =
|
||||
new Key.KeyInteger("transistors", 0)
|
||||
.setMin(0)
|
||||
.setSecondary();
|
||||
|
||||
|
||||
}
|
||||
|
412
src/main/java/de/neemann/digital/draw/elements/Stats.java
Normal file
412
src/main/java/de/neemann/digital/draw/elements/Stats.java
Normal file
@ -0,0 +1,412 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Helmut Neemann.
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.draw.elements;
|
||||
|
||||
import de.neemann.digital.core.arithmetic.Add;
|
||||
import de.neemann.digital.core.arithmetic.Comparator;
|
||||
import de.neemann.digital.core.arithmetic.Sub;
|
||||
import de.neemann.digital.core.basic.*;
|
||||
import de.neemann.digital.core.element.ElementAttributes;
|
||||
import de.neemann.digital.core.element.ElementTypeDescription;
|
||||
import de.neemann.digital.core.element.Key;
|
||||
import de.neemann.digital.core.element.Keys;
|
||||
import de.neemann.digital.core.flipflops.FlipflopD;
|
||||
import de.neemann.digital.core.io.Const;
|
||||
import de.neemann.digital.core.io.In;
|
||||
import de.neemann.digital.core.io.Out;
|
||||
import de.neemann.digital.core.memory.RAMDualPort;
|
||||
import de.neemann.digital.core.memory.RAMSinglePort;
|
||||
import de.neemann.digital.core.memory.ROM;
|
||||
import de.neemann.digital.core.memory.Register;
|
||||
import de.neemann.digital.core.switching.NFET;
|
||||
import de.neemann.digital.core.switching.PFET;
|
||||
import de.neemann.digital.core.wiring.*;
|
||||
import de.neemann.digital.draw.library.ElementLibrary;
|
||||
import de.neemann.digital.draw.library.ElementNotFoundException;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
|
||||
import javax.swing.event.TableModelListener;
|
||||
import javax.swing.table.TableModel;
|
||||
import java.util.*;
|
||||
|
||||
public class Stats {
|
||||
private static ArrayList<Key> RELEVANT_KEYS = new ArrayList<>();
|
||||
|
||||
static {
|
||||
RELEVANT_KEYS.add(Keys.INPUT_COUNT);
|
||||
RELEVANT_KEYS.add(Keys.BITS);
|
||||
RELEVANT_KEYS.add(Keys.ADDR_BITS);
|
||||
RELEVANT_KEYS.add(Keys.SELECTOR_BITS);
|
||||
}
|
||||
|
||||
private static HashMap<String, TransistorCalculator> TRANSISTORS = new HashMap<>();
|
||||
|
||||
static {
|
||||
add(NFET.DESCRIPTION, ElementAttributes::getBits);
|
||||
add(PFET.DESCRIPTION, ElementAttributes::getBits);
|
||||
|
||||
add(NAnd.DESCRIPTION, attr -> attr.get(Keys.INPUT_COUNT) * attr.getBits() * 2);
|
||||
add(And.DESCRIPTION, attr -> (attr.get(Keys.INPUT_COUNT) * 2 + 2) * attr.getBits());
|
||||
add(NOr.DESCRIPTION, attr -> attr.get(Keys.INPUT_COUNT) * attr.getBits() * 2);
|
||||
add(Or.DESCRIPTION, attr -> (attr.get(Keys.INPUT_COUNT) * 2 + 2) * attr.getBits());
|
||||
add(XOr.DESCRIPTION, attr -> (attr.get(Keys.INPUT_COUNT) * 8) * attr.getBits());
|
||||
add(XNOr.DESCRIPTION, attr -> (attr.get(Keys.INPUT_COUNT) * 8 + 1) * attr.getBits());
|
||||
add(Not.DESCRIPTION, attr -> 2 * attr.getBits());
|
||||
add(Driver.DESCRIPTION, attr -> 6 * attr.getBits());
|
||||
add(DriverInvSel.DESCRIPTION, attr -> 6 * attr.getBits());
|
||||
add(DriverInvSel.DESCRIPTION, attr -> 6 * attr.getBits());
|
||||
add(Multiplexer.DESCRIPTION, attr -> {
|
||||
int sel = attr.get(Keys.SELECTOR_BITS);
|
||||
final int andInputs = sel + 1;
|
||||
final int orInputs = 1 << sel;
|
||||
return sel * 2 + ((1 << sel) * (andInputs * 2 + 2) + (orInputs * 2 + 2)) * attr.getBits();
|
||||
});
|
||||
add(Demultiplexer.DESCRIPTION, attr -> {
|
||||
int sel = attr.get(Keys.SELECTOR_BITS);
|
||||
final int andInputs = sel + 1;
|
||||
return sel * 2 + (1 << sel) * (andInputs * 2 + 2) * attr.getBits();
|
||||
});
|
||||
add(Decoder.DESCRIPTION, attr -> {
|
||||
int sel = attr.get(Keys.SELECTOR_BITS);
|
||||
return sel * 2 + (1 << sel) * (sel * 2 + 2) * attr.getBits();
|
||||
});
|
||||
add(FlipflopD.DESCRIPTION, attr -> 26 * attr.getBits());
|
||||
add(Register.DESCRIPTION, attr -> 30 * attr.getBits());
|
||||
|
||||
|
||||
add(Add.DESCRIPTION, attr -> 28 * attr.getBits());
|
||||
add(Sub.DESCRIPTION, attr -> 28 * attr.getBits());
|
||||
add(Comparator.DESCRIPTION, attr -> 38 * attr.getBits());
|
||||
final TransistorCalculator ram = attr -> 40 * attr.get(Keys.ADDR_BITS) + (1 << attr.get(Keys.ADDR_BITS)) * attr.getBits() * 6;
|
||||
add(RAMDualPort.DESCRIPTION, ram);
|
||||
add(RAMSinglePort.DESCRIPTION, ram);
|
||||
add(ROM.DESCRIPTION, attr -> 40 * attr.get(Keys.ADDR_BITS) + (1 << attr.get(Keys.ADDR_BITS)) * attr.getBits());
|
||||
}
|
||||
|
||||
private static void add(ElementTypeDescription description, TransistorCalculator tc) {
|
||||
TRANSISTORS.put(description.getName(), tc);
|
||||
}
|
||||
|
||||
private final ElementLibrary library;
|
||||
private TreeMap<EntryKey, Entry> map;
|
||||
|
||||
public Stats(ElementLibrary library) {
|
||||
this.library = library;
|
||||
map = new TreeMap<>();
|
||||
}
|
||||
|
||||
public Stats add(Circuit circuit) throws ElementNotFoundException {
|
||||
for (VisualElement ve : circuit.getElements()) {
|
||||
if (ve.equalsDescription(In.DESCRIPTION) ||
|
||||
ve.equalsDescription(Out.DESCRIPTION) ||
|
||||
ve.equalsDescription(Const.DESCRIPTION) ||
|
||||
ve.equalsDescription(Tunnel.DESCRIPTION) ||
|
||||
ve.equalsDescription(Splitter.DESCRIPTION) ||
|
||||
ve.equalsDescription(Clock.DESCRIPTION))
|
||||
continue;
|
||||
|
||||
ElementAttributes attr = ve.getElementAttributes();
|
||||
ElementTypeDescription description = library.getElementType(ve.getElementName());
|
||||
add(description, attr);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void add(ElementTypeDescription description, ElementAttributes attr) throws ElementNotFoundException {
|
||||
int transistors = 0;
|
||||
Circuit childCircuit = null;
|
||||
if (description instanceof ElementLibrary.ElementTypeDescriptionCustom) {
|
||||
ElementLibrary.ElementTypeDescriptionCustom c = (ElementLibrary.ElementTypeDescriptionCustom) description;
|
||||
childCircuit = c.getCircuit();
|
||||
transistors = childCircuit.getAttributes().get(Keys.TRANSISTORS);
|
||||
if (transistors > 0)
|
||||
childCircuit = null;
|
||||
} else {
|
||||
TransistorCalculator tr = TRANSISTORS.get(description.getName());
|
||||
if (tr != null)
|
||||
transistors = tr.transistors(attr);
|
||||
}
|
||||
|
||||
EntryKey key = new EntryKey(description, attr, transistors);
|
||||
Entry e = map.get(key);
|
||||
if (e == null) {
|
||||
e = new Entry(key);
|
||||
map.put(key, e);
|
||||
}
|
||||
e.addOne();
|
||||
|
||||
if (childCircuit != null)
|
||||
add(childCircuit);
|
||||
}
|
||||
|
||||
public TableModel getTableModel() {
|
||||
final ArrayList<Row> entries = new ArrayList<>(map.size());
|
||||
int tr = 0;
|
||||
for (Entry e : map.values()) {
|
||||
entries.add(e);
|
||||
tr += e.getTransistors();
|
||||
}
|
||||
final int transistors = tr;
|
||||
entries.add(new Row() {
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return Lang.get("stat_sum");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTransistorsEach() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTransistors() {
|
||||
return transistors;
|
||||
}
|
||||
});
|
||||
|
||||
return new MyTableModel(entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int transistors = 0;
|
||||
for (Entry e : map.values()) {
|
||||
sb.append(e.toString());
|
||||
sb.append("\n");
|
||||
transistors += e.getTransistors();
|
||||
}
|
||||
if (transistors > 0)
|
||||
sb.append(transistors).append(" transistors total");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static class EntryKey implements Comparable<EntryKey> {
|
||||
private final String name;
|
||||
private final int transistors;
|
||||
private final HashMap<Key, Object> map;
|
||||
|
||||
private EntryKey(ElementTypeDescription description, ElementAttributes attr, int transistors) {
|
||||
this.name = description.getTranslatedName();
|
||||
this.transistors = transistors;
|
||||
this.map = new HashMap<>();
|
||||
for (Key k : description.getAttributeList()) {
|
||||
if (RELEVANT_KEYS.contains(k))
|
||||
map.put(k, attr.get(k));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = getDescriptionInt();
|
||||
if (transistors > 0)
|
||||
sb.append("; ").append(transistors).append(" transistors each");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
StringBuilder getDescriptionInt() {
|
||||
StringBuilder sb = new StringBuilder(name);
|
||||
if (!map.isEmpty()) {
|
||||
sb.append(" (");
|
||||
boolean first = true;
|
||||
for (Key k : RELEVANT_KEYS) {
|
||||
Object v = map.get(k);
|
||||
if (v != null) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
sb.append(", ");
|
||||
sb.append(k.toString());
|
||||
sb.append(":");
|
||||
sb.append(v);
|
||||
}
|
||||
}
|
||||
sb.append(")");
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return getDescriptionInt().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
EntryKey entryKey = (EntryKey) o;
|
||||
return transistors == entryKey.transistors &&
|
||||
name.equals(entryKey.name) &&
|
||||
map.equals(entryKey.map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, transistors, map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(EntryKey entryKey) {
|
||||
int c = name.compareTo(entryKey.name);
|
||||
if (c != 0) return c;
|
||||
for (Key k : RELEVANT_KEYS) {
|
||||
c = check(k, entryKey);
|
||||
if (c != 0) return c;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int check(Key key, EntryKey entryKey) {
|
||||
Object a = map.get(key);
|
||||
Object b = entryKey.map.get(key);
|
||||
if (a == null & b == null) return 0;
|
||||
if (a instanceof Long)
|
||||
return Long.compare((Long) a, (Long) b);
|
||||
if (a instanceof Integer)
|
||||
return Integer.compare((Integer) a, (Integer) b);
|
||||
if (a instanceof String)
|
||||
return ((String) a).compareTo((String) b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class Entry implements Row {
|
||||
|
||||
private final EntryKey key;
|
||||
private int count;
|
||||
|
||||
private Entry(EntryKey key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
private void addOne() {
|
||||
count++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return count + " x " + key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return key.getDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTransistorsEach() {
|
||||
return key.transistors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTransistors() {
|
||||
return count * key.transistors;
|
||||
}
|
||||
}
|
||||
|
||||
private interface TransistorCalculator {
|
||||
int transistors(ElementAttributes attr);
|
||||
}
|
||||
|
||||
private interface Row {
|
||||
|
||||
int getCount();
|
||||
|
||||
String getDescription();
|
||||
|
||||
int getTransistorsEach();
|
||||
|
||||
int getTransistors();
|
||||
}
|
||||
|
||||
private static class MyTableModel implements TableModel {
|
||||
private final List<Row> entries;
|
||||
|
||||
private MyTableModel(List<Row> entries) {
|
||||
this.entries = entries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return entries.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
return Lang.get("stat_number");
|
||||
case 1:
|
||||
return Lang.get("stat_part");
|
||||
case 2:
|
||||
return Lang.get("stat_transistors");
|
||||
default:
|
||||
return Lang.get("stat_transistorsTotal");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getColumnClass(int i) {
|
||||
if (i == 1)
|
||||
return String.class;
|
||||
return Integer.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int i, int i1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int row, int col) {
|
||||
Row r = entries.get(row);
|
||||
switch (col) {
|
||||
case 0:
|
||||
return check(r.getCount());
|
||||
case 1:
|
||||
return r.getDescription();
|
||||
case 2:
|
||||
return check(r.getTransistorsEach());
|
||||
default:
|
||||
return check(r.getTransistors());
|
||||
}
|
||||
}
|
||||
|
||||
private Object check(int i) {
|
||||
if (i > 0) return i;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueAt(Object o, int row, int col) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableModelListener(TableModelListener tableModelListener) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTableModelListener(TableModelListener tableModelListener) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -378,6 +378,19 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
});
|
||||
treeCheckBox.setAccelerator(KeyStroke.getKeyStroke("F5"));
|
||||
|
||||
ToolTipAction stats = new ToolTipAction(Lang.get("menu_stats")) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
try {
|
||||
Stats stats = new Stats(library);
|
||||
stats.add(circuitComponent.getCircuit());
|
||||
new StatsDialog(Main.this, stats.getTableModel()).setVisible(true);
|
||||
} catch (ElementNotFoundException e) {
|
||||
new ErrorMessage(Lang.get("msg_couldNotCreateStats")).addCause(e).show(Main.this);
|
||||
}
|
||||
}
|
||||
}.setToolTip(Lang.get("menu_stats_tt"));
|
||||
|
||||
if (Settings.getInstance().get(Keys.SETTINGS_DEFAULT_TREESELECT))
|
||||
SwingUtilities.invokeLater(treeCheckBox::doClick);
|
||||
|
||||
@ -395,6 +408,7 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
view.add(treeCheckBox);
|
||||
view.addSeparator();
|
||||
view.add(viewHelp.createJMenuItem());
|
||||
view.add(stats.createJMenuItem());
|
||||
}
|
||||
|
||||
/**
|
||||
|
41
src/main/java/de/neemann/digital/gui/StatsDialog.java
Normal file
41
src/main/java/de/neemann/digital/gui/StatsDialog.java
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Helmut Neemann.
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.gui;
|
||||
|
||||
import de.neemann.digital.lang.Lang;
|
||||
import de.neemann.gui.Screen;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
import javax.swing.table.TableModel;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* Dialog used to show the circuits stats
|
||||
*/
|
||||
public class StatsDialog extends JDialog {
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param frame the parent frame
|
||||
* @param model the table model
|
||||
*/
|
||||
public StatsDialog(Frame frame, TableModel model) {
|
||||
super(frame, Lang.get("menu_stats"));
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
|
||||
final JTable table = new JTable(model);
|
||||
getContentPane().add(new JScrollPane(table));
|
||||
final TableColumnModel columnModel = table.getColumnModel();
|
||||
final int fontSize = Screen.getInstance().getFontSize();
|
||||
columnModel.getColumn(1).setPreferredWidth(fontSize * 60);
|
||||
table.setPreferredScrollableViewportSize(new Dimension(fontSize * 70, fontSize * 20));
|
||||
|
||||
pack();
|
||||
setLocationRelativeTo(frame);
|
||||
}
|
||||
}
|
@ -77,6 +77,7 @@ public class CircuitComponent extends JComponent implements Circuit.ChangedListe
|
||||
ATTR_LIST.add(Keys.SHOW_DATA_GRAPH_MICRO);
|
||||
ATTR_LIST.add(Keys.PRELOAD_PROGRAM);
|
||||
ATTR_LIST.add(Keys.PROGRAM_TO_PRELOAD);
|
||||
ATTR_LIST.add(Keys.TRANSISTORS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1319,6 +1319,8 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
|
||||
<string name="key_midiProgChange">Programmwechsel erlauben</string>
|
||||
<string name="key_midiProgChange_tt">Fügt einen weiteren Eingang PC hinzu. Wird dieser Eingang auf High gesetzt,
|
||||
wird mit dem Wert am Eingang N das Programm (Instrument) gewechselt.</string>
|
||||
<string name="key_transistors">Transistorzahl</string>
|
||||
<string name="key_transistors_tt">Anzahl der erforderlichen Transistoren. Wird für die Schaltungsstatistik verwendet. Null bedeutet, dass die Zahl automatisch bestimmt wird.</string>
|
||||
|
||||
<string name="mod_insertWire">Leitung eingefügt.</string>
|
||||
<string name="mod_insertCopied">Aus Zwischenablage eingefügt.</string>
|
||||
@ -1542,6 +1544,15 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
|
||||
<string name="menu_labelPins">Ein- und Ausgänge benennen</string>
|
||||
<string name="menu_labelPins_tt">Für alle unbenannten Ein- und Ausgänge eine Bezeichnung setzen.</string>
|
||||
|
||||
|
||||
<string name="menu_stats">Schaltungsstatistik</string>
|
||||
<string name="menu_stats_tt">Zeigt eine Liste der verwendeten Komponenten</string>
|
||||
<string name="stat_number">Zahl</string>
|
||||
<string name="stat_part">Bauteil</string>
|
||||
<string name="stat_transistors">Trans.</string>
|
||||
<string name="stat_transistorsTotal">Trans. total</string>
|
||||
<string name="stat_sum">Summe</string>
|
||||
|
||||
<string name="msg_errorOpeningDocumentation">Fehler beim Öffnen einer PDF-Datei!</string>
|
||||
|
||||
<string name="message"><h1>Digital</h1>Ein einfacher Simulator für digitale Schaltkreise.
|
||||
|
@ -1309,6 +1309,10 @@
|
||||
<string name="key_midiProgChange_tt">Adds a new input PC. If this input is set to high,
|
||||
the value at input N is used to change te program (instrument).</string>
|
||||
|
||||
<string name="key_transistors">Transistors</string>
|
||||
<string name="key_transistors_tt">Number of transistors required. Used for circuit statistics.
|
||||
Zero means that the number is determined automatically.</string>
|
||||
|
||||
<string name="mod_insertWire">Inserted wire.</string>
|
||||
<string name="mod_insertCopied">Insert from clipboard.</string>
|
||||
<string name="mod_setKey_N0_in_element_N1">Value ''{0}'' in component ''{1}'' modified.</string>
|
||||
@ -1528,6 +1532,14 @@
|
||||
<string name="menu_labelPins">Label Inputs and Outputs</string>
|
||||
<string name="menu_labelPins_tt">Set a label to all inputs and outputs without a label.</string>
|
||||
|
||||
<string name="menu_stats">Circuit Statistics</string>
|
||||
<string name="menu_stats_tt">Shows a list of used components.</string>
|
||||
<string name="stat_number">Number</string>
|
||||
<string name="stat_part">Component</string>
|
||||
<string name="stat_transistors">Trans.</string>
|
||||
<string name="stat_transistorsTotal">Trans. total</string>
|
||||
<string name="stat_sum">Sum</string>
|
||||
|
||||
|
||||
<string name="message"><h1>Digital</h1>A simple simulator for digital circuits.
|
||||
Written by H. Neemann in 2016-2019.
|
||||
|
Loading…
x
Reference in New Issue
Block a user