kisch 1.0.3 → 1.0.5
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 +36 -0
- package/src/{Entity.js → schematic/Entity.js} +149 -19
- package/src/{LibrarySymbol.js → schematic/LibrarySymbol.js} +37 -2
- package/src/{Schematic.js → schematic/Schematic.js} +210 -81
- 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.5",
|
|
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,36 @@
|
|
|
1
|
+
export default class CompoundSymbol {
|
|
2
|
+
constructor(...symbols) {
|
|
3
|
+
this.symbols=symbols;
|
|
4
|
+
this.pins=[];
|
|
5
|
+
|
|
6
|
+
for (let symbol of symbols) {
|
|
7
|
+
let pinNums=symbol.getPinNums();
|
|
8
|
+
pinNums.sort();
|
|
9
|
+
|
|
10
|
+
for (let pinNum of pinNums) {
|
|
11
|
+
this.pins.push(symbol.pin(pinNum));
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
pin(num) {
|
|
17
|
+
if (!num)
|
|
18
|
+
throw new Error("Pins start at 1");
|
|
19
|
+
|
|
20
|
+
return this.pins[num-1];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
namePins(names) {
|
|
24
|
+
if (names.length!=this.pins.length)
|
|
25
|
+
throw new Error("pin count mismatch");
|
|
26
|
+
|
|
27
|
+
for (let i=0; i<this.pins.length; i++)
|
|
28
|
+
this[names[i]]=this.pins[i];
|
|
29
|
+
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function compoundSymbol(...args) {
|
|
35
|
+
return new CompoundSymbol(...args);
|
|
36
|
+
}
|
|
@@ -1,31 +1,60 @@
|
|
|
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
8
|
|
|
10
|
-
//console.log(this.sexpr);
|
|
9
|
+
//console.log("ctor pin num: "+this.sexpr[1]);
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
getNum() {
|
|
13
|
+
//console.log("pin num: "+this.sexpr[1]);
|
|
14
|
+
|
|
14
15
|
return this.sexpr[1];
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
initPoint() {
|
|
18
19
|
let librarySymbol=this.entity.getLibrarySymbol();
|
|
19
|
-
let librarySymbolPin
|
|
20
|
+
let librarySymbolPin;
|
|
21
|
+
if (isNaN(this.getNum()))
|
|
22
|
+
librarySymbolPin=librarySymbol.getPin(this.getNum());
|
|
23
|
+
|
|
24
|
+
else
|
|
25
|
+
librarySymbolPin=librarySymbol.getPin(Number(this.getNum()));
|
|
26
|
+
|
|
20
27
|
let pinAt=Point.from(librarySymbolPin.at);
|
|
28
|
+
let symbolAt=this.entity.getAt();
|
|
29
|
+
let symbolRot=this.entity.getRotation();
|
|
21
30
|
pinAt[1]=-pinAt[1];
|
|
22
31
|
|
|
23
|
-
|
|
32
|
+
//this.point=Point.from(symbolAt).add(pinAt.rotateDegrees(-symbolAt[2]));
|
|
33
|
+
//this.point=Point.from(symbolAt).add(pinAt.rotateDegrees(-this.entity.getRotation()));
|
|
34
|
+
this.point=Point.from(symbolAt).add(pinAt.rotateDegrees(-symbolRot));
|
|
35
|
+
|
|
36
|
+
let leg=new Point(librarySymbolPin.length,0);
|
|
37
|
+
leg=leg.rotateDegrees(-(librarySymbolPin.rotation+symbolRot));
|
|
38
|
+
this.legPoint=this.point.add(leg);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getLegPoint() {
|
|
42
|
+
if (!this.legPoint)
|
|
43
|
+
this.initPoint();
|
|
44
|
+
|
|
45
|
+
return this.legPoint;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getPoint() {
|
|
49
|
+
if (!this.point)
|
|
50
|
+
this.initPoint();
|
|
51
|
+
|
|
52
|
+
return this.point;
|
|
24
53
|
}
|
|
25
54
|
|
|
26
55
|
isConnected(p) {
|
|
27
56
|
if (typeof p=="string") {
|
|
28
|
-
for (let e of this.entity.schematic.
|
|
57
|
+
for (let e of this.entity.schematic.getEntities({label: p})) {
|
|
29
58
|
let p=e.getConnectionPoints()[0];
|
|
30
59
|
if (this.entity.schematic.arePointsConnected(this.getPoint(),p))
|
|
31
60
|
return true;
|
|
@@ -40,9 +69,12 @@ class EntityPin {
|
|
|
40
69
|
}
|
|
41
70
|
|
|
42
71
|
connect(p) {
|
|
72
|
+
if (!p)
|
|
73
|
+
return;
|
|
74
|
+
|
|
43
75
|
if (this.isConnected(p)) {
|
|
44
76
|
if (typeof p=="string") {
|
|
45
|
-
for (let e of this.entity.schematic.
|
|
77
|
+
for (let e of this.entity.schematic.getEntities({label: p})) {
|
|
46
78
|
let p=e.getConnectionPoints()[0];
|
|
47
79
|
if (this.entity.schematic.arePointsConnected(this.getPoint(),p)) {
|
|
48
80
|
e.declared=true;
|
|
@@ -64,11 +96,16 @@ class EntityPin {
|
|
|
64
96
|
}
|
|
65
97
|
|
|
66
98
|
else {
|
|
99
|
+
//console.log("connecting wire",this.toString(),"->",p.toString());
|
|
67
100
|
this.entity.schematic.addConnectionWire(this.getPoint(),p.getPoint());
|
|
68
101
|
this.entity.schematic.markConnectionDeclared(this.getPoint(),p.getPoint());
|
|
69
102
|
}
|
|
70
103
|
}
|
|
71
104
|
|
|
105
|
+
toString() {
|
|
106
|
+
return this.entity.getReference()+":"+this.getNum();
|
|
107
|
+
}
|
|
108
|
+
|
|
72
109
|
getConnections() {
|
|
73
110
|
let connections=[];
|
|
74
111
|
|
|
@@ -77,7 +114,7 @@ class EntityPin {
|
|
|
77
114
|
connections.push(net);
|
|
78
115
|
}
|
|
79
116
|
|
|
80
|
-
for (let e of this.entity.schematic.
|
|
117
|
+
for (let e of this.entity.schematic.getEntities({type: "symbol"})) {
|
|
81
118
|
if (e==this.entity)
|
|
82
119
|
continue;
|
|
83
120
|
|
|
@@ -97,7 +134,7 @@ export default class Entity {
|
|
|
97
134
|
this.pins=[];
|
|
98
135
|
|
|
99
136
|
this.type=symName(this.sexpr[0]);
|
|
100
|
-
if (!["symbol","wire","label"].includes(this.type))
|
|
137
|
+
if (!["symbol","wire","label","junction"].includes(this.type))
|
|
101
138
|
throw new Error("Unknown entity: "+this.type);
|
|
102
139
|
|
|
103
140
|
for (let a of this.sexpr)
|
|
@@ -105,6 +142,14 @@ export default class Entity {
|
|
|
105
142
|
this.pins.push(new EntityPin(a,this));
|
|
106
143
|
}
|
|
107
144
|
|
|
145
|
+
getRotation() {
|
|
146
|
+
return this.getAt()[2];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
getPins() {
|
|
150
|
+
return this.pins;
|
|
151
|
+
}
|
|
152
|
+
|
|
108
153
|
getSexp() {
|
|
109
154
|
return this.sexpr;
|
|
110
155
|
}
|
|
@@ -178,6 +223,36 @@ export default class Entity {
|
|
|
178
223
|
el[2]=footprint;
|
|
179
224
|
}
|
|
180
225
|
|
|
226
|
+
removeProp(name) {
|
|
227
|
+
if (this.getType()!="symbol")
|
|
228
|
+
throw new Error("Only symbols have props");
|
|
229
|
+
|
|
230
|
+
let index=this.sexpr.findIndex(a=>sexpCallName(a)=="property" && a[1]==name);
|
|
231
|
+
if (index<0)
|
|
232
|
+
return;
|
|
233
|
+
|
|
234
|
+
this.sexpr.splice(index,1);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
setProp(name, value) {
|
|
238
|
+
if (this.getType()!="symbol")
|
|
239
|
+
throw new Error("Only symbols have props");
|
|
240
|
+
|
|
241
|
+
let el=this.sexpr.find(a=>sexpCallName(a)=="property" && a[1]==name);
|
|
242
|
+
if (!el) {
|
|
243
|
+
let exp=[sym("property"),name,"",
|
|
244
|
+
[sym("effects"),
|
|
245
|
+
[sym("hide"),sym("yes")]
|
|
246
|
+
]
|
|
247
|
+
];
|
|
248
|
+
|
|
249
|
+
this.sexpr.push(exp);
|
|
250
|
+
el=exp;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
el[2]=value;
|
|
254
|
+
}
|
|
255
|
+
|
|
181
256
|
getLibId() {
|
|
182
257
|
return this.sexpr.find(x=>sexpCallName(x)=="lib_id")[1];
|
|
183
258
|
}
|
|
@@ -196,12 +271,18 @@ export default class Entity {
|
|
|
196
271
|
}
|
|
197
272
|
|
|
198
273
|
getBoundingRect() {
|
|
274
|
+
if (!this.librarySymbol)
|
|
275
|
+
throw new Error("Can't get bounding rect, no library symbol");
|
|
276
|
+
|
|
199
277
|
//console.log(this.librarySymbol);
|
|
200
278
|
let r=this.librarySymbol.getBoundingRect();
|
|
279
|
+
let corner=r.corner.rotateDegrees(-this.getRotation());
|
|
280
|
+
let size=r.size.rotateDegrees(-this.getRotation());
|
|
281
|
+
|
|
201
282
|
//console.log(r);
|
|
202
283
|
let p=Point.from(this.getAt());
|
|
203
284
|
|
|
204
|
-
return new Rect(p.add(
|
|
285
|
+
return new Rect(p.add(corner),size);
|
|
205
286
|
}
|
|
206
287
|
|
|
207
288
|
getLibrarySymbol() {
|
|
@@ -212,19 +293,26 @@ export default class Entity {
|
|
|
212
293
|
if (!num)
|
|
213
294
|
throw new Error("Pin numbers start at 1");
|
|
214
295
|
|
|
215
|
-
for (let p of this.pins)
|
|
296
|
+
for (let p of this.pins) {
|
|
297
|
+
//console.log("pin num: "+p.getNum());
|
|
298
|
+
|
|
216
299
|
if (p.getNum()==num)
|
|
217
300
|
return p;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
throw new Error("Can't find pin: "+num);
|
|
218
304
|
}
|
|
219
305
|
|
|
220
306
|
getType() {
|
|
221
307
|
return this.type;
|
|
222
|
-
|
|
308
|
+
}
|
|
223
309
|
|
|
224
|
-
|
|
225
|
-
|
|
310
|
+
getPinNums() {
|
|
311
|
+
let nums=[];
|
|
312
|
+
for (let p of this.pins)
|
|
313
|
+
nums.push(p.getNum())
|
|
226
314
|
|
|
227
|
-
return
|
|
315
|
+
return nums;
|
|
228
316
|
}
|
|
229
317
|
|
|
230
318
|
getConnectionPoints() {
|
|
@@ -239,8 +327,11 @@ export default class Entity {
|
|
|
239
327
|
|
|
240
328
|
case "symbol":
|
|
241
329
|
let p=[];
|
|
242
|
-
for (let
|
|
243
|
-
p.push(this.pin(
|
|
330
|
+
for (let num of this.getPinNums())
|
|
331
|
+
p.push(this.pin(num).getPoint());
|
|
332
|
+
|
|
333
|
+
/*for (let i=1; i<=this.pins.length; i++)
|
|
334
|
+
p.push(this.pin(i).getPoint());*/
|
|
244
335
|
|
|
245
336
|
return p;
|
|
246
337
|
break;
|
|
@@ -249,4 +340,43 @@ export default class Entity {
|
|
|
249
340
|
throw new Error("Unknown entity type: "+this.getType());
|
|
250
341
|
}
|
|
251
342
|
}
|
|
343
|
+
|
|
344
|
+
connect(...pins) {
|
|
345
|
+
if (this.getType()!="symbol")
|
|
346
|
+
throw new Error("can only connect symbols");
|
|
347
|
+
|
|
348
|
+
if (pins.length!=this.pins.length)
|
|
349
|
+
throw new Error("pin count mismatch");
|
|
350
|
+
|
|
351
|
+
for (let i=0; i<this.pins.length; i++)
|
|
352
|
+
this.pins[i].connect(pins[i]);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
containsPoint(p) {
|
|
356
|
+
function isNumberInRangeInclusive(num, a, b) {
|
|
357
|
+
return ((num >= Math.min(a, b)) && (num <= Math.max(a, b)));
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (this.getType()!="wire")
|
|
361
|
+
throw new Error("Only a wire can contain points");
|
|
362
|
+
|
|
363
|
+
p=Point.from(p);
|
|
364
|
+
let cp=this.getConnectionPoints();
|
|
365
|
+
if (cp[0][0]==cp[1][0]) { // vertical
|
|
366
|
+
if (p[0]!=cp[0][0])
|
|
367
|
+
return false;
|
|
368
|
+
|
|
369
|
+
return isNumberInRangeInclusive(p[1],cp[0][1],cp[1][1]);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
else if (cp[0][1]==cp[1][1]) { // horizontal
|
|
373
|
+
if (p[1]!=cp[0][1])
|
|
374
|
+
return false;
|
|
375
|
+
|
|
376
|
+
return isNumberInRangeInclusive(p[0],cp[0][0],cp[1][0]);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
else
|
|
380
|
+
throw new Error("wire is not horizontal or vertical");
|
|
381
|
+
}
|
|
252
382
|
}
|
|
@@ -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]);
|