added a register file component, fixes #104

This commit is contained in:
hneemann 2018-01-13 13:22:22 +01:00
parent 0c550d4a32
commit 41b487a60e
14 changed files with 711 additions and 13 deletions

View File

@ -3,6 +3,7 @@ Release Notes
HEAD, planned as v0.17
- Added 64 bit support for Add and Sub components.
- Added support of some more ATF150x chips.
- Added a register file component.
- Bug fixes
- Splitter, BarrelShifter and Comparator now are working with 64 bit.

View File

@ -14,11 +14,6 @@ Single-Cycle CPU.</string>
</entry>
</attributes>
<visualElements>
<visualElement>
<elementName>Register.dig</elementName>
<elementAttributes/>
<pos x="660" y="120"/>
</visualElement>
<visualElement>
<elementName>Multiplexer</elementName>
<elementAttributes>
@ -53,7 +48,7 @@ Single-Cycle CPU.</string>
<elementAttributes>
<entry>
<string>Value</string>
<int>0</int>
<long>0</long>
</entry>
<entry>
<string>Bits</string>
@ -67,7 +62,7 @@ Single-Cycle CPU.</string>
<elementAttributes>
<entry>
<string>Value</string>
<int>255</int>
<long>255</long>
</entry>
<entry>
<string>Bits</string>
@ -81,7 +76,7 @@ Single-Cycle CPU.</string>
<elementAttributes>
<entry>
<string>Value</string>
<int>4095</int>
<long>4095</long>
</entry>
<entry>
<string>Bits</string>
@ -848,6 +843,11 @@ Single-Cycle CPU.</string>
<elementAttributes/>
<pos x="1060" y="140"/>
</visualElement>
<visualElement>
<elementName>RegisterOpt.dig</elementName>
<elementAttributes/>
<pos x="660" y="120"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -0,0 +1,213 @@
<?xml version="1.0" encoding="utf-8"?>
<circuit>
<version>1</version>
<attributes>
<entry>
<string>Description</string>
<string>In diesem Block befinden sich die 16
Prozessorregister.</string>
</entry>
<entry>
<string>Width</string>
<int>5</int>
</entry>
</attributes>
<visualElements>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Description</string>
<string>Daten die gespeichert werden sollen.
Der hier anliegende Wert wird gespeichert, wenn
der Eingang WE auf 1 geschaltet wird.</string>
</entry>
<entry>
<string>Label</string>
<string>WD</string>
</entry>
<entry>
<string>Bits</string>
<int>16</int>
</entry>
</elementAttributes>
<pos x="100" y="140"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Description</string>
<string>Takt. Geht der Takt auf High, und ist WE auf High
wird der Wert an WD im dem Register gespeichert,
welches in dest angegeben ist.</string>
</entry>
<entry>
<string>Label</string>
<string>C</string>
</entry>
</elementAttributes>
<pos x="200" y="200"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Description</string>
<string>Nummer des Source Registers. Legt fest, welches
Register an Rsrc ausgegeben werden soll.</string>
</entry>
<entry>
<string>Label</string>
<string>src</string>
</entry>
<entry>
<string>Bits</string>
<int>4</int>
</entry>
</elementAttributes>
<pos x="200" y="240"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Description</string>
<string>Nummer des Destignation Registers. Legt fest,
welches Register an Rdest ausgegeben werden soll.
Zudem wird dieses Register beschrieben, wenn
WE auf 1 gesetzt wird.</string>
</entry>
<entry>
<string>Label</string>
<string>dest</string>
</entry>
<entry>
<string>Bits</string>
<int>4</int>
</entry>
</elementAttributes>
<pos x="100" y="220"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Description</string>
<string>Das Speichern aktivieren. Wenn dieser Eingang auf
High geht, wird der Wert an WD in dem Register
gespeichert, welches in dest angegeben ist.</string>
</entry>
<entry>
<string>Label</string>
<string>WE</string>
</entry>
</elementAttributes>
<pos x="200" y="160"/>
</visualElement>
<visualElement>
<elementName>Out</elementName>
<elementAttributes>
<entry>
<string>Description</string>
<string>Inhalt des Destignation Registers.
Welches Register ausgegeben wird, wird mittels
des Eingangs dest festgelegt.</string>
</entry>
<entry>
<string>Label</string>
<string>Rdest</string>
</entry>
<entry>
<string>Bits</string>
<int>16</int>
</entry>
</elementAttributes>
<pos x="360" y="140"/>
</visualElement>
<visualElement>
<elementName>Out</elementName>
<elementAttributes>
<entry>
<string>Description</string>
<string>Inhalt des Source Registers. Welches Register
ausgegeben wird, wird mittels des Einganges src
festgelegt.</string>
</entry>
<entry>
<string>Label</string>
<string>Rsrc</string>
</entry>
<entry>
<string>Bits</string>
<int>16</int>
</entry>
</elementAttributes>
<pos x="360" y="180"/>
</visualElement>
<visualElement>
<elementName>RegisterFile</elementName>
<elementAttributes>
<entry>
<string>AddrBits</string>
<int>4</int>
</entry>
<entry>
<string>Bits</string>
<int>16</int>
</entry>
</elementAttributes>
<pos x="240" y="140"/>
</visualElement>
</visualElements>
<wires>
<wire>
<p1 x="320" y="160"/>
<p2 x="340" y="160"/>
</wire>
<wire>
<p1 x="200" y="160"/>
<p2 x="240" y="160"/>
</wire>
<wire>
<p1 x="200" y="240"/>
<p2 x="240" y="240"/>
</wire>
<wire>
<p1 x="340" y="180"/>
<p2 x="360" y="180"/>
</wire>
<wire>
<p1 x="220" y="180"/>
<p2 x="240" y="180"/>
</wire>
<wire>
<p1 x="200" y="200"/>
<p2 x="240" y="200"/>
</wire>
<wire>
<p1 x="320" y="140"/>
<p2 x="360" y="140"/>
</wire>
<wire>
<p1 x="100" y="140"/>
<p2 x="240" y="140"/>
</wire>
<wire>
<p1 x="100" y="220"/>
<p2 x="220" y="220"/>
</wire>
<wire>
<p1 x="220" y="220"/>
<p2 x="240" y="220"/>
</wire>
<wire>
<p1 x="340" y="160"/>
<p2 x="340" y="180"/>
</wire>
<wire>
<p1 x="220" y="180"/>
<p2 x="220" y="220"/>
</wire>
</wires>
</circuit>

View File

@ -0,0 +1,130 @@
package de.neemann.digital.core.memory;
import de.neemann.digital.core.Node;
import de.neemann.digital.core.NodeException;
import de.neemann.digital.core.ObservableValue;
import de.neemann.digital.core.ObservableValues;
import de.neemann.digital.core.element.Element;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.ElementTypeDescription;
import de.neemann.digital.core.element.Keys;
import static de.neemann.digital.core.element.PinInfo.input;
/**
* A register file with two output a one input port.
*
* @author hneemann
*/
public class RegisterFile extends Node implements Element, RAMInterface {
/**
* The RAMs {@link ElementTypeDescription}
*/
public static final ElementTypeDescription DESCRIPTION = new ElementTypeDescription(RegisterFile.class,
input("Din"),
input("we"),
input("Rw"),
input("C"),
input("Ra"),
input("Rb"))
.addAttribute(Keys.ROTATE)
.addAttribute(Keys.BITS)
.addAttribute(Keys.ADDR_BITS)
.addAttribute(Keys.LABEL);
private final DataField memory;
private final ObservableValue out1;
private final ObservableValue out2;
private final int addrBits;
private final int bits;
private final String label;
private final int size;
private ObservableValue reg1In;
private ObservableValue reg2In;
private ObservableValue regWIn;
private ObservableValue data1In;
private ObservableValue weIn;
private ObservableValue clk1In;
private int reg1;
private int reg2;
private boolean lastClk = false;
/**
* Creates a new instance
*
* @param attr the elements attributes
*/
public RegisterFile(ElementAttributes attr) {
super(true);
bits = attr.get(Keys.BITS);
out1 = new ObservableValue("Da", bits).setPinDescription(DESCRIPTION);
out2 = new ObservableValue("Db", bits).setPinDescription(DESCRIPTION);
addrBits = attr.get(Keys.ADDR_BITS);
size = 1 << addrBits;
memory = new DataField(size);
label = attr.getCleanLabel();
}
@Override
public void setInputs(ObservableValues inputs) throws NodeException {
this.data1In = inputs.get(0).checkBits(bits, this);
this.weIn = inputs.get(1).checkBits(1, this);
this.regWIn = inputs.get(2).checkBits(addrBits, this);
this.clk1In = inputs.get(3).checkBits(1, this).addObserverToValue(this);
this.reg1In = inputs.get(4).checkBits(addrBits, this).addObserverToValue(this);
this.reg2In = inputs.get(5).checkBits(addrBits, this).addObserverToValue(this);
}
@Override
public ObservableValues getOutputs() {
return new ObservableValues(out1, out2);
}
@Override
public void readInputs() throws NodeException {
boolean clk = clk1In.getBool();
boolean str = !lastClk && clk && weIn.getBool();
if (str) {
long data = data1In.getValue();
int regW = (int) regWIn.getValue();
memory.setData(regW, data);
}
reg1 = (int) reg1In.getValue();
reg2 = (int) reg2In.getValue();
lastClk = clk;
}
@Override
public void writeOutputs() throws NodeException {
out1.setValue(memory.getDataWord(reg1));
out2.setValue(memory.getDataWord(reg2));
}
@Override
public DataField getMemory() {
return memory;
}
@Override
public String getLabel() {
return label;
}
@Override
public int getSize() {
return size;
}
@Override
public int getDataBits() {
return bits;
}
@Override
public int getAddrBits() {
return addrBits;
}
}

View File

@ -152,6 +152,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
.add(EEPROM.DESCRIPTION)
.add(GraphicCard.DESCRIPTION)
.add(RAMDualAccess.DESCRIPTION)
.add(RegisterFile.DESCRIPTION)
.add(Counter.DESCRIPTION))
.add(new LibraryNode(Lang.get("lib_arithmetic"))
.add(Add.DESCRIPTION)

View File

@ -37,10 +37,23 @@ public class RAMShape extends GenericShape {
* @throws PinException PinException
*/
public RAMShape(ElementAttributes attr, ElementTypeDescription description) throws NodeException, PinException {
this(attr, description, 3);
}
/**
* Creates a new instance
*
* @param attr the attributes of the element
* @param description element type description
* @param width the used width
* @throws NodeException NodeException
* @throws PinException PinException
*/
public RAMShape(ElementAttributes attr, ElementTypeDescription description, int width) throws NodeException, PinException {
super(description.getShortName(),
description.getInputDescription(attr),
description.getOutputDescriptions(attr),
attr.getLabel(), true);
attr.getLabel(), true, width);
if (attr.getLabel().length() > 0)
dialogTitle = attr.getLabel();
else

View File

@ -77,6 +77,7 @@ public final class ShapeFactory {
map.put(RAMSinglePortSel.DESCRIPTION.getName(), (attr, inputs, outputs) -> new RAMShape(attr, RAMSinglePortSel.DESCRIPTION));
map.put(EEPROM.DESCRIPTION.getName(), (attr, inputs, outputs) -> new RAMShape(attr, EEPROM.DESCRIPTION));
map.put(RAMDualAccess.DESCRIPTION.getName(), (attr, inputs, outputs) -> new RAMShape(attr, RAMDualAccess.DESCRIPTION));
map.put(RegisterFile.DESCRIPTION.getName(), (attr, inputs, outputs) -> new RAMShape(attr, RegisterFile.DESCRIPTION, 4));
map.put(In.DESCRIPTION.getName(), InputShape::new);
map.put(Reset.DESCRIPTION.getName(), ResetShape::new);

View File

@ -467,6 +467,20 @@
<string name="elem_RAMDualAccess_pin_ld">Ist diese Leitung high, wird der Ausgang D1 aktiviert, und die Daten liegen dort an.</string>
<string name="elem_RAMDualAccess_pin_str">Ist diese Leitung high, wird das Datenwort an D1 gespeichert, wenn der Takt ansteigt.</string>
<string name="elem_RegisterFile">Registerspeicher</string>
<string name="elem_RegisterFile_short">Register</string>
<string name="elem_RegisterFile_tt">Speicher mit einem Schreib- und zwei Leseports. Kann verwendet werden um
Prozessorregister zu implementieren.
Es können so gleichzeitig zwei Register gelesen und ein Drittes beschrieben werden.</string>
<string name="elem_RegisterFile_pin_Da">Inhalt des Registers a.</string>
<string name="elem_RegisterFile_pin_Db">Inhalt des Registers b.</string>
<string name="elem_RegisterFile_pin_Ra">Nummer des Registers a.</string>
<string name="elem_RegisterFile_pin_Rb">Nummer des Registers b.</string>
<string name="elem_RegisterFile_pin_Rw">Nummer des zu beschreibenden Registers.</string>
<string name="elem_RegisterFile_pin_we">Bei einer 1 werden die Daten in das Register Rw übernommen.</string>
<string name="elem_RegisterFile_pin_C">Takteingang</string>
<string name="elem_RegisterFile_pin_Din">Die zu schreibenden Daten.</string>
<string name="elem_Counter">Zähler</string>
<string name="elem_Counter_short">Zähler</string>
<string name="elem_Counter_tt">Ein einfacher Zähler-Baustein.

View File

@ -470,6 +470,20 @@
<string name="elem_RAMDualAccess_pin_ld">If this input is high the output is activated and the data is visible at the output 1D.</string>
<string name="elem_RAMDualAccess_pin_str">If this input is high and when the clock becomes high, the the data is stored.</string>
<string name="elem_RegisterFile">Register File</string>
<string name="elem_RegisterFile_short">Register</string>
<string name="elem_RegisterFile_tt">Memory with one port that allows to write and two ports that allow to read from
the memory simultaneously. Can be used to implement processor registers.
Two registers can be read simultaneously and a third can be written.</string>
<string name="elem_RegisterFile_pin_Da">Output Port a</string>
<string name="elem_RegisterFile_pin_Db">Output Port b</string>
<string name="elem_RegisterFile_pin_Ra">The register which is visible at port a.</string>
<string name="elem_RegisterFile_pin_Rb">The register which is visible at port b.</string>
<string name="elem_RegisterFile_pin_Rw">The register into which the data is written.</string>
<string name="elem_RegisterFile_pin_we">If this input is high and when the clock becomes high, the the data is stored.</string>
<string name="elem_RegisterFile_pin_C">Clock</string>
<string name="elem_RegisterFile_pin_Din">The data to be stored in the register Rw.</string>
<string name="elem_Counter">Counter</string>
<string name="elem_Counter_short">count</string>
<string name="elem_Counter_tt">A simple counter component. The clock input increases the counter.

View File

@ -0,0 +1,32 @@
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
entity DIG_RegisterFile is
generic (
Bits : integer;
AddrBits : integer );
port (
PORT_Da: out std_logic_vector ((Bits-1) downto 0);
PORT_Db: out std_logic_vector ((Bits-1) downto 0);
PORT_Din: in std_logic_vector ((Bits-1) downto 0);
PORT_we: in std_logic;
PORT_Rw: in std_logic_vector ((AddrBits-1) downto 0);
PORT_C: in std_logic;
PORT_Ra: in std_logic_vector ((AddrBits-1) downto 0);
PORT_Rb: in std_logic_vector ((AddrBits-1) downto 0) );
end DIG_RegisterFile;
architecture DIG_RegisterFile_arch of DIG_RegisterFile is
type memoryType is array(0 to (2**AddrBits)-1) of STD_LOGIC_VECTOR((Bits-1) downto 0);
signal memory : memoryType;
begin
process ( PORT_C )
begin
if rising_edge(PORT_C) AND (PORT_we='1') then
memory(to_integer(unsigned(PORT_Rw))) <= PORT_Din;
end if;
end process;
PORT_Da <= memory(to_integer(unsigned(PORT_Ra)));
PORT_Db <= memory(to_integer(unsigned(PORT_Rb)));
end DIG_RegisterFile_arch;

View File

@ -0,0 +1,43 @@
package de.neemann.digital.core.memory;
import de.neemann.digital.TestExecuter;
import de.neemann.digital.core.Model;
import de.neemann.digital.core.ObservableValue;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.Keys;
import junit.framework.TestCase;
import static de.neemann.digital.TestExecuter.HIGHZ;
import static de.neemann.digital.core.ObservableValues.ovs;
/**
* @author hneemann
*/
public class RegisterFileTest extends TestCase {
public void testRegisterFile() throws Exception {
ObservableValue ra = new ObservableValue("ra", 2);
ObservableValue rb = new ObservableValue("rb", 2);
ObservableValue rw = new ObservableValue("rw", 2);
ObservableValue in = new ObservableValue("in", 4);
ObservableValue we = new ObservableValue("we", 1);
ObservableValue clk = new ObservableValue("clk", 1);
Model model = new Model();
RegisterFile out = model.add(new RegisterFile(
new ElementAttributes()
.set(Keys.ADDR_BITS, 2)
.setBits(4)));
out.setInputs(ovs(in, we, rw, clk, ra, rb));
TestExecuter sc = new TestExecuter(model).setInputs(clk, in, we, rw, ra, rb).setOutputs(out.getOutputs());
// c in we rw ra rb da db
sc.check(0, 0, 0, 0, 0, 0, 0, 0);
sc.check(1, 7, 1, 1, 0, 0, 0, 0);
sc.check(0, 0, 0, 0, 1, 1, 7, 7);
sc.check(1, 5, 1, 2, 1, 1, 7, 7);
sc.check(0, 0, 0, 0, 1, 2, 7, 5);
}
}

View File

@ -37,7 +37,7 @@ public class TestInSimulator extends TestCase {
File examples = new File(Resources.getRoot(), "/dig/test/vhdl");
try {
int tested = new FileScanner(this::check).scan(examples);
assertEquals(25, tested);
assertEquals(26, tested);
assertEquals(tested, testBenches);
} catch (FileScanner.SkipAllException e) {
// if ghdl is not installed its also ok
@ -79,7 +79,7 @@ public class TestInSimulator extends TestCase {
/*
public void testInSimulatorDebug() throws Exception {
File file = new File(Resources.getRoot(),"dig/test/vhdl/priorityEncoder.dig");
File file = new File(Resources.getRoot(),"dig/test/vhdl/registerFile.dig");
ToBreakRunner br = new ToBreakRunner(file);
System.out.println(new VHDLGenerator(br.getLibrary(), new CodePrinterStr(true)).export(br.getCircuit()));

View File

@ -40,8 +40,8 @@ public class TestExamples extends TestCase {
*/
public void testTestExamples() throws Exception {
File examples = new File(Resources.getRoot(), "/dig/test");
assertEquals(115, new FileScanner(this::check).scan(examples));
assertEquals(105, testCasesInFiles);
assertEquals(116, new FileScanner(this::check).scan(examples));
assertEquals(106, testCasesInFiles);
}

View File

@ -0,0 +1,236 @@
<?xml version="1.0" encoding="utf-8"?>
<circuit>
<version>1</version>
<attributes/>
<visualElements>
<visualElement>
<elementName>Out</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>Da</string>
</entry>
<entry>
<string>Bits</string>
<int>8</int>
</entry>
</elementAttributes>
<pos x="600" y="200"/>
</visualElement>
<visualElement>
<elementName>Out</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>Db</string>
</entry>
<entry>
<string>Bits</string>
<int>8</int>
</entry>
</elementAttributes>
<pos x="600" y="240"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>Rw</string>
</entry>
<entry>
<string>Bits</string>
<int>4</int>
</entry>
</elementAttributes>
<pos x="360" y="280"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>C</string>
</entry>
</elementAttributes>
<pos x="360" y="320"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>we</string>
</entry>
</elementAttributes>
<pos x="360" y="240"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>Ra</string>
</entry>
<entry>
<string>Bits</string>
<int>4</int>
</entry>
</elementAttributes>
<pos x="360" y="360"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>Di</string>
</entry>
<entry>
<string>Bits</string>
<int>8</int>
</entry>
</elementAttributes>
<pos x="360" y="200"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>Rb</string>
</entry>
<entry>
<string>Bits</string>
<int>4</int>
</entry>
</elementAttributes>
<pos x="360" y="400"/>
</visualElement>
<visualElement>
<elementName>Testcase</elementName>
<elementAttributes>
<entry>
<string>Testdata</string>
<testData>
<dataString>C we Di Rw Ra Rb Da Db
# write all registers
loop (a, 16)
c 1 (a*10) (a) 0 0 x x
end loop
# read registers
loop (a, 16)
0 0 0 0 (a) 0 (a*10) 0
0 0 0 0 0 (a) 0 (a*10)
0 0 0 0 (a) (a) (a*10) (a*10)
end loop
0 1 1 0 0 0 0 0
1 1 1 0 0 0 1 1
0 0 0 0 0 0 1 1
</dataString>
</testData>
</entry>
</elementAttributes>
<pos x="540" y="360"/>
</visualElement>
<visualElement>
<elementName>RegisterFile</elementName>
<elementAttributes>
<entry>
<string>AddrBits</string>
<int>4</int>
</entry>
<entry>
<string>Bits</string>
<int>8</int>
</entry>
</elementAttributes>
<pos x="480" y="200"/>
</visualElement>
</visualElements>
<wires>
<wire>
<p1 x="580" y="240"/>
<p2 x="600" y="240"/>
</wire>
<wire>
<p1 x="360" y="240"/>
<p2 x="380" y="240"/>
</wire>
<wire>
<p1 x="400" y="240"/>
<p2 x="480" y="240"/>
</wire>
<wire>
<p1 x="360" y="320"/>
<p2 x="420" y="320"/>
</wire>
<wire>
<p1 x="360" y="400"/>
<p2 x="460" y="400"/>
</wire>
<wire>
<p1 x="420" y="260"/>
<p2 x="480" y="260"/>
</wire>
<wire>
<p1 x="560" y="200"/>
<p2 x="600" y="200"/>
</wire>
<wire>
<p1 x="360" y="200"/>
<p2 x="480" y="200"/>
</wire>
<wire>
<p1 x="360" y="280"/>
<p2 x="400" y="280"/>
</wire>
<wire>
<p1 x="440" y="280"/>
<p2 x="480" y="280"/>
</wire>
<wire>
<p1 x="360" y="360"/>
<p2 x="440" y="360"/>
</wire>
<wire>
<p1 x="560" y="220"/>
<p2 x="580" y="220"/>
</wire>
<wire>
<p1 x="380" y="220"/>
<p2 x="480" y="220"/>
</wire>
<wire>
<p1 x="460" y="300"/>
<p2 x="480" y="300"/>
</wire>
<wire>
<p1 x="400" y="240"/>
<p2 x="400" y="280"/>
</wire>
<wire>
<p1 x="580" y="220"/>
<p2 x="580" y="240"/>
</wire>
<wire>
<p1 x="420" y="260"/>
<p2 x="420" y="320"/>
</wire>
<wire>
<p1 x="440" y="280"/>
<p2 x="440" y="360"/>
</wire>
<wire>
<p1 x="380" y="220"/>
<p2 x="380" y="240"/>
</wire>
<wire>
<p1 x="460" y="300"/>
<p2 x="460" y="400"/>
</wire>
</wires>
</circuit>