allow toolchain config parameters

This commit is contained in:
hneemann 2019-05-20 07:42:12 +02:00
parent bdafd03aa4
commit da72a50323
7 changed files with 106 additions and 64 deletions

View File

@ -7,10 +7,15 @@
<arg>vivado/&lt;?=shortname?&gt;.xpr</arg> <arg>vivado/&lt;?=shortname?&gt;.xpr</arg>
</command> </command>
</commands> </commands>
<params>
<!-- used by the Vivado project template -->
<param name="chip">xc7a35ticpg236-1L</param>
<param name="extension">.vhdl</param>
</params>
<files> <files>
<file name="clockGenerator.vhdl" overwrite="true" filter="true" id="MMCME2_BASE"> <file name="clockGenerator.vhdl" overwrite="true" filter="true" id="MMCME2_BASE">
<content><![CDATA[ <content><![CDATA[
<? if (hdl.frequency<4687500) { ?> <? if (model.frequency<4687500) { ?>
LIBRARY ieee; LIBRARY ieee;
USE ieee.std_logic_1164.all; USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all; USE ieee.numeric_std.all;
@ -22,7 +27,7 @@ entity clockGenerator is
cin: in std_logic ); cin: in std_logic );
end clockGenerator; end clockGenerator;
<? maxCounter:=100000000 / (2 * hdl.frequency);?> <? maxCounter:=100000000 / (2 * model.frequency);?>
architecture Behavioral of clockGenerator is architecture Behavioral of clockGenerator is
-- Don't use a logic signal as clock source in a real world application! -- Don't use a logic signal as clock source in a real world application!
@ -89,7 +94,7 @@ begin
M_IDEAL := D_MIN*VCO_MAX/F_IN; M_IDEAL := D_MIN*VCO_MAX/F_IN;
F_DES := hdl.frequency/1000000.0; F_DES := model.frequency/1000000.0;
bestError:=F_DES; bestError:=F_DES;
bestErrorM:=M_MAX; bestErrorM:=M_MAX;
@ -205,11 +210,11 @@ end Behavioral;
<? } ?> <? } ?>
]]></content> ]]></content>
</file> </file>
<file name="&lt;?=shortname?&gt;_constraints.xdc" overwrite="true" filter="true"> <file name="&lt;?=shortname?&gt;_constraints.xdc" overwrite="true" filter="true" id="constraints.xdc">
<content><![CDATA[<? <content><![CDATA[<?
for (i:=0; i<sizeOf(hdl.ports);i++) { for (i:=0; i<sizeOf(model.ports);i++) {
port:=hdl.ports[i]; port:=model.ports[i];
if (port.bits=1) { if (port.bits=1) {
print("set_property PACKAGE_PIN "+port.pin+" [get_ports "+port.name+"]\n"); print("set_property PACKAGE_PIN "+port.pin+" [get_ports "+port.name+"]\n");
print("set_property IOSTANDARD LVCMOS33 [get_ports "+port.name+"]\n\n"); print("set_property IOSTANDARD LVCMOS33 [get_ports "+port.name+"]\n\n");
@ -225,30 +230,32 @@ print("set_property CONFIG_VOLTAGE 3.3 [current_design]\n");
?>]]></content> ?>]]></content>
</file> </file>
<file name="vivado/&lt;?=shortname?&gt;.xpr" overwrite="false" filter="true"> <file name="vivado/&lt;?=shortname?&gt;.xpr" overwrite="false" filter="true" id="vivado">
<content><![CDATA[<?print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");?> <content><![CDATA[<?print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");?>
<!-- Created by Digital --> <!-- Created by Digital -->
<Project Version="7" Minor="20" Path="<?=dir?>/vivado/<?=shortname?>.xpr"> <Project Version="7" Minor="20" Path="<?=dir?>/vivado/<?=shortname?>.xpr">
<DefaultLaunch Dir="$PRUNDIR"/> <DefaultLaunch Dir="$PRUNDIR"/>
<Configuration> <Configuration>
<Option Name="Part" Val="xc7a35ticpg236-1L"/> <Option Name="Part" Val="<?=chip?>"/>
</Configuration> </Configuration>
<FileSets Version="1" Minor="31"> <FileSets Version="1" Minor="31">
<FileSet Name="sources_1" Type="DesignSrcs" RelSrcDir="$PSRCDIR/sources_1"> <FileSet Name="sources_1" Type="DesignSrcs" RelSrcDir="$PSRCDIR/sources_1">
<Filter Type="Srcs"/> <Filter Type="Srcs"/>
<File Path="$PPRDIR/../<?=shortname?>.vhdl"> <File Path="$PPRDIR/../<?=shortname?><?=extension?>">
<FileInfo> <FileInfo>
<Attr Name="UsedIn" Val="synthesis"/> <Attr Name="UsedIn" Val="synthesis"/>
<Attr Name="UsedIn" Val="simulation"/> <Attr Name="UsedIn" Val="simulation"/>
</FileInfo> </FileInfo>
</File> </File>
<File Path="$PPRDIR/../clockGenerator.vhdl"> <? if (isPresent("clockGenerator")) { ?>
<File Path="$PPRDIR/../<?=clockGenerator?><?=extension?>">
<FileInfo> <FileInfo>
<Attr Name="UsedIn" Val="synthesis"/> <Attr Name="UsedIn" Val="synthesis"/>
<Attr Name="UsedIn" Val="simulation"/> <Attr Name="UsedIn" Val="simulation"/>
</FileInfo> </FileInfo>
</File> </File>
<? } ?>
<Config> <Config>
<Option Name="DesignMode" Val="RTL"/> <Option Name="DesignMode" Val="RTL"/>
<Option Name="TopModule" Val="main"/> <Option Name="TopModule" Val="main"/>

View File

@ -1,20 +1,25 @@
<!-- if a clockGenerator is given, this config needs to create the required source code --> <!-- if a clockGenerator is given, this config needs to create the required source code -->
<toolchain name="VerilogClockTest" clockGenerator="clockGenerator"> <toolchain name="VerilogClockExample" clockGenerator="clockGenerator">
<commands> <commands>
<command name="Export" requires="verilog"/> <command name="Export" requires="verilog"/>
</commands> </commands>
<params>
<!-- used by the Vivado project template -->
<param name="chip">xc7a35ticpg236-1L</param>
<param name="extension">.v</param>
</params>
<files> <files>
<file name="clockGenerator.v" overwrite="true" filter="true"> <file name="clockGenerator.v" overwrite="true" filter="true">
<content><![CDATA[<? <content><![CDATA[<?
// Add the board specific clock generation here! // Add the board specific clock generation here!
// This example assumes a 100MHz clock and creates a simple clock divider to // This example assumes a 100MHz clock and creates a simple clock divider to
// match the input clock frequency given in the circuit. // match the input clock frequency given in the circuit.
// The variable hdl.frequency holds the frequency selected in the circuits // The variable model.frequency holds the frequency selected in the circuits
// clock component. // clock component.
board_f := 100000000; // assuming a 100MHz clock board_frequency := 100000000; // assuming a 100MHz clock
maxCounter := board_f/hdl.frequency/2; maxCounter := board_frequency/model.frequency/2;
bits := bitsNeededFor(maxCounter); bits := bitsNeededFor(maxCounter);
?>module clockGenerator ?>module clockGenerator
@ -45,42 +50,6 @@ endmodule
]]></content> ]]></content>
</file> </file>
<!-- creates a vivado project file which simplifies testing --> <!-- creates a vivado project file which simplifies testing -->
<file name="vivado/&lt;?=shortname?&gt;.xpr" overwrite="false" filter="true"> <file name="vivado/&lt;?=shortname?&gt;.xpr" overwrite="false" filter="true" lookAt="BASYS3.config" ref="vivado"/>
<content><![CDATA[<?print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");?>
<Project Version="7" Minor="20" Path="<?=dir?>/vivado/<?=shortname?>.xpr">
<DefaultLaunch Dir="$PRUNDIR"/>
<Configuration>
<Option Name="Part" Val="xc7a35ticpg236-1L"/>
</Configuration>
<FileSets Version="1" Minor="31">
<FileSet Name="sources_1" Type="DesignSrcs" RelSrcDir="$PSRCDIR/sources_1">
<Filter Type="Srcs"/>
<File Path="$PPRDIR/../<?=shortname?>.v">
<FileInfo>
<Attr Name="UsedIn" Val="synthesis"/>
<Attr Name="UsedIn" Val="simulation"/>
</FileInfo>
</File>
<File Path="$PPRDIR/../clockGenerator.v">
<FileInfo>
<Attr Name="UsedIn" Val="synthesis"/>
<Attr Name="UsedIn" Val="simulation"/>
</FileInfo>
</File>
<Config>
<Option Name="DesignMode" Val="RTL"/>
<Option Name="TopModule" Val="main"/>
<Option Name="TopAutoSet" Val="TRUE"/>
</Config>
</FileSet>
<FileSet Name="constrs_1" Type="Constrs" RelSrcDir="$PSRCDIR/constrs_1">
<Filter Type="Constrs"/>
<Config>
<Option Name="ConstrsType" Val="XDC"/>
</Config>
</FileSet>
</FileSets>
</Project>]]></content>
</file>
</files> </files>
</toolchain> </toolchain>

View File

@ -24,6 +24,7 @@ import de.neemann.digital.hdl.verilog2.VerilogGenerator;
import de.neemann.digital.hdl.vhdl2.VHDLGenerator; import de.neemann.digital.hdl.vhdl2.VHDLGenerator;
import de.neemann.digital.lang.Lang; import de.neemann.digital.lang.Lang;
import de.neemann.gui.ErrorMessage; import de.neemann.gui.ErrorMessage;
import de.neemann.gui.language.Resources;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -32,6 +33,7 @@ import java.awt.event.ActionEvent;
import java.io.*; import java.io.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Used to create the IDE integration * Used to create the IDE integration
@ -76,6 +78,8 @@ public final class Configuration {
xStream.aliasAttribute(Configuration.class, "name", "name"); xStream.aliasAttribute(Configuration.class, "name", "name");
xStream.aliasAttribute(Configuration.class, "frequency", "frequency"); xStream.aliasAttribute(Configuration.class, "frequency", "frequency");
xStream.aliasAttribute(Configuration.class, "clockGenerator", "clockGenerator"); xStream.aliasAttribute(Configuration.class, "clockGenerator", "clockGenerator");
xStream.aliasAttribute(Configuration.class, "params", "params");
xStream.registerConverter(new Resources.MapEntryConverter("param"));
xStream.alias("command", Command.class); xStream.alias("command", Command.class);
xStream.aliasAttribute(Command.class, "name", "name"); xStream.aliasAttribute(Command.class, "name", "name");
xStream.aliasAttribute(Command.class, "requires", "requires"); xStream.aliasAttribute(Command.class, "requires", "requires");
@ -97,6 +101,7 @@ public final class Configuration {
private String clockGenerator; private String clockGenerator;
private ArrayList<Command> commands; private ArrayList<Command> commands;
private ArrayList<FileToCreate> files; private ArrayList<FileToCreate> files;
private Map<String, String> params;
private transient FilenameProvider filenameProvider; private transient FilenameProvider filenameProvider;
private transient CircuitProvider circuitProvider; private transient CircuitProvider circuitProvider;
private transient LibraryProvider libraryProvider; private transient LibraryProvider libraryProvider;
@ -173,17 +178,40 @@ public final class Configuration {
} }
} }
private Context createContext(File fileToExecute, HDLModel hdlModel) throws HGSEvalException { private Context createContext(File fileToExecute, HDLModel hdlModel, Command command) throws HGSEvalException {
final Context context = new Context() final Context context = new Context()
.declareVar("path", fileToExecute.getPath()) .declareVar("path", fileToExecute.getPath())
.declareVar("dir", fileToExecute.getParentFile()) .declareVar("dir", fileToExecute.getParentFile())
.declareVar("name", fileToExecute.getName()) .declareVar("name", fileToExecute.getName())
.declareVar("shortname", createShortname(fileToExecute.getName())); .declareVar("shortname", createShortname(fileToExecute.getName()));
if (params != null)
for (Map.Entry<String, String> e : params.entrySet())
context.declareVar(e.getKey(), toHGLValue(e.getValue()));
if (command.needsHDL())
context.declareVar("hdl", command.getHDL());
if (clockGenerator != null)
context.declareVar("clockGenerator", clockGenerator);
if (hdlModel != null) if (hdlModel != null)
context.declareVar("hdl", new ModelAccess(hdlModel.getMain())); context.declareVar("model", new ModelAccess(hdlModel.getMain()));
return context; return context;
} }
private Object toHGLValue(String value) {
try {
return Long.parseLong(value);
} catch (NumberFormatException e1) {
try {
return Double.parseDouble(value);
} catch (NumberFormatException e2) {
return value;
}
}
}
private IOInterface getIoInterface() { private IOInterface getIoInterface() {
if (ioInterface == null) if (ioInterface == null)
ioInterface = new DefaultIOInterface(); ioInterface = new DefaultIOInterface();
@ -246,13 +274,13 @@ public final class Configuration {
action.setEnabled(false); action.setEnabled(false);
Thread t = new Thread(() -> { Thread t = new Thread(() -> {
try { try {
checkFilesToCreate(digFile, hdlModel); checkFilesToCreate(digFile, hdlModel, command);
String[] args = command.getArgs(); String[] args = command.getArgs();
if (args != null) { if (args != null) {
if (command.isFilter()) { if (command.isFilter()) {
final int argCount = command.getArgs().length; final int argCount = command.getArgs().length;
Context context = createContext(digFile, hdlModel); Context context = createContext(digFile, hdlModel, command);
for (int i = 0; i < argCount; i++) { for (int i = 0; i < argCount; i++) {
context.clearOutput(); context.clearOutput();
new Parser(args[i]).parse().execute(context); new Parser(args[i]).parse().execute(context);
@ -278,14 +306,17 @@ public final class Configuration {
return null; return null;
} }
private void checkFilesToCreate(File fileToExecute, HDLModel hdlModel) throws HGSEvalException, IOException, ParserException { private void checkFilesToCreate(File fileToExecute, HDLModel hdlModel, Command command) throws HGSEvalException, IOException, ParserException {
Context context = createContext(fileToExecute, hdlModel); Context context = createContext(fileToExecute, hdlModel, command);
if (files != null) { if (files != null) {
ConfigCache configCache = new ConfigCache(origin); ConfigCache configCache = new ConfigCache(origin);
for (FileToCreate f : files) { for (FileToCreate f : files) {
context.clearOutput(); context.clearOutput();
Parser p = new Parser(f.getName()); final String name = f.getName();
if (name == null)
throw new IOException("no file name given!");
Parser p = new Parser(name);
p.parse().execute(context); p.parse().execute(context);
File filename = new File(fileToExecute.getParent(), context.toString()); File filename = new File(fileToExecute.getParent(), context.toString());

View File

@ -22,7 +22,7 @@ public class Bundle {
private static XStream getxStream() { private static XStream getxStream() {
XStream xStream = new XStream(new StaxDriver()); XStream xStream = new XStream(new StaxDriver());
xStream.alias("languages", Map.class); xStream.alias("languages", Map.class);
xStream.registerConverter(new Resources.MapEntryConverter()); xStream.registerConverter(new Resources.MapEntryConverter("string"));
return xStream; return xStream;
} }

View File

@ -19,13 +19,14 @@ import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
/** /**
* Used to store the language keys.
*/ */
public class Resources { public class Resources {
private static XStream getxStream() { private static XStream getxStream() {
XStream xStream = new XStream(new StaxDriver()); XStream xStream = new XStream(new StaxDriver());
xStream.alias("resources", Map.class); xStream.alias("resources", Map.class);
xStream.registerConverter(new MapEntryConverter()); xStream.registerConverter(new MapEntryConverter("string"));
return xStream; return xStream;
} }
@ -92,23 +93,57 @@ public class Resources {
return resourceMap.keySet(); return resourceMap.keySet();
} }
static class MapEntryConverter implements Converter { /**
* Simplified map converter
*/
public static class MapEntryConverter implements Converter {
private String keyName;
/**
* Creates a new Instance
*
* @param keyName the name of the xml entity
*/
public MapEntryConverter(String keyName) {
this.keyName = keyName;
}
/**
* Returns true if the given class can be converted by this converter.
*
* @param clazz the class to test.
* @return true if the given class can be converted by this converter.
*/
public boolean canConvert(Class clazz) { public boolean canConvert(Class clazz) {
return Map.class.isAssignableFrom(clazz); return Map.class.isAssignableFrom(clazz);
} }
/**
* Marshals the given object
*
* @param value the value to matshal
* @param writer the writer to write the xml to
* @param context the context of the marshaler
*/
public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) { public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {
Map map = (Map) value; Map map = (Map) value;
for (Object obj : map.entrySet()) { for (Object obj : map.entrySet()) {
Map.Entry entry = (Map.Entry) obj; Map.Entry entry = (Map.Entry) obj;
writer.startNode("string"); writer.startNode(keyName);
writer.addAttribute("name", entry.getKey().toString()); writer.addAttribute("name", entry.getKey().toString());
writer.setValue(entry.getValue().toString()); writer.setValue(entry.getValue().toString());
writer.endNode(); writer.endNode();
} }
} }
/**
* Unmarshals a object
*
* @param reader the reader to read the xml from
* @param context the context of the unmarshaler
* @return the read object
*/
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
Map<String, String> map = new TreeMap<>(); Map<String, String> map = new TreeMap<>();
while (reader.hasMoreChildren()) { while (reader.hasMoreChildren()) {

View File

@ -26,7 +26,7 @@ public class BASYS3Test extends TestCase {
String content = clock.getContent(); String content = clock.getContent();
for (int f = 4688; f < 500000; f+=77) { for (int f = 4688; f < 500000; f+=77) {
Context context = new Context().disableLogging(); Context context = new Context().disableLogging();
context.declareVar("hdl", context.declareVar("model",
new ElementAttributes() new ElementAttributes()
.set(new Key<>("frequency", 10), f * 1000)); .set(new Key<>("frequency", 10), f * 1000));
Parser p = new Parser(content); Parser p = new Parser(content);

View File

@ -76,7 +76,7 @@ public class ConfigurationTest extends TestCase {
" <content>deal with &lt;?=path?&gt;</content>\n" + " <content>deal with &lt;?=path?&gt;</content>\n" +
" </file>\n" + " </file>\n" +
" <file name=\"file2\" overwrite=\"true\" filter=\"true\">\n" + " <file name=\"file2\" overwrite=\"true\" filter=\"true\">\n" +
" <content>deal with &lt;?=path?&gt;, Bits: &lt;?=hdl.ports[0].bits?&gt; (&lt;?=hdl.ports[0].name?&gt;)</content>\n" + " <content>deal with &lt;?=path?&gt;, Bits: &lt;?=model.ports[0].bits?&gt; (&lt;?=model.ports[0].name?&gt;)</content>\n" +
" </file>\n" + " </file>\n" +
" <file name=\"&lt;?=shortname?&gt;.z\" overwrite=\"true\" filter=\"false\">\n" + " <file name=\"&lt;?=shortname?&gt;.z\" overwrite=\"true\" filter=\"false\">\n" +
" <content>test</content>\n" + " <content>test</content>\n" +