From 98c791e87ad218fda90827447518bdef43fa45a6 Mon Sep 17 00:00:00 2001 From: Neta London Date: Sun, 16 Jun 2024 20:35:36 +0300 Subject: [PATCH 1/3] Add full topological sort --- simulator/src/chip/builder.ts | 1 + simulator/src/chip/chip.ts | 72 +++++++++++++++++++++++++++++------ 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/simulator/src/chip/builder.ts b/simulator/src/chip/builder.ts index 28910e50..e731e234 100644 --- a/simulator/src/chip/builder.ts +++ b/simulator/src/chip/builder.ts @@ -213,6 +213,7 @@ class ChipBuilder { } // Reset clock order after wiring sub-pins + this.chip.sortParts(); for (const part of this.chip.parts) { part.subscribeToClock(); } diff --git a/simulator/src/chip/chip.ts b/simulator/src/chip/chip.ts index c7e82e0d..4faea27c 100644 --- a/simulator/src/chip/chip.ts +++ b/simulator/src/chip/chip.ts @@ -8,9 +8,9 @@ import { Result, isErr, } from "@davidsouther/jiffies/lib/esm/result.js"; +import type { Subscription } from "rxjs"; import { bin } from "../util/twos.js"; import { Clock } from "./clock.js"; -import type { Subscription } from "rxjs"; export const HIGH = 1; export const LOW = 0; @@ -455,20 +455,70 @@ export class Chip { // It should go at the lower of: // before the first chip that it has an output to, or at the end // after the last chip it has an input from, or at the beginning - const before = this.parts - .map((other, i) => ({ other, i })) - .filter(({ other }) => this.hasConnection(part, other)); - const beforeIdx = before.at(0)?.i ?? this.parts.length; - const after = this.parts - .map((other, i) => ({ other, i })) - .filter(({ other }) => this.hasConnection(other, part)); - const afterIdx = (after.at(-1)?.i ?? -1) + 1; - const index = Math.min(beforeIdx, afterIdx); - this.parts.splice(index, 0, part); + // const before = this.parts + // .map((other, i) => ({ other, i })) + // .filter(({ other }) => this.hasConnection(part, other)); + // const beforeIdx = before.at(0)?.i ?? this.parts.length; + // const after = this.parts + // .map((other, i) => ({ other, i })) + // .filter(({ other }) => this.hasConnection(other, part)); + // const afterIdx = (after.at(-1)?.i ?? -1) + 1; + // const index = Math.min(beforeIdx, afterIdx); + // this.parts.splice(index, 0, part); + this.parts.push(part); return Ok(); } + sortParts() { + const sorted: Chip[] = []; + const visited = new Set(); + const visiting = new Set(); + + type Node = { part: Chip; isReturning: boolean }; + + const stack: Node[] = this.parts.map((part) => ({ + part, + isReturning: false, + })); + + while (stack.length > 0) { + const node = assertExists(stack.pop()); + + if (node.isReturning) { + // If we are returning to this node, we can safely add it to the sorted list + visited.add(node.part); + sorted.push(node.part); + } else if (!visited.has(node.part)) { + if (visiting.has(node.part)) { + continue; + } + visiting.add(node.part); + + // Re-push this node to handle it on return + stack.push({ part: node.part, isReturning: true }); + + // Push all its children to visit them + for (const out of this.partToOuts.get(node.part) ?? []) { + stack.push( + ...Array.from(this.insToPart.get(out) ?? []) + .filter( + (part) => + !(part.clocked && this.isInternalPin(out)) && + !visited.has(part), + ) + .map((part) => ({ + part, + isReturning: false, + })), + ); + } + } + } + + this.parts = sorted.reverse(); + } + private findPin(from: string, minWidth?: number): Pin { if (from === "true" || from === "1") { return TRUE_BUS; From 3992739d2603112f57fdf280a53a40d5481428eb Mon Sep 17 00:00:00 2001 From: Neta London Date: Sun, 16 Jun 2024 21:18:46 +0300 Subject: [PATCH 2/3] Remove old insertion sort code --- simulator/src/chip/chip.ts | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/simulator/src/chip/chip.ts b/simulator/src/chip/chip.ts index 4faea27c..4deb724b 100644 --- a/simulator/src/chip/chip.ts +++ b/simulator/src/chip/chip.ts @@ -450,21 +450,6 @@ export class Chip { } } } - - // Topological insertion sort for where this part should go. - // It should go at the lower of: - // before the first chip that it has an output to, or at the end - // after the last chip it has an input from, or at the beginning - // const before = this.parts - // .map((other, i) => ({ other, i })) - // .filter(({ other }) => this.hasConnection(part, other)); - // const beforeIdx = before.at(0)?.i ?? this.parts.length; - // const after = this.parts - // .map((other, i) => ({ other, i })) - // .filter(({ other }) => this.hasConnection(other, part)); - // const afterIdx = (after.at(-1)?.i ?? -1) + 1; - // const index = Math.min(beforeIdx, afterIdx); - // this.parts.splice(index, 0, part); this.parts.push(part); return Ok(); From 8d0278a605cfe07ca89464b0542593fed81d6b0e Mon Sep 17 00:00:00 2001 From: Neta London Date: Sun, 16 Jun 2024 21:51:13 +0300 Subject: [PATCH 3/3] Fix tests --- simulator/src/chip/chip.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/simulator/src/chip/chip.test.ts b/simulator/src/chip/chip.test.ts index 58d1ecdf..729cbe8f 100644 --- a/simulator/src/chip/chip.test.ts +++ b/simulator/src/chip/chip.test.ts @@ -641,6 +641,7 @@ describe("Chip", () => { } const fooA = new FooA(); + fooA.sortParts(); expect(fooA.parts).toEqual([fooA.notB, fooA.notA]); class FooB extends Chip { @@ -672,6 +673,7 @@ describe("Chip", () => { } const fooB = new FooB(); + fooB.sortParts(); expect(fooB.parts).toEqual([fooB.notA, fooB.notB]); }); @@ -719,6 +721,7 @@ describe("Chip", () => { } } const fooC = new FooC(); + fooC.sortParts(); const parts = fooC.parts.map((chip) => chip.id); expect(parts).toEqual([fooC.register.id, fooC.inc16A.id, fooC.inc16B.id]); });