adds a external file based component, see #713

This commit is contained in:
hneemann 2021-04-19 08:54:19 +02:00
parent 074ea08fe2
commit 96ca9783ab
22 changed files with 626 additions and 12 deletions

View File

@ -5,6 +5,7 @@
*/
package de.neemann.digital.core.element;
import de.neemann.digital.FileLocator;
import de.neemann.digital.core.ValueFormatter;
import de.neemann.digital.hdl.hgs.HGSMap;
@ -23,6 +24,7 @@ public class ElementAttributes implements HGSMap {
private HashMap<String, Object> attributes;
private transient ArrayList<AttributeListener> listeners;
private transient HashMap<String, Object> cache;
private transient File origin;
/**
* Creates a new instance
@ -206,6 +208,19 @@ public class ElementAttributes implements HGSMap {
return attributes.isEmpty();
}
/**
* Gets a file stored in the map
*
* @param key the file key
* @return the file
*/
public File getFile(Key<File> key) {
File f = get(key);
if (origin != null)
f = new FileLocator(f).setBaseFile(origin).locate();
return f;
}
/**
* Gets a file stored directly in the map
*
@ -215,8 +230,12 @@ public class ElementAttributes implements HGSMap {
public File getFile(String fileKey) {
if (attributes != null) {
Object f = attributes.get(fileKey);
if (f != null)
return new File(f.toString().trim());
if (f != null) {
File file = new File(f.toString().trim());
if (origin != null)
file = new FileLocator(file).setBaseFile(origin).locate();
return file;
}
}
return null;
}
@ -347,4 +366,20 @@ public class ElementAttributes implements HGSMap {
return null;
return cache.remove(key);
}
/**
* Sets the origin of this data
*
* @param filename the file this data comes from
*/
public void setOrigin(File filename) {
this.origin = filename;
}
/**
* @return the file this data comes from
*/
public File getOrigin() {
return origin;
}
}

View File

@ -727,6 +727,11 @@ public final class Keys {
*/
public static final Key.LongString EXTERNAL_CODE
= new Key.LongString("Code").setRows(30).setColumns(80).setLineNumbers(true);
/**
* The code to be executed by the external process
*/
public static final Key.KeyFile EXTERNAL_CODE_FILE
= new Key.KeyFile("CodeFile", new File(""));
/**
* Path to ghdl

View File

@ -6,15 +6,49 @@
package de.neemann.digital.core.extern;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.Keys;
import de.neemann.digital.core.extern.handler.ProcessInterface;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
/**
* Represents an application
*/
public interface Application {
/**
* Extract the code from the attributes.
* The code is either stored directly or there is a file given.
*
* @param attr the attributes
* @return the code
* @throws IOException IOException
*/
static String getCode(ElementAttributes attr) throws IOException {
if (attr.contains(Keys.EXTERNAL_CODE))
return attr.get(Keys.EXTERNAL_CODE);
if (attr.contains(Keys.EXTERNAL_CODE_FILE))
return readCode(attr.getFile(Keys.EXTERNAL_CODE_FILE));
return "";
}
/**
* Reads the code from a file
*
* @param file the file
* @return the code
* @throws IOException IOException
*/
static String readCode(File file) throws IOException {
byte[] data = Files.readAllBytes(file.toPath());
return new String(data, StandardCharsets.UTF_8);
}
/**
* The available types of applications
*/

View File

@ -74,9 +74,9 @@ public abstract class ApplicationVHDLStdIO implements Application {
@Override
public boolean ensureConsistency(ElementAttributes attributes) {
String code = attributes.get(Keys.EXTERNAL_CODE);
VHDLTokenizer st = new VHDLTokenizer(new StringReader(code));
try {
String code = Application.getCode(attributes);
VHDLTokenizer st = new VHDLTokenizer(new StringReader(code));
while (!st.value().equalsIgnoreCase("entity"))
st.next();

View File

@ -82,10 +82,10 @@ public abstract class ApplicationVerilogStdIO implements Application {
@Override
public boolean ensureConsistency(ElementAttributes attributes) {
String code = attributes.get(Keys.EXTERNAL_CODE);
VerilogTokenizer st = new VerilogTokenizer(new StringReader(code));
try {
String code = Application.getCode(attributes);
VerilogTokenizer st = new VerilogTokenizer(new StringReader(code));
PortDefinition in;
PortDefinition out;
String label;

View File

@ -49,8 +49,8 @@ public class External extends Node implements Element {
private final PortDefinition outs;
private final ElementAttributes attr;
private final ObservableValues outputs;
private final String code;
private final String label;
private String code;
private ObservableValues inputs;
private ProcessInterface processInterface;
@ -103,6 +103,9 @@ public class External extends Node implements Element {
@Override
public void init(Model model) throws NodeException {
if (label.isEmpty())
throw new NodeException(Lang.get("err_emptyLabelIsNotAllowed"));
try {
Application app = Application.create(type, attr);
if (app == null)
@ -123,4 +126,13 @@ public class External extends Node implements Element {
}
}, ModelEventType.CLOSED);
}
/**
* Sets the code to use.
*
* @param code the code
*/
public void setCode(String code) {
this.code = code;
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2018 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.core.extern;
import de.neemann.digital.core.Model;
import de.neemann.digital.core.NodeException;
import de.neemann.digital.core.element.*;
import de.neemann.digital.lang.Lang;
import java.io.File;
import java.io.IOException;
/**
* The external component
*/
public class ExternalFile extends External {
/**
* The external component description
*/
public static final ElementTypeDescription DESCRIPTION = new ElementTypeDescription(ExternalFile.class) {
@Override
public PinDescriptions getInputDescription(ElementAttributes elementAttributes) {
return new PortDefinition(elementAttributes.get(Keys.EXTERNAL_INPUTS)).getPinDescriptions(PinDescription.Direction.input);
}
@Override
public PinDescriptions getOutputDescriptions(ElementAttributes elementAttributes) {
return new PortDefinition(elementAttributes.get(Keys.EXTERNAL_OUTPUTS)).getPinDescriptions(PinDescription.Direction.output);
}
}
.addAttribute(Keys.LABEL)
.addAttribute(Keys.WIDTH)
.addAttribute(Keys.EXTERNAL_INPUTS)
.addAttribute(Keys.EXTERNAL_OUTPUTS)
.addAttribute(Keys.EXTERNAL_CODE_FILE)
.addAttribute(Keys.APPLICATION_TYPE)
.addAttribute(Keys.GHDL_OPTIONS)
.addAttribute(Keys.IVERILOG_OPTIONS)
.supportsHDL();
private final File file;
/**
* Creates a new instance
*
* @param attr the elements attributes
*/
public ExternalFile(ElementAttributes attr) {
super(attr);
file = attr.getFile(Keys.EXTERNAL_CODE_FILE);
}
@Override
public void init(Model model) throws NodeException {
try {
setCode(Application.readCode(file));
} catch (IOException e) {
throw new NodeException(Lang.get("err_errorLoadingHDLFile_N", file));
}
super.init(model);
}
}

View File

@ -118,6 +118,8 @@ public class Circuit implements Copyable<Circuit> {
public static Circuit loadCircuit(File filename, ShapeFactory shapeFactory) throws IOException {
final Circuit circuit = loadCircuit(new FileInputStream(filename), shapeFactory);
circuit.origin = filename;
for (VisualElement ve : circuit.visualElements)
ve.setOrigin(filename);
return circuit;
}
@ -162,6 +164,8 @@ public class Circuit implements Copyable<Circuit> {
*/
public void save(File filename) throws IOException {
save(new FileOutputStream(filename));
for (VisualElement ve : visualElements)
ve.setOrigin(filename);
}
/**

View File

@ -16,6 +16,7 @@ import de.neemann.gui.Screen;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import static de.neemann.digital.draw.shapes.GenericShape.SIZE;
import static de.neemann.digital.draw.shapes.GenericShape.SIZE2;
@ -491,4 +492,12 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
return null;
}
/**
* Sets the file this data comes from
*
* @param filename the origin of this data
*/
public void setOrigin(File filename) {
elementAttributes.setOrigin(filename);
}
}

View File

@ -12,6 +12,7 @@ import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.ElementTypeDescription;
import de.neemann.digital.core.element.Keys;
import de.neemann.digital.core.extern.External;
import de.neemann.digital.core.extern.ExternalFile;
import de.neemann.digital.core.flipflops.*;
import de.neemann.digital.core.io.*;
import de.neemann.digital.core.memory.*;
@ -236,6 +237,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
.add(Stop.DESCRIPTION)
.add(AsyncSeq.DESCRIPTION)
.add(External.DESCRIPTION)
.add(ExternalFile.DESCRIPTION)
.add(PinControl.DESCRIPTION));
addExternalJarComponents(jarFile);

View File

@ -821,9 +821,9 @@ public final class EditorFactory {
PortDefinition ins = new PortDefinition(elementAttributes.get(Keys.EXTERNAL_INPUTS));
PortDefinition outs = new PortDefinition(elementAttributes.get(Keys.EXTERNAL_OUTPUTS));
String label = elementAttributes.getLabel();
String code = elementAttributes.get(Keys.EXTERNAL_CODE);
try {
String code = Application.getCode(elementAttributes);
String message = app.checkCode(label, code, ins, outs);
if (message != null && !message.isEmpty()) {
createError(consistent, Lang.get("msg_checkResult") + "\n\n" + message).show(getAttributeDialog());

View File

@ -7,6 +7,8 @@ package de.neemann.digital.hdl.hgs;
import de.neemann.digital.FileLocator;
import de.neemann.digital.core.Bits;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.extern.Application;
import de.neemann.digital.core.memory.DataField;
import de.neemann.digital.core.memory.importer.Importer;
import de.neemann.digital.hdl.hgs.function.Func;
@ -55,6 +57,7 @@ public class Context implements HGSMap {
BUILT_IN.put("splitString", new FunctionSplitString());
BUILT_IN.put("identifier", new FunctionIdentifier());
BUILT_IN.put("loadHex", new FunctionLoadHex());
BUILT_IN.put("loadFile", new FunctionLoadFile());
BUILT_IN.put("sizeOf", new Func(1, args -> Value.toArray(args[0]).hgsArraySize()));
}
@ -677,6 +680,25 @@ public class Context implements HGSMap {
}
}
private static final class FunctionLoadFile extends InnerFunction {
private FunctionLoadFile() {
super(1);
}
@Override
public Object call(Context c, ArrayList<Expression> args) throws HGSEvalException {
File f = new File(args.get(0).value(c).toString());
File origin = ((ElementAttributes) c.map.get("elem")).getOrigin();
if (origin != null)
f = new FileLocator(f).setBaseFile(origin).locate();
try {
return Application.readCode(f);
} catch (IOException e) {
throw new HGSEvalException("error reading the file " + f.getPath(), e);
}
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View File

@ -1009,6 +1009,14 @@
Wird verwendet, um das Verhalten eines Elements mit einer Hardwarebeschreibungssprache wie VHDL oder
Verilog zu beschreiben. Die eigentliche Simulation des Verhaltens muss mit einem externen Simulator erfolgen.
Zur Zeit wird nur der VHDL-Simulator ghdl und der Verilog-Simulator Icarus Verilog unterstützt.
Das Label der Komponente muss mit dem Namen der Entity bzw. des Moduls übereinstimmen!
</string>
<string name="elem_ExternalFile">Extern Datei</string>
<string name="elem_ExternalFile_tt">Element zur Anbindung von externen Programmen zur Berechnung der Logik.
Wird verwendet, um das Verhalten eines Elements mit einer Hardwarebeschreibungssprache wie VHDL oder
Verilog zu beschreiben. Die eigentliche Simulation des Verhaltens muss mit einem externen Simulator erfolgen.
Zur Zeit wird nur der VHDL-Simulator ghdl und der Verilog-Simulator Icarus Verilog unterstützt.
Das Label der Komponente muss mit dem Namen der Entity bzw. des Moduls übereinstimmen!
</string>
<string name="elem_Diode">Diode</string>
@ -1183,6 +1191,9 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
<string name="err_iverilogNotInstalled">
Der Verilog Simulator Icarus scheint nicht installiert zu sein. Installieren Sie Icarus (http://iverilog.icarus.com/) und versuchen Sie es erneut. Sollte es immer noch Probleme geben, überprüfen Sie den Pfad zur ausfühbaren iverilog-Datei in den Digital-Einstellungen.
</string>
<string name="err_errorLoadingHDLFile_N">Fehler beim Laden der HDL-Datei {0}</string>
<string name="err_emptyLabelIsNotAllowed">Eine leere Bezeichnung is nicht erlaubt!</string>
<string name="err_errorAnalysingCircuit_N">Fehler bei der Analyse der Schaltung: {0}</string>
<string name="err_romNeedsALabelToBeExported">Jedes ROM braucht eine eindeutige Bezeichnung um exportiert zu werden!</string>
<string name="err_lutNeedsALabelToBeExported">Jede LUT braucht eine eindeutige Bezeichnung um exportiert zu werden!</string>
@ -1486,6 +1497,8 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
</string>
<string name="key_Code">Programmcode</string>
<string name="key_Code_tt">Der Programmcode welcher ausgeführt werden soll.</string>
<string name="key_CodeFile">Programmcode</string>
<string name="key_CodeFile_tt">Datei mit dem Programmcode welcher ausgeführt werden soll.</string>
<string name="attr_panel_Options">Optionen</string>
<string name="key_ghdlPath">GHDL</string>
<string name="key_ghdlPath_tt">Pfad der ausführbaren ghdl-Datei. Nur wichtig, wenn ghdl zur Interpretation von

View File

@ -984,6 +984,14 @@
Is used to specify the behaviour of a component by VHDL or Verilog.
The actual simulation of the behavior must be done with an external simulator.
At present only the VHDL simulator ghdl and the verilog simulator Icarus Verilog are supported.
The label of the component must match the name of the entity or module!
</string>
<string name="elem_ExternalFile">External File</string>
<string name="elem_ExternalFile_tt">Component to execute an external process to calculate the logic function.
Is used to specify the behaviour of a component by VHDL or Verilog.
The actual simulation of the behavior must be done with an external simulator.
At present only the VHDL simulator ghdl and the verilog simulator Icarus Verilog are supported.
The label of the component must match the name of the entity or module!
</string>
<string name="elem_Diode">Diode</string>
@ -1171,6 +1179,9 @@
try again.
If there are still problems, check the path to the IVerilog executable in the Digital settings.
</string>
<string name="err_errorLoadingHDLFile_N">Error loading the HDL file {0}</string>
<string name="err_emptyLabelIsNotAllowed">A empty label is not allowed!</string>
<string name="err_errorAnalysingCircuit_N">Error analysing the circuit: {0}</string>
<string name="err_romNeedsALabelToBeExported">Every ROM needs a unique label to be exported!</string>
<string name="err_lutNeedsALabelToBeExported">Every LUT needs a unique label to be exported!</string>
@ -1477,6 +1488,8 @@
</string>
<string name="key_Code">Program code</string>
<string name="key_Code_tt">The program code to be executed by the external application.</string>
<string name="key_CodeFile">Program code</string>
<string name="key_CodeFile_tt">The file containing the program code to be executed by the external application.</string>
<string name="attr_panel_Options">Options</string>
<string name="key_ghdlPath">GHDL</string>
<string name="key_ghdlPath_tt">Path to the executable ghdl file. Only necessary if you want to use ghdl to simulate

View File

@ -0,0 +1,8 @@
<?=loadFile(elem.CodeFile);
moduleName=elem.Label;
if (elem.applicationType!="IVERILOG")
panic("err_canOnlyExportExternalVerilog");
?>

View File

@ -0,0 +1,8 @@
<?=loadFile(elem.CodeFile);
entityName:=elem.Label;
if (elem.applicationType!="GHDL")
panic("err_canOnlyExportExternalVHDL");
?>

View File

@ -129,7 +129,7 @@ public class VerilogSimulatorTest extends TestCase {
// check simulation in Digital
new TestExamples().check(f);
}).scan(source);
assertEquals(4, tested);
assertEquals(5, tested);
}
}

View File

@ -123,7 +123,7 @@ public class VHDLSimulatorTest extends TestCase {
// check simulation in Digital
new TestExamples().check(f);
}).noOutput().scan(source);
assertEquals(4, tested);
assertEquals(5, tested);
}

View File

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="utf-8"?>
<circuit>
<version>1</version>
<attributes/>
<visualElements>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>A</string>
</entry>
<entry>
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>InDefault</string>
<value v="3" z="false"/>
</entry>
</elementAttributes>
<pos x="240" y="100"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>B</string>
</entry>
<entry>
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>InDefault</string>
<value v="4" z="false"/>
</entry>
</elementAttributes>
<pos x="240" y="160"/>
</visualElement>
<visualElement>
<elementName>Out</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>S</string>
</entry>
<entry>
<string>Bits</string>
<int>4</int>
</entry>
</elementAttributes>
<pos x="380" y="140"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>C_i</string>
</entry>
<entry>
<string>InDefault</string>
<value v="4" z="false"/>
</entry>
</elementAttributes>
<pos x="240" y="200"/>
</visualElement>
<visualElement>
<elementName>Out</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>C_o</string>
</entry>
</elementAttributes>
<pos x="380" y="180"/>
</visualElement>
<visualElement>
<elementName>Testcase</elementName>
<elementAttributes>
<entry>
<string>Testdata</string>
<testData>
<dataString>A B C_i C_o S
loop(a,16)
loop(b,16)
let sum=a+b;
(a) (b) 0 (sum&gt;&gt;4) (sum)
(a) (b) 1 ((sum+1)&gt;&gt;4) (sum+1)
end loop
end loop
</dataString>
</testData>
</entry>
</elementAttributes>
<pos x="300" y="40"/>
</visualElement>
<visualElement>
<elementName>ExternalFile</elementName>
<elementAttributes>
<entry>
<string>applicationType</string>
<appType>GHDL</appType>
</entry>
<entry>
<string>Label</string>
<string>add</string>
</entry>
<entry>
<string>externalInputs</string>
<string>a:4,b:4,c_i</string>
</entry>
<entry>
<string>externalOutputs</string>
<string>s:4,c_o</string>
</entry>
<entry>
<string>CodeFile</string>
<file>/home/hneemann/Dokumente/Java/digital/src/test/resources/dig/external/ghdl/ghdlFile.vhdl</file>
</entry>
</elementAttributes>
<pos x="280" y="140"/>
</visualElement>
</visualElements>
<wires>
<wire>
<p1 x="240" y="160"/>
<p2 x="280" y="160"/>
</wire>
<wire>
<p1 x="340" y="160"/>
<p2 x="360" y="160"/>
</wire>
<wire>
<p1 x="260" y="180"/>
<p2 x="280" y="180"/>
</wire>
<wire>
<p1 x="360" y="180"/>
<p2 x="380" y="180"/>
</wire>
<wire>
<p1 x="240" y="100"/>
<p2 x="260" y="100"/>
</wire>
<wire>
<p1 x="240" y="200"/>
<p2 x="260" y="200"/>
</wire>
<wire>
<p1 x="340" y="140"/>
<p2 x="380" y="140"/>
</wire>
<wire>
<p1 x="260" y="140"/>
<p2 x="280" y="140"/>
</wire>
<wire>
<p1 x="260" y="100"/>
<p2 x="260" y="140"/>
</wire>
<wire>
<p1 x="260" y="180"/>
<p2 x="260" y="200"/>
</wire>
<wire>
<p1 x="360" y="160"/>
<p2 x="360" y="180"/>
</wire>
</wires>
<measurementOrdering/>
</circuit>

View File

@ -0,0 +1,21 @@
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
entity add is
port (
a: in std_logic_vector(3 downto 0);
b: in std_logic_vector(3 downto 0);
c_i: in std_logic;
s: out std_logic_vector(3 downto 0);
c_o: out std_logic );
end add;
architecture add_arch of add is
signal temp : std_logic_vector(4 downto 0);
begin
temp <= ('0' & a) + b + c_i;
s <= temp(3 downto 0);
c_o <= temp(4);
end add_arch;

View File

@ -0,0 +1,173 @@
<?xml version="1.0" encoding="utf-8"?>
<circuit>
<version>1</version>
<attributes/>
<visualElements>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>A</string>
</entry>
<entry>
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>InDefault</string>
<value v="3" z="false"/>
</entry>
</elementAttributes>
<pos x="240" y="100"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>B</string>
</entry>
<entry>
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>InDefault</string>
<value v="4" z="false"/>
</entry>
</elementAttributes>
<pos x="240" y="160"/>
</visualElement>
<visualElement>
<elementName>Out</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>S</string>
</entry>
<entry>
<string>Bits</string>
<int>4</int>
</entry>
</elementAttributes>
<pos x="380" y="140"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>C_i</string>
</entry>
<entry>
<string>InDefault</string>
<value v="4" z="false"/>
</entry>
</elementAttributes>
<pos x="240" y="200"/>
</visualElement>
<visualElement>
<elementName>Out</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>C_o</string>
</entry>
</elementAttributes>
<pos x="380" y="180"/>
</visualElement>
<visualElement>
<elementName>Testcase</elementName>
<elementAttributes>
<entry>
<string>Testdata</string>
<testData>
<dataString>A B C_i C_o S
loop(a,16)
loop(b,16)
(a) (b) 0 ((a+b)&gt;&gt;4) (a+b)
end loop
end loop
</dataString>
</testData>
</entry>
</elementAttributes>
<pos x="300" y="40"/>
</visualElement>
<visualElement>
<elementName>ExternalFile</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>add</string>
</entry>
<entry>
<string>applicationType</string>
<appType>IVERILOG</appType>
</entry>
<entry>
<string>externalInputs</string>
<string>a:4,b:4,c_i</string>
</entry>
<entry>
<string>externalOutputs</string>
<string>s:4,c_o</string>
</entry>
<entry>
<string>CodeFile</string>
<file>/home/hneemann/Dokumente/Java/digital/src/test/resources/dig/external/verilog/verilogFile.v</file>
</entry>
</elementAttributes>
<pos x="280" y="140"/>
</visualElement>
</visualElements>
<wires>
<wire>
<p1 x="240" y="160"/>
<p2 x="280" y="160"/>
</wire>
<wire>
<p1 x="340" y="160"/>
<p2 x="360" y="160"/>
</wire>
<wire>
<p1 x="260" y="180"/>
<p2 x="280" y="180"/>
</wire>
<wire>
<p1 x="360" y="180"/>
<p2 x="380" y="180"/>
</wire>
<wire>
<p1 x="240" y="100"/>
<p2 x="260" y="100"/>
</wire>
<wire>
<p1 x="240" y="200"/>
<p2 x="260" y="200"/>
</wire>
<wire>
<p1 x="340" y="140"/>
<p2 x="380" y="140"/>
</wire>
<wire>
<p1 x="260" y="140"/>
<p2 x="280" y="140"/>
</wire>
<wire>
<p1 x="260" y="100"/>
<p2 x="260" y="140"/>
</wire>
<wire>
<p1 x="260" y="180"/>
<p2 x="260" y="200"/>
</wire>
<wire>
<p1 x="360" y="160"/>
<p2 x="360" y="180"/>
</wire>
</wires>
<measurementOrdering/>
</circuit>

View File

@ -0,0 +1,14 @@
module add
(
input [3:0] a,
input [3:0] b,
input c_i,
output [3:0] s,
output c_o
);
wire [4:0] temp;
assign temp = a + b + c_i;
assign s = temp [3:0];
assign c_o = temp[4];
endmodule