Skip to content

Repository files navigation

@tscircuit/crossbar-mapping-solver

Maps a horizontal line of incoming fanout traces through a spread zone and column gaps to matching vias in an alternating crossbar matrix.

Open the Cosmos solver debugger

Input

interface FanoutPoint {
  x: number
  y: number
  netId: string
}

interface CrossbarVia {
  y: number
  diameter: number
  netId: string
}

interface CrossbarColumn {
  x: number
  vias: Array<CrossbarVia>
}

interface InputProblem {
  fanoutPoints: Array<FanoutPoint>
  columns: Array<CrossbarColumn>
}

Every fanout point must share the same y, forming one horizontal line above all crossbar vias. The empty interval between that line and the highest via is the spread zone. Fanout points are assigned to compatible, unique column gaps in the same left-to-right order as their source points. Each trace initially descends, spreads diagonally to its gap, descends between the columns, then turns left or right into an adjacent via with the same netId. This ordered assignment prevents different-net traces from crossing or overlapping.

For an alternating matrix, neighboring columns expose different nets to the same gap:

F1      F2      F3
<---- spread zone ---->
C1  C2  C3  C4  C5  C6
N1  N2  N1  N2  N1  N2
N3  N4  N3  N4  N3  N4

Usage

import {
  CrossbarMappingSolver,
  type InputProblem,
} from "@tscircuit/crossbar-mapping-solver"

const input: InputProblem = {
  fanoutPoints: [
    { x: 4, y: 10, netId: "N1" },
    { x: 5, y: 10, netId: "N2" },
    { x: 6, y: 10, netId: "N3" },
  ],
  columns: [
    {
      x: 0,
      vias: [
        { y: 2, diameter: 0.8, netId: "N1" },
        { y: 0, diameter: 0.8, netId: "N3" },
      ],
    },
    {
      x: 2,
      vias: [
        { y: 2, diameter: 0.8, netId: "N2" },
        { y: 0, diameter: 0.8, netId: "N4" },
      ],
    },
    {
      x: 4,
      vias: [
        { y: 2, diameter: 0.8, netId: "N1" },
        { y: 0, diameter: 0.8, netId: "N3" },
      ],
    },
    {
      x: 6,
      vias: [
        { y: 2, diameter: 0.8, netId: "N2" },
        { y: 0, diameter: 0.8, netId: "N4" },
      ],
    },
    {
      x: 8,
      vias: [
        { y: 2, diameter: 0.8, netId: "N1" },
        { y: 0, diameter: 0.8, netId: "N3" },
      ],
    },
    {
      x: 10,
      vias: [
        { y: 2, diameter: 0.8, netId: "N2" },
        { y: 0, diameter: 0.8, netId: "N4" },
      ],
    },
  ],
}

const solver = new CrossbarMappingSolver(input)
solver.solve()

const output = solver.getOutput()

Development

bun install
bun test
bun run typecheck
bun run format:check
bun run start

bun run start opens ten React Cosmos pages, example01 through example10, each containing the generic solver debugger. To make coincident routes legible, the debugger applies tiny deterministic X/Y offsets to rendered paths. These offsets never change solver output geometry.

Every SVG example also checks all pairs of output segments and fails if traces with different netId values intersect, touch, or overlap. Same-net trace overlap is allowed.

Example ladder

Example Routes Columns Buses Routed nets Fanout spacing
01 1 2 2 1 Single source
02 2 4 4 2 Close pair
03 3 6 4 3 Uneven
04 4 8 6 4 Tight cluster + outlier
05 6 12 8 5 Two asymmetric clusters
06 8 16 8 6 Unsorted clusters
07 12 24 10 8 Three clusters
08 18 36 12 12 Three irregular clusters
09 28 56 16 16 Three dense clusters
10 40 80 20 16 Four dense clusters

Example 10 routes NET thirteen times and VCC thirteen times, plus fourteen signal nets. Its crossbar exposes four additional buses that are not requested by the fanout.

Examples 3–10 assert that adjacent fanout spacing is nonuniform. Clustered examples additionally assert that the largest empty interval is at least three times the smallest adjacent spacing.

Simple output

Simple crossbar mapping

About

Map columnar fanout vias into alternating crossbar bus channels

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages