refactor: bus terminals with single-sided pins only

BUS_IN has input pins only (left side), BUS_OUT has output pins
only (right side). No internal connections between them — BUS_OUT
reads values directly from its paired BUS_IN via busPairId. The
bus cable between them is purely visual, representing the grouped
signal bundle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jose Luis
2026-03-20 04:50:42 +01:00
parent 9ec3367253
commit c116b6cf84
4 changed files with 102 additions and 92 deletions

View File

@@ -125,33 +125,32 @@ export function createBusFromCut() {
const busInId = state.nextId++;
const busOutId = state.nextId++;
// Create BUS_IN terminal (left — collects wires into bus)
// Create BUS_IN terminal (left — collects wires into bus, only input pins)
const busIn = {
id: busInId,
type: `BUS:${n}`,
type: `BUS_IN:${n}`,
x: avgX - gap / 2 - 15,
y: avgY - busH / 2,
value: 0,
outputValues: new Array(n).fill(0),
busRole: 'in',
busValues: new Array(n).fill(0),
busPairId: busOutId
};
// Create BUS_OUT terminal (right — distributes bus back to wires)
// Create BUS_OUT terminal (right — distributes bus back to wires, only output pins)
const busOut = {
id: busOutId,
type: `BUS:${n}`,
type: `BUS_OUT:${n}`,
x: avgX + gap / 2 - 15,
y: avgY - busH / 2,
value: 0,
outputValues: new Array(n).fill(0),
busRole: 'out',
busPairId: busInId
};
state.gates.push(busIn, busOut);
// Rewire connections through both terminals
// Rewire: source → BUS_IN input, BUS_OUT output → destination
// No internal connections — BUS_OUT reads from BUS_IN directly via busPairId
hits.forEach((hit, i) => {
const orig = hit.conn;
@@ -166,14 +165,6 @@ export function createBusFromCut() {
toPort: i
});
// BUS_IN output[i] → BUS_OUT input[i] (internal bus link, rendered as cable)
state.connections.push({
from: busIn.id,
fromPort: i,
to: busOut.id,
toPort: i
});
// BUS_OUT output[i] → original destination
state.connections.push({
from: busOut.id,
@@ -187,19 +178,6 @@ export function createBusFromCut() {
evaluateAll();
}
/**
* Check if a connection is an internal bus link (between paired terminals).
* Used by the renderer to skip drawing these as normal wires.
*/
export function isBusInternalConnection(conn) {
const fromGate = state.gates.find(g => g.id === conn.from);
const toGate = state.gates.find(g => g.id === conn.to);
if (!fromGate || !toGate) return false;
return fromGate.type.startsWith('BUS:') &&
toGate.type.startsWith('BUS:') &&
fromGate.busPairId === toGate.id;
}
/**
* Get all bus pairs for rendering the bus cables.
* Returns array of { inGate, outGate } for each pair.
@@ -208,15 +186,12 @@ export function getBusPairs() {
const pairs = [];
const seen = new Set();
for (const gate of state.gates) {
if (!gate.type.startsWith('BUS:') || !gate.busPairId || seen.has(gate.id)) continue;
const pair = state.gates.find(g => g.id === gate.busPairId);
if (!pair) continue;
if (!gate.type.startsWith('BUS_IN:') || !gate.busPairId || seen.has(gate.id)) continue;
const outGate = state.gates.find(g => g.id === gate.busPairId);
if (!outGate || !outGate.type.startsWith('BUS_OUT:')) continue;
seen.add(gate.id);
seen.add(pair.id);
// Determine which is in, which is out
const inGate = gate.busRole === 'in' ? gate : pair;
const outGate = gate.busRole === 'out' ? gate : pair;
pairs.push({ inGate, outGate });
seen.add(outGate.id);
pairs.push({ inGate: gate, outGate });
}
return pairs;
}