refactoring of file handling in ROM component

This commit is contained in:
hneemann 2021-04-25 14:31:33 +02:00
parent 258983caa9
commit 06b09c8723
19 changed files with 75 additions and 123 deletions

View File

@ -73,6 +73,13 @@ public class ElementAttributes implements HGSMap {
value = (VALUE) value.toString();
attributes.put(key.getKey(), value);
}
// needed to fix files with int pin numbers!
if (key == Keys.LAST_DATA_FILE && value instanceof String) {
value = (VALUE) new File(value.toString());
attributes.put(key.getKey(), value);
}
return value;
}
}

View File

@ -381,6 +381,12 @@ public final class Keys {
public static final Key<Boolean> AUTO_RELOAD_ROM
= new Key<>("autoReload", false).setSecondary();
/**
* The last used ROM data file
*/
public static final Key<File> LAST_DATA_FILE
= new Key.KeyFile("lastDataFile", new File("")).setDependsOn(AUTO_RELOAD_ROM).setSecondary();
/**
* flag to show the data table window
*/

View File

@ -5,7 +5,6 @@
*/
package de.neemann.digital.core.memory;
import de.neemann.digital.FileLocator;
import de.neemann.digital.core.*;
import de.neemann.digital.core.element.Element;
import de.neemann.digital.core.element.ElementAttributes;
@ -25,10 +24,6 @@ import static de.neemann.digital.core.element.PinInfo.input;
* A ROM module.
*/
public class ROM extends Node implements Element, ROMInterface, ProgramMemory {
/**
* Key used to store the source file in the attribute set
*/
public final static String LAST_DATA_FILE_KEY = "lastDataFile";
/**
* The ROMs {@link ElementTypeDescription}
@ -44,6 +39,7 @@ public class ROM extends Node implements Element, ROMInterface, ProgramMemory {
.addAttribute(Keys.INT_FORMAT)
.addAttribute(Keys.IS_PROGRAM_MEMORY)
.addAttribute(Keys.AUTO_RELOAD_ROM)
.addAttribute(Keys.LAST_DATA_FILE)
.supportsHDL();
private DataField data;
@ -51,14 +47,14 @@ public class ROM extends Node implements Element, ROMInterface, ProgramMemory {
private final ObservableValue output;
private final int addrBits;
private final int dataBits;
private final File hexFile;
private final boolean autoLoad;
private final boolean isProgramMemory;
private final ElementAttributes attr;
private final String label;
private ObservableValue addrIn;
private ObservableValue selIn;
private int addr;
private boolean sel;
private String label;
/**
* Creates a new instance
@ -71,12 +67,12 @@ public class ROM extends Node implements Element, ROMInterface, ProgramMemory {
data = attr.get(Keys.DATA);
addrBits = attr.get(Keys.ADDR_BITS);
autoLoad = attr.get(Keys.AUTO_RELOAD_ROM);
if (autoLoad)
this.attr = attr;
else
this.attr = null;
label = attr.getLabel();
isProgramMemory = attr.isProgramMemory();
if (autoLoad) {
hexFile = attr.getFile(LAST_DATA_FILE_KEY);
} else
hexFile = null;
formatter = attr.getValueFormatter();
}
@ -118,10 +114,10 @@ public class ROM extends Node implements Element, ROMInterface, ProgramMemory {
@Override
public void init(Model model) throws NodeException {
if (autoLoad) {
if (hexFile == null)
if (attr == null)
throw new NodeException(Lang.get("err_ROM_noFileGivenToLoad"), this, -1, null);
try {
File f = new FileLocator(hexFile).setLibraryRoot(model.getRootPath()).locate();
File f = attr.getFile(Keys.LAST_DATA_FILE, model.getRootPath());
data = Importer.read(f, dataBits);
} catch (IOException e) {
throw new NodeException(e.getMessage(), this, -1, null);

View File

@ -20,6 +20,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@ -376,6 +377,17 @@ public class AttributeDialog extends JDialog {
return null;
}
/**
* @return the root file or null if not available
*/
public File getRootFile() {
File root = null;
Main main = getMain();
if (main != null)
root = main.getLibrary().getRootFilePath();
return root;
}
/**
* @return the visual element of this dialog, maybe null
*/

View File

@ -40,6 +40,7 @@ import java.util.StringTokenizer;
*/
public class DataEditor extends JDialog {
private static final Color MYGRAY = new Color(230, 230, 230);
private static File lastUsedFileName;
private final ValueFormatter addrFormat;
private final int addrBits;
private final DataField localDataField;
@ -144,11 +145,10 @@ public class DataEditor extends JDialog {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new MyFileChooser();
if (fileName != null)
fc.setSelectedFile(fileName);
setFileNameTo(fc);
fc.setFileFilter(new FileNameExtensionFilter("hex", "hex"));
if (fc.showOpenDialog(DataEditor.this) == JFileChooser.APPROVE_OPTION) {
fileName = fc.getSelectedFile();
setFileName(fc.getSelectedFile());
try {
DataField dataRead = Importer.read(fc.getSelectedFile(), dataBits)
.trimValues(addrBits, dataBits);
@ -164,12 +164,11 @@ public class DataEditor extends JDialog {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new MyFileChooser();
if (fileName != null)
fc.setSelectedFile(fileName);
setFileNameTo(fc);
fc.setFileFilter(new FileNameExtensionFilter("hex", "hex"));
new SaveAsHelper(DataEditor.this, fc, "hex").checkOverwrite(
file -> {
fileName = fc.getSelectedFile();
setFileName(file);
localDataField.saveTo(file);
}
);
@ -266,14 +265,17 @@ public class DataEditor extends JDialog {
* @param fileName the filename
*/
public void setFileName(File fileName) {
this.fileName = fileName;
if (fileName.exists()) {
this.fileName = fileName;
lastUsedFileName = fileName;
}
}
/**
* @return the file name last used
*/
public File getFileName() {
return fileName;
private void setFileNameTo(JFileChooser fc) {
if (fileName != null)
fc.setSelectedFile(fileName);
else if (lastUsedFileName != null)
fc.setSelectedFile(lastUsedFileName);
}
/**

View File

@ -5,7 +5,6 @@
*/
package de.neemann.digital.gui.components;
import de.neemann.digital.FileLocator;
import de.neemann.digital.core.Bits;
import de.neemann.digital.core.*;
import de.neemann.digital.core.element.*;
@ -14,8 +13,6 @@ import de.neemann.digital.core.extern.PortDefinition;
import de.neemann.digital.core.io.InValue;
import de.neemann.digital.core.io.MIDIHelper;
import de.neemann.digital.core.memory.DataField;
import de.neemann.digital.core.memory.ROM;
import de.neemann.digital.core.memory.importer.Importer;
import de.neemann.digital.core.memory.rom.ROMManger;
import de.neemann.digital.draw.elements.PinException;
import de.neemann.digital.draw.elements.VisualElement;
@ -25,7 +22,6 @@ import de.neemann.digital.draw.model.InverterConfig;
import de.neemann.digital.draw.model.ModelCreator;
import de.neemann.digital.draw.shapes.custom.CustomShapeDescription;
import de.neemann.digital.gui.Main;
import de.neemann.digital.gui.SaveAsHelper;
import de.neemann.digital.gui.components.table.ShowStringDialog;
import de.neemann.digital.gui.components.testing.TestCaseDescriptionEditor;
import de.neemann.digital.lang.Lang;
@ -640,62 +636,19 @@ public final class EditorFactory {
int dataBits = attr.get(Keys.BITS);
int addrBits = getAddrBits(attr);
DataEditor de = new DataEditor(panel, data, dataBits, addrBits, false, SyncAccess.NOSYNC, attr.getValueFormatter());
de.setFileName(new FileLocator(attr.getFile(ROM.LAST_DATA_FILE_KEY))
.setupWithMain(getAttributeDialog().getMain())
.locate());
if (attr.get(Keys.AUTO_RELOAD_ROM))
de.setFileName(attr.getFile(Keys.LAST_DATA_FILE, getAttributeDialog().getRootFile()));
if (de.showDialog()) {
DataField mod = de.getModifiedDataField();
if (!data.equals(mod))
majorModification = true;
data = mod;
attr.setFile(ROM.LAST_DATA_FILE_KEY, de.getFileName());
}
} catch (EditorParseException e1) {
new ErrorMessage(Lang.get("msg_invalidEditorValue")).addCause(e1).show(panel);
}
}
}.createJButton());
panel.add(new ToolTipAction(Lang.get("btn_reload")) {
@Override
public void actionPerformed(ActionEvent e) {
try {
getAttributeDialog().storeEditedValues();
int dataBits = attr.get(Keys.BITS);
data = Importer.read(new FileLocator(attr.getFile(ROM.LAST_DATA_FILE_KEY))
.setupWithMain(getAttributeDialog().getMain())
.locate(), dataBits)
.trimValues(getAddrBits(attr), dataBits);
} catch (IOException e1) {
new ErrorMessage(Lang.get("msg_errorReadingFile")).addCause(e1).show(panel);
} catch (EditorParseException e1) {
new ErrorMessage(Lang.get("msg_invalidEditorValue")).addCause(e1).show(panel);
}
}
}
.setEnabledChain(attr.getFile(ROM.LAST_DATA_FILE_KEY) != null)
.setToolTip(Lang.get("btn_reload_tt"))
.createJButton()
);
panel.add(new ToolTipAction(Lang.get("btn_save")) {
@Override
public void actionPerformed(ActionEvent e) {
try {
getAttributeDialog().storeEditedValues();
final File file = new FileLocator(attr.getFile(ROM.LAST_DATA_FILE_KEY))
.setupWithMain(getAttributeDialog().getMain())
.locate();
data.saveTo(SaveAsHelper.checkSuffix(file, "hex"));
} catch (IOException e1) {
new ErrorMessage(Lang.get("msg_errorWritingFile")).addCause(e1).show(panel);
} catch (EditorParseException e1) {
new ErrorMessage(Lang.get("msg_invalidEditorValue")).addCause(e1).show(panel);
}
}
}
.setEnabledChain(attr.getFile(ROM.LAST_DATA_FILE_KEY) != null)
.setToolTip(Lang.get("btn_saveAsHex_tt"))
.createJButton()
);
return panel;
}
@ -814,10 +767,7 @@ public final class EditorFactory {
if (app != null) {
try {
getAttributeDialog().storeEditedValues();
File root = null;
Main main = getAttributeDialog().getMain();
if (main != null)
root = main.getLibrary().getRootFilePath();
File root = getAttributeDialog().getRootFile();
final boolean consistent = app.ensureConsistency(elementAttributes, root);
if (consistent)
getAttributeDialog().updateEditedValues();

View File

@ -681,14 +681,11 @@ public class Context implements HGSMap {
@Override
public Object call(Context c, ArrayList<Expression> args) throws HGSEvalException {
String name = args.get(0).value(c).toString();
File name = new File(args.get(0).value(c).toString());
int dataBits = Value.toInt(args.get(1).value(c));
FileLocator fileLocator = new FileLocator(name);
if (c.contains(BASE_FILE_KEY))
fileLocator.setBaseFile((File) c.getVar(BASE_FILE_KEY));
File hexFile = fileLocator.locate();
File hexFile = new FileLocator(name).setLibraryRoot(c.getRootPath()).locate();
if (hexFile == null)
if (hexFile == null || !hexFile.exists())
throw new HGSEvalException("File " + name + " not found! Is circuit saved?");
try {
@ -709,9 +706,7 @@ public class Context implements HGSMap {
@Override
public Object call(Context c, ArrayList<Expression> args) throws HGSEvalException {
File f = new File(args.get(0).value(c).toString());
File root = c.getRootPath();
if (root != null)
f = new FileLocator(f).setLibraryRoot(root).locate();
f = new FileLocator(f).setLibraryRoot(c.getRootPath()).locate();
try {
return Application.readCode(f);
} catch (IOException e) {

View File

@ -19,10 +19,7 @@
<string name="btn_edit">Bearbeiten</string>
<string name="btn_editFurther">Weiter bearbeiten</string>
<string name="btn_load">Laden</string>
<string name="btn_reload">Neu Laden</string>
<string name="btn_reload_tt">Letzte Datei noch einmal laden</string>
<string name="btn_save">Speichern</string>
<string name="btn_saveAsHex_tt">Als HEX-Datei speichern.</string>
<string name="btn_create">Erzeugen</string>
<string name="btn_create_tt">Erzeugt eine Schaltung in einem eigenen Fenster.</string>
<string name="btn_editDetached">Permanent Bearbeiten</string>
@ -1323,6 +1320,8 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
<string name="key_Height_tt">Höhe des Symbols, wenn diese Schaltung in eine andere eingefügt wird.</string>
<string name="key_autoReload">Bei jedem Start automatisch neu laden.</string><!-- ROM -->
<string name="key_autoReload_tt">Lädt das HEX-File bei jedem Modelstart neu.</string>
<string name="key_lastDataFile">Datei</string>
<string name="key_lastDataFile_tt">Datei die in das ROM geladen wird!</string>
<string name="key_flipSelPos">Tausche Selektorposition</string><!-- Driver, DriverInvSel, Multiplexer, Demultiplexer, Decoder -->
<string name="key_flipSelPos_tt">Mit dieser Option kann der Anschluss des Selektors auf die andere Seite des Multiplexers verschoben werden.</string>
<string name="key_intFormat">Zahlenformat</string><!-- Probe -->

View File

@ -19,10 +19,7 @@
<string name="btn_edit">Edit</string>
<string name="btn_editFurther">Continue editing</string>
<string name="btn_load">Load</string>
<string name="btn_reload">Reload</string>
<string name="btn_reload_tt">Reload last HEX file</string>
<string name="btn_save">Save</string>
<string name="btn_saveAsHex_tt">Save as HEX file.</string>
<string name="btn_create">Create</string>
<string name="btn_create_tt">Create a circuit in a separate window</string>
<string name="btn_editDetached">Edit detached</string>
@ -1304,6 +1301,8 @@
<string name="key_Height_tt">Height of symbol if this circuit is used as an component in an other circuit.</string>
<string name="key_autoReload">Reload at model start</string><!-- ROM -->
<string name="key_autoReload_tt">Reloads the HEX file every time the model is started.</string>
<string name="key_lastDataFile">File</string>
<string name="key_lastDataFile_tt">File to be loaded into the ROM.</string>
<string name="key_flipSelPos">Flip selector position
</string><!-- Driver, DriverInvSel, Multiplexer, Demultiplexer, Decoder -->
<string name="key_flipSelPos_tt">This option allows you to move te selector pin to the opposite side of the

View File

@ -25,10 +25,7 @@ In the file howTo.md you can find more details about translations.
<string name="btn_edit">Editar</string>
<string name="btn_editFurther">Seguir editando</string>
<string name="btn_load">Cargar</string>
<string name="btn_reload">Recargar</string>
<string name="btn_reload_tt">Recargar último archivo HEX</string>
<string name="btn_save">Guardar</string>
<string name="btn_saveAsHex_tt">Guardar como archivo HEX</string>
<string name="btn_create">Crear</string>
<string name="btn_create_tt">Crear un circuito en otra ventana</string>
<string name="btn_editDetached">Editar por separado</string>

View File

@ -24,10 +24,7 @@ In the file howTo.md you can find more details about translations.
<string name="btn_edit">Edit</string>
<string name="btn_editFurther">Continue editing</string>
<string name="btn_load">Load</string>
<string name="btn_reload">Reload</string>
<string name="btn_reload_tt">Reload last HEX file</string>
<string name="btn_save">Save</string>
<string name="btn_saveAsHex_tt">Save as HEX file.</string>
<string name="btn_create">Create</string>
<string name="btn_create_tt">Create a circuit in a separate window</string>
<string name="btn_editDetached">Edit detached</string>

View File

@ -25,10 +25,7 @@ In the file howTo.md you can find more details about translations.
<string name="btn_edit">Éditer</string>
<string name="btn_editFurther">Continuer l'édition</string>
<string name="btn_load">Charger</string>
<string name="btn_reload">Recharger</string>
<string name="btn_reload_tt">Recharger le dernier fichier HEX</string>
<string name="btn_save">Enregistrer</string>
<string name="btn_saveAsHex_tt">Enregistrer en fichier HEX.</string>
<string name="btn_create">Créer</string>
<string name="btn_create_tt">Créer un circuit dans une fenêtre séparée.</string>
<string name="btn_editDetached">Éditer séparément</string>

View File

@ -24,10 +24,7 @@ In the file howTo.md you can find more details about translations.
<string name="btn_edit">Edit</string>
<string name="btn_editFurther">Continue editing</string>
<string name="btn_load">Load</string>
<string name="btn_reload">Reload</string>
<string name="btn_reload_tt">Reload last HEX file</string>
<string name="btn_save">Save</string>
<string name="btn_saveAsHex_tt">Save as HEX file.</string>
<string name="btn_create">Create</string>
<string name="btn_create_tt">Create a circuit in a separate window</string>
<string name="btn_editDetached">Edit detached</string>

View File

@ -25,10 +25,7 @@ In the file howTo.md you can find more details about translations.
<string name="btn_edit">Editar</string>
<string name="btn_editFurther">Continuar edição</string>
<string name="btn_load">Carregar</string>
<string name="btn_reload">Recarregar</string>
<string name="btn_reload_tt">Recarregar último arquivo em hexadecimal</string>
<string name="btn_save">Salvar</string>
<string name="btn_saveAsHex_tt">Salvar como arquivo HEX.</string>
<string name="btn_create">Criar</string>
<string name="btn_create_tt">Criar circuito em janela separada</string>
<string name="btn_editDetached">Editar em separado</string>

View File

@ -24,10 +24,7 @@ In the file howTo.md you can find more details about translations.
<string name="btn_edit">Edit</string>
<string name="btn_editFurther">Continue editing</string>
<string name="btn_load">Load</string>
<string name="btn_reload">Reload</string>
<string name="btn_reload_tt">Reload last HEX file</string>
<string name="btn_save">Save</string>
<string name="btn_saveAsHex_tt">Save as HEX file.</string>
<string name="btn_create">Create</string>
<string name="btn_create_tt">Create a circuit in a separate window</string>
<string name="btn_editDetached">Edit detached</string>

View File

@ -25,10 +25,7 @@ In the file howTo.md you can find more details about translations.
<string name="btn_edit">编辑</string>
<string name="btn_editFurther">继续编辑</string>
<string name="btn_load">载入</string>
<string name="btn_reload">重新载入</string>
<string name="btn_reload_tt">重新载入最后使用的十六进制文件</string>
<string name="btn_save">保存</string>
<string name="btn_saveAsHex_tt">另存为十六进制文件</string>
<string name="btn_create">创建</string>
<string name="btn_create_tt">在新窗口中创建电路</string>
<string name="btn_editDetached">分离编辑</string>

View File

@ -24,10 +24,7 @@ In the file howTo.md you can find more details about translations.
<string name="btn_edit">Edit</string>
<string name="btn_editFurther">Continue editing</string>
<string name="btn_load">Load</string>
<string name="btn_reload">Reload</string>
<string name="btn_reload_tt">Reload last HEX file</string>
<string name="btn_save">Save</string>
<string name="btn_saveAsHex_tt">Save as HEX file.</string>
<string name="btn_create">Create</string>
<string name="btn_create_tt">Create a circuit in a separate window</string>
<string name="btn_editDetached">Edit detached</string>

View File

@ -3,7 +3,11 @@
panic("err_romNeedsALabelToBeExported");
romMaxSize := 1 << elem.AddrBits;
romSize := sizeOf(elem.Data);
data:=elem.Data;
if (elem.autoReload) {
data=loadHex(elem.lastDataFile, elem.Bits);
}
romSize := sizeOf(data);
moduleName = format("%s_%dX%d_%s", moduleName, romMaxSize, elem.Bits, identifier(elem.Label));
dBitRange := format("[%d:0]", elem.Bits - 1);
aBitRange := format("[%d:0]", elem.AddrBits - 1);
@ -30,7 +34,7 @@
initial begin<?
for (i := 0; i < romSize; i++) { ?>
my_rom[<?= i ?>] = <?= format("%d'h%x", elem.Bits, elem.Data[i]) ?>;<?
my_rom[<?= i ?>] = <?= format("%d'h%x", elem.Bits, data[i]) ?>;<?
} ?>
end
endmodule

View File

@ -6,6 +6,13 @@ use IEEE.NUMERIC_STD.ALL;
panic("err_romNeedsALabelToBeExported");
entityName:="DIG_ROM_"+identifier(elem.Label);
data:=elem.Data;
if (elem.autoReload) {
data=loadHex(elem.lastDataFile, elem.Bits);
}
len:=sizeOf(data);
?>
entity <?=entityName?> is
port (
@ -15,16 +22,15 @@ entity <?=entityName?> is
end <?=entityName?>;
architecture Behavioral of <?=entityName?> is
type mem is array ( 0 to <?=sizeOf(elem.Data)-1?>) of <?= vhdl.type(elem.Bits)?>;
type mem is array ( 0 to <?=len-1?>) of <?= vhdl.type(elem.Bits)?>;
constant my_Rom : mem := (
<?
len:=sizeOf(elem.Data);
maxCol:=76/(elem.Bits+4);
col:=0;
for (i:=0;i<len;i++) {
print( vhdl.value(elem.Data[i],elem.Bits));
print( vhdl.value(data[i],elem.Bits));
if (i<len-1) {
print(", ");
}
@ -41,7 +47,7 @@ begin
begin
if sel='0' then
D <= <? if (elem.Bits>1) {?>(others => 'Z')<? } else {?>'Z'<? } ?>;
elsif A > <?= vhdl.value(sizeOf(elem.Data)-1,elem.AddrBits)?> then
elsif A > <?= vhdl.value(len-1,elem.AddrBits)?> then
D <= <?= vhdl.zero(elem.Bits)?>;
else
D <= my_rom(to_integer(unsigned(A)));