/// <summary> /// Restore wire linkage /// </summary> /// <param name="model"></param> public static void RestoreLinkage(LogisimModel model) { foreach (var wire in model.wires) { foreach (var comp in model.comps) { if (wire.sourceId == comp.id) { wire.source = comp; } if (wire.destId == comp.id) { wire.dest = comp; } } foreach (var vias in model.viases) { if (wire.sourceId == vias.id) { wire.source = vias; } if (wire.destId == vias.id) { wire.dest = vias; } } } }
/// <summary> /// Reduce simple vias connections /// </summary> /// <param name="model"></param> public static void Reduce(LogisimModel model) { bool found = false; do { found = false; foreach (var vias in model.viases) { // Count inputs/outputs for vias int inputCount = 0; int outputCount = 0; LogisimWire wireIn = null; LogisimWire wireOut = null; foreach (var wire in model.wires) { if (wire.dest == vias) { if (wireIn == null) { wireIn = wire; } inputCount++; } if (wire.source == vias) { if (wireOut == null) { wireOut = wire; } outputCount++; } } // If exactly 1/1 - delete vias and reduce wire if (inputCount == 1 && outputCount == 1) { Point last = wireIn.To(); wireIn.path.Remove(last); wireIn.path.AddRange(wireOut.path); wireIn.dest = wireOut.dest; model.wires.Remove(wireOut); model.viases.Remove(vias); if (wireIn.name == "") { wireIn.name = wireOut.name; } found = true; break; } } } while (found); }
private static LogisimVias GetViasByLoc(LogisimModel model, Point loc) { foreach (var vias in model.viases) { if (vias.loc.Equals(loc)) { return(vias); } } return(null); }
private static LogisimComp ViasIntersectComp(LogisimModel model, LogisimVias vias) { foreach (var comp in model.comps) { Rectangle rect = new Rectangle(comp.loc.X, comp.loc.Y, CompSize + 2, CompSize + 2); if (rect.Contains(vias.loc)) { return(comp); } } return(null); }
/// <summary> /// Connect wires with components /// </summary> /// <param name="model"></param> private static void PreProcessing(LogisimModel model) { foreach (var wire in model.wires) { foreach (var comp in model.comps) { if (comp.loc.Equals(wire.From()) && wire.source.id < 0) { wire.source = comp; } if (comp.loc.Equals(wire.To()) && wire.dest.id < 0) { wire.dest = comp; } } } }
public static void DumpLogisimModel(LogisimModel model) { Console.WriteLine(model.name + ":"); foreach (var comp in model.comps) { comp.Dump(); } foreach (var wire in model.wires) { wire.Dump(); } foreach (var vias in model.viases) { vias.Dump(); } }
public static int GetNextId(LogisimModel model) { int id = -1; foreach (var comp in model.comps) { if (comp.id > id) { id = comp.id; } } foreach (var vias in model.viases) { if (vias.id > id) { id = vias.id; } } return(id + 1); }
/// <summary> /// Convert logisim model to yEd Xml /// </summary> /// <param name="model"></param> /// <returns></returns> public static XmlDocument ToYed(LogisimModel model) { XmlDocument doc = new XmlDocument(); // Create an XML declaration XmlDeclaration xmldecl; xmldecl = doc.CreateXmlDeclaration("1.0", "UTF-8", "no"); // Add the new node to the document XmlElement root = doc.DocumentElement; doc.InsertBefore(xmldecl, root); // Convert Logisim Model to Yed Model YedModel yed = new YedModel(); AddYedKeys(yed); YedData graphData = new YedData(); graphData.key = "d0"; graphData.xmlSpace = "preserve"; yed.graph.data.Add(graphData); foreach (var comp in model.comps) { YedNode node = new YedNode(); node.id = "n" + comp.id.ToString(); YedData d6 = new YedData(); node.data.Add(d6); d6.key = "d6"; d6.node = new YedShapeNode(); d6.node.geometry = new YedGeometry(); d6.node.fill = new YedFill(); d6.node.label = new YedNodeLabel(); d6.node.shape = new YedShape(); d6.node.geometry.x = comp.loc.X; d6.node.geometry.y = comp.loc.Y; d6.node.geometry.width = CompSize; d6.node.geometry.height = CompSize; if (comp.name == "1") { d6.node.fill.color = "#FF6600"; } else if (comp.name == "0") { d6.node.fill.color = "#339966"; } else { d6.node.fill.color = "#FFCC00"; } d6.node.fill.transparent = false; d6.node.label.text = comp.name; d6.node.shape.type = "rectangle"; yed.graph.nodes.Add(node); } foreach (var vias in model.viases) { YedNode node = new YedNode(); node.id = "n" + vias.id.ToString(); YedData d6 = new YedData(); node.data.Add(d6); d6.key = "d6"; d6.node = new YedShapeNode(); d6.node.geometry = new YedGeometry(); d6.node.fill = new YedFill(); d6.node.shape = new YedShape(); d6.node.geometry.width = 5; d6.node.geometry.height = 5; d6.node.geometry.x = vias.loc.X - d6.node.geometry.width / 2; d6.node.geometry.y = vias.loc.Y - d6.node.geometry.height / 2; d6.node.fill.color = "#FFCC00"; d6.node.fill.transparent = false; d6.node.shape.type = "ellipse"; yed.graph.nodes.Add(node); } int edgeId = 0; // Doesn't matter.. foreach (var wire in model.wires) { // Skip wires to nowhere if (wire.source.id < 0 || wire.dest.id < 0) { continue; } YedEdge edge = new YedEdge(); edge.id = "e" + edgeId.ToString(); edge.source = "n" + wire.source.id.ToString(); edge.target = "n" + wire.dest.id.ToString(); edgeId++; YedData d10 = new YedData(); d10.key = "d10"; edge.data.Add(d10); d10.edge = new YedPolyLineEdge(); if (wire.path.Count > 2) { for (int i = 1; i < wire.path.Count - 1; i++) { d10.edge.path.points.Add(new YedPoint(wire.path[i].X, wire.path[i].Y)); } } if (wire.name != "") { d10.edge.label = new YedEdgeLabel(wire.name); } yed.graph.edges.Add(edge); } // Convert Yed Model to Xml var nav = doc.CreateNavigator(); var ns = new XmlSerializerNamespaces(); ns.Add("java", "http://www.yworks.com/xml/yfiles-common/1.0/java"); ns.Add("sys", "http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0"); ns.Add("x", "http://www.yworks.com/xml/yfiles-common/markup/2.0"); ns.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance"); ns.Add("y", "http://www.yworks.com/xml/graphml"); ns.Add("yed", "http://www.yworks.com/xml/yed/3"); using (var writer = nav.AppendChild()) { var ser = new XmlSerializer(typeof(YedModel)); ser.Serialize(writer, yed, ns); } return(doc); }
/// <summary> /// Parse Logisim Xml to model. /// </summary> /// <param name="source">Logisim Circuit</param> /// <returns>Model</returns> public static LogisimModel LoadModel(XmlDocument source) { // Get circuit XmlNode circuit = null; foreach (XmlNode node in source.DocumentElement.ChildNodes) { if (node.Name == "circuit") { circuit = node; break; } } if (circuit == null) { throw new Exception("Invalid format. Missing circuit."); } // Processing LogisimModel model = new LogisimModel(); if (circuit.Attributes["name"] != null) { model.name = circuit.Attributes["name"].Value; } // Get components foreach (XmlNode node in circuit) { if (node.Name == "comp") { LogisimComp comp = new LogisimComp(); if (node.Attributes["lib"] != null) { comp.lib = int.Parse(node.Attributes["lib"].Value); } comp.loc = ParseLoc(node.Attributes["loc"].Value); comp.name = node.Attributes["name"].Value; comp.id = GetNextId(model); foreach (XmlNode a in node) { if (a.Name == "a") { string k = a.Attributes["name"].Value; string v = a.Attributes["val"].Value; comp.props[k] = v; } } model.comps.Add(comp); } } // Get wires foreach (XmlNode node in circuit) { if (node.Name == "wire") { Point start = ParseLoc(node.Attributes["from"].Value); Point end = ParseLoc(node.Attributes["to"].Value); LogisimWire wire = new LogisimWire(start, end); model.wires.Add(wire); } } // Connect wires with components PreProcessing(model); // Get wires interconnections (produce viases) foreach (var wire in model.wires) { foreach (var another in model.wires) { if (wire != another) { if (wire.From().Equals(another.From()) || wire.From().Equals(another.To())) { LogisimVias vias = new LogisimVias(wire.From()); if (!model.ViasExists(vias)) { vias.id = GetNextId(model); model.viases.Add(vias); } } if (wire.To().Equals(another.To()) || wire.To().Equals(another.From())) { LogisimVias vias = new LogisimVias(wire.To()); if (!model.ViasExists(vias)) { vias.id = GetNextId(model); model.viases.Add(vias); } } } } } PostProcessing(model); Reduce(model); DumpLogisimModel(model); return(model); }
private static void AddTrans(Rectangle bbox, LogisimComp comp, LogisimModel model) { LogisimWire source = null; LogisimWire drain = null; LogisimWire gate = null; LogisimVias sourcePad = null; LogisimVias drainPad = null; LogisimVias gatePad = null; int delta = 12; bool br = false; // Gate direction (br? wtf is br?) if (comp.props.ContainsKey("gate")) { br = comp.props["gate"] == "br" ? true : false; } // Facing of drain // TODO: Some translational symmetry here.. make code more compact.. and complicated switch (comp.props["facing"]) { case "north": source = new LogisimWire( new Point(bbox.X + bbox.Width / 2, bbox.Y + bbox.Height + delta), new Point(bbox.X + bbox.Width / 2, bbox.Y + bbox.Height)); drain = new LogisimWire( new Point(bbox.X + bbox.Width / 2, bbox.Y), new Point(bbox.X + bbox.Width / 2, bbox.Y - delta)); if (br) { gate = new LogisimWire( new Point(bbox.X + bbox.Width + delta, bbox.Y + bbox.Height / 2), new Point(bbox.X + bbox.Width, bbox.Y + bbox.Height / 2)); } else { gate = new LogisimWire( new Point(bbox.X - delta, bbox.Y + bbox.Height / 2), new Point(bbox.X, bbox.Y + bbox.Height / 2)); } break; case "south": source = new LogisimWire( new Point(bbox.X + bbox.Width / 2, bbox.Y - delta), new Point(bbox.X + bbox.Width / 2, bbox.Y)); drain = new LogisimWire( new Point(bbox.X + bbox.Width / 2, bbox.Y + bbox.Height), new Point(bbox.X + bbox.Width / 2, bbox.Y + bbox.Height + delta)); if (br) { gate = new LogisimWire( new Point(bbox.X + bbox.Width + delta, bbox.Y + bbox.Height / 2), new Point(bbox.X + bbox.Width, bbox.Y + bbox.Height / 2)); } else { gate = new LogisimWire( new Point(bbox.X - delta, bbox.Y + bbox.Height / 2), new Point(bbox.X, bbox.Y + bbox.Height / 2)); } break; case "west": source = new LogisimWire( new Point(bbox.X + bbox.Width + delta, bbox.Y + bbox.Height / 2), new Point(bbox.X + bbox.Width, bbox.Y + bbox.Height / 2)); drain = new LogisimWire( new Point(bbox.X, bbox.Y + bbox.Height / 2), new Point(bbox.X - delta, bbox.Y + bbox.Height / 2)); if (br) { gate = new LogisimWire( new Point(bbox.X + bbox.Width / 2, bbox.Y + bbox.Height + delta), new Point(bbox.X + bbox.Width / 2, bbox.Y + bbox.Height)); } else { gate = new LogisimWire( new Point(bbox.X + bbox.Width / 2, bbox.Y - delta), new Point(bbox.X + bbox.Width / 2, bbox.Y)); } break; case "east": source = new LogisimWire( new Point(bbox.X - delta, bbox.Y + bbox.Height / 2), new Point(bbox.X, bbox.Y + bbox.Height / 2)); drain = new LogisimWire( new Point(bbox.X + bbox.Width, bbox.Y + bbox.Height / 2), new Point(bbox.X + bbox.Width + delta, bbox.Y + bbox.Height / 2)); if (br) { gate = new LogisimWire( new Point(bbox.X + bbox.Width / 2, bbox.Y + bbox.Height + delta), new Point(bbox.X + bbox.Width / 2, bbox.Y + bbox.Height)); } else { gate = new LogisimWire( new Point(bbox.X + bbox.Width / 2, bbox.Y - delta), new Point(bbox.X + bbox.Width / 2, bbox.Y)); } break; } // Create actual nodes/edges and link them sourcePad = GetViasByLoc(model, source.From()); if (sourcePad == null) { sourcePad = new LogisimVias(source.From()); } drainPad = GetViasByLoc(model, drain.To()); if (drainPad == null) { drainPad = new LogisimVias(drain.To()); } gatePad = GetViasByLoc(model, gate.From()); if (gatePad == null) { gatePad = new LogisimVias(gate.From()); } int nextId = GetNextId(model); sourcePad.id = nextId; drainPad.id = nextId + 1; gatePad.id = nextId + 2; gate.name = "g"; // Required by GraphFlow // Source LogisimComp sourceComp = ViasIntersectComp(model, sourcePad); if (sourceComp != null) { source.source = sourceComp; sourcePad = null; } else { source.source = sourcePad; } source.dest = comp; model.wires.Add(source); if (sourcePad != null) { model.viases.Add(sourcePad); } // Drain LogisimComp drainComp = ViasIntersectComp(model, drainPad); if (drainComp != null) { drain.dest = drainComp; drainPad = null; } else { drain.dest = drainPad; } drain.source = comp; model.wires.Add(drain); if (drainPad != null) { model.viases.Add(drainPad); } // Gate LogisimComp gateComp = ViasIntersectComp(model, gatePad); if (gateComp != null) { gate.source = gateComp; gatePad = null; } else { gate.source = gatePad; } gate.dest = comp; model.wires.Add(gate); if (gatePad != null) { model.viases.Add(gatePad); } }
/// <summary> /// Modify model to look nice /// </summary> /// <param name="model"></param> private static void PostProcessing(LogisimModel model) { int nfetCounter = 1; int pfetCounter = 1; // Comps foreach (var comp in model.comps) { string facingDefault = "east"; if (comp.name == "Transistor") { if (comp.props.ContainsKey("type")) { if (comp.props["type"] == "n") { comp.name = "nfet_" + nfetCounter.ToString(); nfetCounter++; } else { comp.name = "pfet_" + pfetCounter.ToString(); pfetCounter++; } } else { comp.name = "pfet_" + pfetCounter.ToString(); pfetCounter++; } if (!comp.props.ContainsKey("facing")) { comp.props["facing"] = facingDefault; } switch (comp.props["facing"]) { case "north": comp.loc = new Point( comp.loc.X, comp.loc.Y + CompSize - 4); break; case "south": comp.loc = new Point( comp.loc.X, comp.loc.Y - CompSize + 4); break; case "west": comp.loc = new Point( comp.loc.X + CompSize - 4, comp.loc.Y); break; case "east": comp.loc = new Point( comp.loc.X - CompSize + 4, comp.loc.Y); break; } } else if (comp.name == "Power") { comp.name = "1"; if (!comp.props.ContainsKey("facing")) { comp.props["facing"] = facingDefault; } if (comp.props["facing"] == "west") { comp.props["facing"] = "east"; } else if (comp.props["facing"] == "east") { comp.props["facing"] = "west"; } } else if (comp.name == "Ground") { comp.name = "0"; if (!comp.props.ContainsKey("facing")) { comp.props["facing"] = facingDefault; } if (comp.props["facing"] == "west") { comp.props["facing"] = "east"; } else if (comp.props["facing"] == "east") { comp.props["facing"] = "west"; } } else if (comp.name == "Pin") { if (comp.props.ContainsKey("label")) { comp.name = comp.props["label"]; } if (!comp.props.ContainsKey("facing")) { comp.props["facing"] = facingDefault; } } if (comp.props.ContainsKey("facing")) { switch (comp.props["facing"]) { case "north": comp.loc = new Point( comp.loc.X - CompSize / 2, comp.loc.Y); break; case "south": comp.loc = new Point( comp.loc.X - CompSize / 2, comp.loc.Y - CompSize); break; case "west": comp.loc = new Point( comp.loc.X, comp.loc.Y - CompSize / 2); break; case "east": comp.loc = new Point( comp.loc.X - CompSize, comp.loc.Y - CompSize / 2); break; } } if (comp.name.Contains("nfet") || comp.name.Contains("pfet")) { AddTrans(new Rectangle(comp.loc.X, comp.loc.Y, CompSize, CompSize), comp, model); } } // Link wires with viases foreach (var wire in model.wires) { foreach (var vias in model.viases) { if (vias.loc.Equals(wire.From()) && wire.source.id < 0) { wire.source = vias; } if (vias.loc.Equals(wire.To()) && wire.dest.id < 0) { wire.dest = vias; } } } }