kisch 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/package.json +5 -2
- package/src/app/exports.js +1 -0
- package/src/{kisch-cli.js → app/kisch-cli.js} +25 -9
- package/src/schematic/CompoundSymbol.js +35 -0
- package/src/{Entity.js → schematic/Entity.js} +122 -18
- package/src/{LibrarySymbol.js → schematic/LibrarySymbol.js} +37 -2
- package/src/{Schematic.js → schematic/Schematic.js} +194 -78
- package/src/{SymbolLibrary.js → schematic/SymbolLibrary.js} +1 -1
- package/src/utils/RoutingGrid.js +260 -0
- package/src/utils/astar.js +113 -0
- package/src/{cartesian-math.js → utils/cartesian-math.js} +44 -3
- package/src/utils/grid-util.js +39 -0
- package/src/utils/js-util.js +33 -0
- package/src/{node-util.js → utils/node-util.js} +5 -0
- package/src/js-util.js +0 -15
- package/src/manhattan-router.js +0 -176
- /package/src/{place-rect.js → utils/place-rect.js} +0 -0
- /package/src/{sexp.js → utils/sexp.js} +0 -0
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kisch",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"test": "jasmine"
|
|
11
11
|
},
|
|
12
12
|
"bin": {
|
|
13
|
-
"kisch": "src/kisch-cli.js"
|
|
13
|
+
"kisch": "src/app/kisch-cli.js"
|
|
14
14
|
},
|
|
15
15
|
"keywords": [],
|
|
16
16
|
"author": "",
|
|
@@ -22,5 +22,8 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"commander": "^14.0.3"
|
|
25
|
+
},
|
|
26
|
+
"exports": {
|
|
27
|
+
".": "./src/exports.js"
|
|
25
28
|
}
|
|
26
29
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {default as SymbolLibrary} from "./SymbolLibrary.js";
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import {program} from "commander";
|
|
4
|
-
import Schematic, {loadSchematic, createSchematic} from "
|
|
4
|
+
import Schematic, {loadSchematic, createSchematic} from "../schematic/Schematic.js";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import pkg from "
|
|
7
|
-
import {DeclaredError} from "
|
|
6
|
+
import pkg from "../../package.json" with { type: "json" };
|
|
7
|
+
import {DeclaredError} from "../utils/js-util.js";
|
|
8
8
|
import fs, {promises as fsp} from "fs";
|
|
9
|
-
|
|
10
|
-
/*todo...
|
|
11
|
-
|
|
12
|
-
defines
|
|
13
|
-
wires*/
|
|
9
|
+
import {compoundSymbol} from "../schematic/CompoundSymbol.js";
|
|
14
10
|
|
|
15
11
|
let HELP_TEXT=`
|
|
16
12
|
Examples:
|
|
@@ -45,6 +41,8 @@ program
|
|
|
45
41
|
.option("-s, --script <script.js>", "Input script to apply to schematic.")
|
|
46
42
|
.option("-e, --emit <script.js>", "Emit script based on schematic.")
|
|
47
43
|
.option("-q, --quiet", "No output, except for errors.")
|
|
44
|
+
.option("-a, --append", "Append mode: don't remove undeclared.")
|
|
45
|
+
.option("--bounding-boxes", "Remove wires and draw bounding boxes instead (only for debug!).")
|
|
48
46
|
//.option("-v, --verbose", "Print detailed execution info")
|
|
49
47
|
.option(
|
|
50
48
|
"-D, --define <key=value>",
|
|
@@ -111,11 +109,29 @@ try {
|
|
|
111
109
|
([e.slice(0,e.indexOf("=")),e.slice(e.indexOf("=")+1)])
|
|
112
110
|
));
|
|
113
111
|
|
|
112
|
+
global.compoundSymbol=compoundSymbol;
|
|
114
113
|
let mod=await import(path.resolve(options.script));
|
|
115
114
|
if (typeof mod.default=="function")
|
|
116
115
|
await mod.default(schematic,defines);
|
|
117
116
|
|
|
118
|
-
|
|
117
|
+
if (!options.append)
|
|
118
|
+
schematic.removeUndeclared();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (options.boundingBoxes) {
|
|
122
|
+
cons.info("Drawing bounding boxes...");
|
|
123
|
+
for (let e of schematic.getEntities({type: "wire"})) {
|
|
124
|
+
schematic.removeEntity(e);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
for (let s of schematic.getEntities({type: "symbol"})) {
|
|
128
|
+
schematic.drawWireRect(s.getBoundingRect());
|
|
129
|
+
for (let p of s.getPins()) {
|
|
130
|
+
schematic.drawWirePoint(p.getPoint());
|
|
131
|
+
schematic.drawWirePoint(p.getLegPoint());
|
|
132
|
+
schematic.drawWireLine(p.getPoint(),p.getLegPoint());
|
|
133
|
+
}
|
|
134
|
+
}
|
|
119
135
|
}
|
|
120
136
|
|
|
121
137
|
if (options.emit) {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export default class CompoundSymbol {
|
|
2
|
+
constructor(...symbols) {
|
|
3
|
+
this.symbols=symbols;
|
|
4
|
+
this.pins=[];
|
|
5
|
+
|
|
6
|
+
for (let symbol of symbols) {
|
|
7
|
+
for (let pin of symbol.pins) {
|
|
8
|
+
//console.log(pin.getNum());
|
|
9
|
+
|
|
10
|
+
this.pins.push(pin);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
pin(num) {
|
|
16
|
+
if (!num)
|
|
17
|
+
throw new Error("Pins start at 1");
|
|
18
|
+
|
|
19
|
+
return this.pins[num-1];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
namePins(names) {
|
|
23
|
+
if (names.length!=this.pins.length)
|
|
24
|
+
throw new Error("pin count mismatch");
|
|
25
|
+
|
|
26
|
+
for (let i=0; i<this.pins.length; i++)
|
|
27
|
+
this[names[i]]=this.pins[i];
|
|
28
|
+
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function compoundSymbol(...args) {
|
|
34
|
+
return new CompoundSymbol(...args);
|
|
35
|
+
}
|
|
@@ -1,31 +1,50 @@
|
|
|
1
|
-
import {Point} from "
|
|
2
|
-
import {sym, symName, sexpCallName} from "
|
|
3
|
-
import {Rect} from "./cartesian-math.js";
|
|
1
|
+
import {Point, Rect} from "../utils/cartesian-math.js";
|
|
2
|
+
import {sym, symName, sexpCallName} from "../utils/sexp.js";
|
|
4
3
|
|
|
5
4
|
class EntityPin {
|
|
6
5
|
constructor(sexpr, entity) {
|
|
7
6
|
this.sexpr=sexpr;
|
|
8
7
|
this.entity=entity;
|
|
9
|
-
|
|
10
|
-
//console.log(this.sexpr);
|
|
11
8
|
}
|
|
12
9
|
|
|
13
10
|
getNum() {
|
|
14
11
|
return this.sexpr[1];
|
|
15
12
|
}
|
|
16
13
|
|
|
17
|
-
|
|
14
|
+
initPoint() {
|
|
18
15
|
let librarySymbol=this.entity.getLibrarySymbol();
|
|
19
16
|
let librarySymbolPin=librarySymbol.getPin(Number(this.getNum()));
|
|
20
17
|
let pinAt=Point.from(librarySymbolPin.at);
|
|
18
|
+
let symbolAt=this.entity.getAt();
|
|
19
|
+
let symbolRot=this.entity.getRotation();
|
|
21
20
|
pinAt[1]=-pinAt[1];
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
//this.point=Point.from(symbolAt).add(pinAt.rotateDegrees(-symbolAt[2]));
|
|
23
|
+
//this.point=Point.from(symbolAt).add(pinAt.rotateDegrees(-this.entity.getRotation()));
|
|
24
|
+
this.point=Point.from(symbolAt).add(pinAt.rotateDegrees(-symbolRot));
|
|
25
|
+
|
|
26
|
+
let leg=new Point(librarySymbolPin.length,0);
|
|
27
|
+
leg=leg.rotateDegrees(-(librarySymbolPin.rotation+symbolRot));
|
|
28
|
+
this.legPoint=this.point.add(leg);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getLegPoint() {
|
|
32
|
+
if (!this.legPoint)
|
|
33
|
+
this.initPoint();
|
|
34
|
+
|
|
35
|
+
return this.legPoint;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
getPoint() {
|
|
39
|
+
if (!this.point)
|
|
40
|
+
this.initPoint();
|
|
41
|
+
|
|
42
|
+
return this.point;
|
|
24
43
|
}
|
|
25
44
|
|
|
26
45
|
isConnected(p) {
|
|
27
46
|
if (typeof p=="string") {
|
|
28
|
-
for (let e of this.entity.schematic.
|
|
47
|
+
for (let e of this.entity.schematic.getEntities({label: p})) {
|
|
29
48
|
let p=e.getConnectionPoints()[0];
|
|
30
49
|
if (this.entity.schematic.arePointsConnected(this.getPoint(),p))
|
|
31
50
|
return true;
|
|
@@ -40,9 +59,12 @@ class EntityPin {
|
|
|
40
59
|
}
|
|
41
60
|
|
|
42
61
|
connect(p) {
|
|
62
|
+
if (!p)
|
|
63
|
+
return;
|
|
64
|
+
|
|
43
65
|
if (this.isConnected(p)) {
|
|
44
66
|
if (typeof p=="string") {
|
|
45
|
-
for (let e of this.entity.schematic.
|
|
67
|
+
for (let e of this.entity.schematic.getEntities({label: p})) {
|
|
46
68
|
let p=e.getConnectionPoints()[0];
|
|
47
69
|
if (this.entity.schematic.arePointsConnected(this.getPoint(),p)) {
|
|
48
70
|
e.declared=true;
|
|
@@ -64,11 +86,16 @@ class EntityPin {
|
|
|
64
86
|
}
|
|
65
87
|
|
|
66
88
|
else {
|
|
89
|
+
//console.log("connecting wire",this.toString(),"->",p.toString());
|
|
67
90
|
this.entity.schematic.addConnectionWire(this.getPoint(),p.getPoint());
|
|
68
91
|
this.entity.schematic.markConnectionDeclared(this.getPoint(),p.getPoint());
|
|
69
92
|
}
|
|
70
93
|
}
|
|
71
94
|
|
|
95
|
+
toString() {
|
|
96
|
+
return this.entity.getReference()+":"+this.getNum();
|
|
97
|
+
}
|
|
98
|
+
|
|
72
99
|
getConnections() {
|
|
73
100
|
let connections=[];
|
|
74
101
|
|
|
@@ -77,7 +104,7 @@ class EntityPin {
|
|
|
77
104
|
connections.push(net);
|
|
78
105
|
}
|
|
79
106
|
|
|
80
|
-
for (let e of this.entity.schematic.
|
|
107
|
+
for (let e of this.entity.schematic.getEntities({type: "symbol"})) {
|
|
81
108
|
if (e==this.entity)
|
|
82
109
|
continue;
|
|
83
110
|
|
|
@@ -97,7 +124,7 @@ export default class Entity {
|
|
|
97
124
|
this.pins=[];
|
|
98
125
|
|
|
99
126
|
this.type=symName(this.sexpr[0]);
|
|
100
|
-
if (!["symbol","wire","label"].includes(this.type))
|
|
127
|
+
if (!["symbol","wire","label","junction"].includes(this.type))
|
|
101
128
|
throw new Error("Unknown entity: "+this.type);
|
|
102
129
|
|
|
103
130
|
for (let a of this.sexpr)
|
|
@@ -105,6 +132,14 @@ export default class Entity {
|
|
|
105
132
|
this.pins.push(new EntityPin(a,this));
|
|
106
133
|
}
|
|
107
134
|
|
|
135
|
+
getRotation() {
|
|
136
|
+
return this.getAt()[2];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
getPins() {
|
|
140
|
+
return this.pins;
|
|
141
|
+
}
|
|
142
|
+
|
|
108
143
|
getSexp() {
|
|
109
144
|
return this.sexpr;
|
|
110
145
|
}
|
|
@@ -178,6 +213,36 @@ export default class Entity {
|
|
|
178
213
|
el[2]=footprint;
|
|
179
214
|
}
|
|
180
215
|
|
|
216
|
+
removeProp(name) {
|
|
217
|
+
if (this.getType()!="symbol")
|
|
218
|
+
throw new Error("Only symbols have props");
|
|
219
|
+
|
|
220
|
+
let index=this.sexpr.findIndex(a=>sexpCallName(a)=="property" && a[1]==name);
|
|
221
|
+
if (index<0)
|
|
222
|
+
return;
|
|
223
|
+
|
|
224
|
+
this.sexpr.splice(index,1);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
setProp(name, value) {
|
|
228
|
+
if (this.getType()!="symbol")
|
|
229
|
+
throw new Error("Only symbols have props");
|
|
230
|
+
|
|
231
|
+
let el=this.sexpr.find(a=>sexpCallName(a)=="property" && a[1]==name);
|
|
232
|
+
if (!el) {
|
|
233
|
+
let exp=[sym("property"),name,"",
|
|
234
|
+
[sym("effects"),
|
|
235
|
+
[sym("hide"),sym("yes")]
|
|
236
|
+
]
|
|
237
|
+
];
|
|
238
|
+
|
|
239
|
+
this.sexpr.push(exp);
|
|
240
|
+
el=exp;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
el[2]=value;
|
|
244
|
+
}
|
|
245
|
+
|
|
181
246
|
getLibId() {
|
|
182
247
|
return this.sexpr.find(x=>sexpCallName(x)=="lib_id")[1];
|
|
183
248
|
}
|
|
@@ -196,12 +261,18 @@ export default class Entity {
|
|
|
196
261
|
}
|
|
197
262
|
|
|
198
263
|
getBoundingRect() {
|
|
264
|
+
if (!this.librarySymbol)
|
|
265
|
+
throw new Error("Can't get bounding rect, no library symbol");
|
|
266
|
+
|
|
199
267
|
//console.log(this.librarySymbol);
|
|
200
268
|
let r=this.librarySymbol.getBoundingRect();
|
|
269
|
+
let corner=r.corner.rotateDegrees(-this.getRotation());
|
|
270
|
+
let size=r.size.rotateDegrees(-this.getRotation());
|
|
271
|
+
|
|
201
272
|
//console.log(r);
|
|
202
273
|
let p=Point.from(this.getAt());
|
|
203
274
|
|
|
204
|
-
return new Rect(p.add(
|
|
275
|
+
return new Rect(p.add(corner),size);
|
|
205
276
|
}
|
|
206
277
|
|
|
207
278
|
getLibrarySymbol() {
|
|
@@ -219,12 +290,6 @@ export default class Entity {
|
|
|
219
290
|
|
|
220
291
|
getType() {
|
|
221
292
|
return this.type;
|
|
222
|
-
/*let t=symName(this.sexpr[0]);
|
|
223
|
-
|
|
224
|
-
if (!["symbol","wire","label"].includes(t))
|
|
225
|
-
throw new Error("Unknown entity: "+t);
|
|
226
|
-
|
|
227
|
-
return t;*/
|
|
228
293
|
}
|
|
229
294
|
|
|
230
295
|
getConnectionPoints() {
|
|
@@ -249,4 +314,43 @@ export default class Entity {
|
|
|
249
314
|
throw new Error("Unknown entity type: "+this.getType());
|
|
250
315
|
}
|
|
251
316
|
}
|
|
317
|
+
|
|
318
|
+
connect(...pins) {
|
|
319
|
+
if (this.getType()!="symbol")
|
|
320
|
+
throw new Error("can only connect sybols");
|
|
321
|
+
|
|
322
|
+
if (pins.length!=this.pins.length)
|
|
323
|
+
throw new Error("pin count mismatch");
|
|
324
|
+
|
|
325
|
+
for (let i=0; i<this.pins.length; i++)
|
|
326
|
+
this.pins[i].connect(pins[i]);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
containsPoint(p) {
|
|
330
|
+
function isNumberInRangeInclusive(num, a, b) {
|
|
331
|
+
return ((num >= Math.min(a, b)) && (num <= Math.max(a, b)));
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (this.getType()!="wire")
|
|
335
|
+
throw new Error("Only a wire can contain points");
|
|
336
|
+
|
|
337
|
+
p=Point.from(p);
|
|
338
|
+
let cp=this.getConnectionPoints();
|
|
339
|
+
if (cp[0][0]==cp[1][0]) { // vertical
|
|
340
|
+
if (p[0]!=cp[0][0])
|
|
341
|
+
return false;
|
|
342
|
+
|
|
343
|
+
return isNumberInRangeInclusive(p[1],cp[0][1],cp[1][1]);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
else if (cp[0][1]==cp[1][1]) { // horizontal
|
|
347
|
+
if (p[1]!=cp[0][1])
|
|
348
|
+
return false;
|
|
349
|
+
|
|
350
|
+
return isNumberInRangeInclusive(p[0],cp[0][0],cp[1][0]);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
else
|
|
354
|
+
throw new Error("wire is not horizontal or vertical");
|
|
355
|
+
}
|
|
252
356
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {sym, isSym, symEq, symName, sexpStringify, sexpCallName} from "
|
|
2
|
-
import {Rect} from "
|
|
1
|
+
import {sym, isSym, symEq, symName, sexpStringify, sexpCallName} from "../utils/sexp.js";
|
|
2
|
+
import {Rect} from "../utils/cartesian-math.js";
|
|
3
3
|
|
|
4
4
|
export default class LibrarySymbol {
|
|
5
5
|
constructor(sexpr, qualifiedName) {
|
|
@@ -61,6 +61,13 @@ export default class LibrarySymbol {
|
|
|
61
61
|
if (sexpCallName(x)=="rectangle") {
|
|
62
62
|
let start=x.find(x=>sexpCallName(x)=="start").slice(1);
|
|
63
63
|
let end=x.find(x=>sexpCallName(x)=="end").slice(1);
|
|
64
|
+
|
|
65
|
+
start[1]=-start[1];
|
|
66
|
+
end[1]=-end[1];
|
|
67
|
+
|
|
68
|
+
/*console.log(start);
|
|
69
|
+
console.log(end);*/
|
|
70
|
+
|
|
64
71
|
let r=Rect.fromCorners(start,end);
|
|
65
72
|
|
|
66
73
|
if (!rect)
|
|
@@ -68,6 +75,32 @@ export default class LibrarySymbol {
|
|
|
68
75
|
|
|
69
76
|
rect=rect.union(r);
|
|
70
77
|
}
|
|
78
|
+
|
|
79
|
+
if (sexpCallName(x)=="polyline") {
|
|
80
|
+
//console.log("poly line...");
|
|
81
|
+
for (let sub of x) {
|
|
82
|
+
if (sexpCallName(sub)=="pts") {
|
|
83
|
+
for (let p of sub) {
|
|
84
|
+
if (sexpCallName(p)=="xy") {
|
|
85
|
+
let point=[p[1],p[2]];
|
|
86
|
+
|
|
87
|
+
if (!rect)
|
|
88
|
+
rect=new Rect(point,[0,0]);
|
|
89
|
+
|
|
90
|
+
//console.log("rect",rect);
|
|
91
|
+
//console.log("point",point);
|
|
92
|
+
|
|
93
|
+
rect=rect.includePoint(point);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!rect) {
|
|
102
|
+
//console.log(symbolExp);
|
|
103
|
+
throw new Error("Symbol doesn't have any rect!");
|
|
71
104
|
}
|
|
72
105
|
|
|
73
106
|
//console.log(sexpStringify(symbolExp));
|
|
@@ -93,7 +126,9 @@ export class LibrarySymbolPin {
|
|
|
93
126
|
|
|
94
127
|
switch (symName(e[0])) {
|
|
95
128
|
case "at":
|
|
129
|
+
//console.log(e);
|
|
96
130
|
this.at = e.slice(1).map(Number); // [x, y, rotation]
|
|
131
|
+
this.rotation=Number(e[3]);
|
|
97
132
|
break;
|
|
98
133
|
case "length":
|
|
99
134
|
this.length = Number(e[1]);
|