circuitscript 0.1.23 → 0.1.24
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/dist/cjs/BaseVisitor.js +35 -23
- package/dist/cjs/BomGeneration.js +167 -0
- package/dist/cjs/ComponentMatchConditions.js +116 -0
- package/dist/cjs/antlr/CircuitScriptLexer.js +247 -244
- package/dist/cjs/antlr/CircuitScriptParser.js +1476 -825
- package/dist/cjs/builtinMethods.js +6 -1
- package/dist/cjs/execute.js +27 -16
- package/dist/cjs/graph.js +10 -9
- package/dist/cjs/helpers.js +23 -4
- package/dist/cjs/layout.js +14 -13
- package/dist/cjs/main.js +17 -1
- package/dist/cjs/objects/ExecutionScope.js +3 -0
- package/dist/cjs/objects/PinDefinition.js +11 -1
- package/dist/cjs/objects/types.js +6 -4
- package/dist/cjs/rules-check/no-connect-on-connected-pin.js +81 -0
- package/dist/cjs/rules-check/rules.js +74 -0
- package/dist/cjs/rules-check/unconnected-pins.js +52 -0
- package/dist/cjs/visitor.js +121 -5
- package/dist/esm/BaseVisitor.js +35 -23
- package/dist/esm/BomGeneration.js +137 -0
- package/dist/esm/ComponentMatchConditions.js +109 -0
- package/dist/esm/antlr/CircuitScriptLexer.js +247 -244
- package/dist/esm/antlr/CircuitScriptParser.js +1471 -824
- package/dist/esm/antlr/CircuitScriptVisitor.js +7 -0
- package/dist/esm/builtinMethods.js +6 -1
- package/dist/esm/execute.js +27 -16
- package/dist/esm/graph.js +11 -10
- package/dist/esm/helpers.js +23 -4
- package/dist/esm/layout.js +15 -13
- package/dist/esm/main.js +17 -1
- package/dist/esm/objects/ExecutionScope.js +3 -0
- package/dist/esm/objects/PinDefinition.js +11 -1
- package/dist/esm/objects/types.js +7 -5
- package/dist/esm/rules-check/no-connect-on-connected-pin.js +77 -0
- package/dist/esm/rules-check/rules.js +70 -0
- package/dist/esm/rules-check/unconnected-pins.js +48 -0
- package/dist/esm/visitor.js +121 -5
- package/dist/libs/std.cst +7 -3
- package/dist/types/BomGeneration.d.ts +13 -0
- package/dist/types/ComponentMatchConditions.d.ts +19 -0
- package/dist/types/antlr/CircuitScriptLexer.d.ts +60 -59
- package/dist/types/antlr/CircuitScriptParser.d.ts +146 -62
- package/dist/types/antlr/CircuitScriptVisitor.d.ts +14 -0
- package/dist/types/execute.d.ts +2 -1
- package/dist/types/graph.d.ts +6 -1
- package/dist/types/helpers.d.ts +3 -0
- package/dist/types/layout.d.ts +3 -2
- package/dist/types/objects/ExecutionScope.d.ts +8 -2
- package/dist/types/objects/ParamDefinition.d.ts +1 -1
- package/dist/types/objects/PinDefinition.d.ts +1 -0
- package/dist/types/objects/types.d.ts +4 -2
- package/dist/types/rules-check/no-connect-on-connected-pin.d.ts +3 -0
- package/dist/types/rules-check/rules.d.ts +15 -0
- package/dist/types/rules-check/unconnected-pins.d.ts +2 -0
- package/dist/types/visitor.d.ts +10 -1
- package/libs/std.cst +7 -3
- package/package.json +2 -1
|
@@ -79,5 +79,12 @@ export class CircuitScriptVisitor extends AbstractParseTreeVisitor {
|
|
|
79
79
|
visitElse_expr;
|
|
80
80
|
visitWhile_expr;
|
|
81
81
|
visitFor_expr;
|
|
82
|
+
visitPart_set_expr;
|
|
83
|
+
visitPart_set_key;
|
|
84
|
+
visitPart_match_block;
|
|
85
|
+
visitPart_sub_expr;
|
|
86
|
+
visitPart_condition_expr;
|
|
87
|
+
visitPart_condition_key_only_expr;
|
|
88
|
+
visitPart_value_expr;
|
|
82
89
|
visitAnnotation_comment_expr;
|
|
83
90
|
}
|
|
@@ -159,7 +159,12 @@ function toString(obj) {
|
|
|
159
159
|
return obj.toDisplayString();
|
|
160
160
|
}
|
|
161
161
|
else if (obj.toString) {
|
|
162
|
-
|
|
162
|
+
if (typeof obj === 'object') {
|
|
163
|
+
return JSON.stringify(obj);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
return obj.toString();
|
|
167
|
+
}
|
|
163
168
|
}
|
|
164
169
|
else {
|
|
165
170
|
throw "Could not create string from object: " + obj;
|
package/dist/esm/execute.js
CHANGED
|
@@ -378,9 +378,9 @@ export class ExecutionContext {
|
|
|
378
378
|
+ pinId + ' in ' + component);
|
|
379
379
|
}
|
|
380
380
|
this.scope.setCurrent(component, usePinId);
|
|
381
|
-
if (!this.scope.hasNet(component,
|
|
381
|
+
if (!this.scope.hasNet(component, usePinId)) {
|
|
382
382
|
const tmpNet = new Net(this.netNamespace, this.getUniqueNetName());
|
|
383
|
-
this.scope.setNet(component,
|
|
383
|
+
this.scope.setNet(component, usePinId, tmpNet);
|
|
384
384
|
}
|
|
385
385
|
this.scope.clearActive();
|
|
386
386
|
if (addSequence) {
|
|
@@ -502,7 +502,9 @@ export class ExecutionContext {
|
|
|
502
502
|
const { start_point: [component, pin, wireId] } = stackRef;
|
|
503
503
|
this.atComponent(component, pin, { addSequence: true });
|
|
504
504
|
if (wireId !== -1) {
|
|
505
|
-
this.scope.
|
|
505
|
+
const wireObject = this.scope.wires[wireId];
|
|
506
|
+
this.scope.sequence.push([SequenceAction.WireJump,
|
|
507
|
+
wireId, PinId.from(1), wireObject]);
|
|
506
508
|
}
|
|
507
509
|
}
|
|
508
510
|
else if (blockType === BlockTypes.Join || blockType === BlockTypes.Parallel) {
|
|
@@ -628,7 +630,7 @@ export class ExecutionContext {
|
|
|
628
630
|
type: isVariable ? ReferenceTypes.variable
|
|
629
631
|
: ReferenceTypes.instance,
|
|
630
632
|
found: (tmpReference.value !== undefined),
|
|
631
|
-
|
|
633
|
+
rootValue: tmpReference.rootValue,
|
|
632
634
|
value: tmpReference.value,
|
|
633
635
|
name: idName,
|
|
634
636
|
trailers,
|
|
@@ -642,16 +644,19 @@ export class ExecutionContext {
|
|
|
642
644
|
});
|
|
643
645
|
}
|
|
644
646
|
resolveTrailers(type, item, trailers = []) {
|
|
645
|
-
let
|
|
647
|
+
let rootValue;
|
|
646
648
|
let useValue = item;
|
|
647
649
|
if (trailers.length > 0) {
|
|
648
|
-
|
|
650
|
+
rootValue = useValue;
|
|
649
651
|
const trailersPath = trailers.join(".");
|
|
650
652
|
if (type === ReferenceTypes.variable) {
|
|
651
|
-
useValue =
|
|
653
|
+
useValue = rootValue;
|
|
654
|
+
trailers.forEach(trailerPath => {
|
|
655
|
+
useValue = useValue[trailerPath];
|
|
656
|
+
});
|
|
652
657
|
}
|
|
653
658
|
else if (type === ReferenceTypes.instance) {
|
|
654
|
-
const tmpComponent =
|
|
659
|
+
const tmpComponent = rootValue;
|
|
655
660
|
if (tmpComponent.typeProp === ComponentTypes.net) {
|
|
656
661
|
const usedNet = this.scope.getNet(tmpComponent, new PinId(1));
|
|
657
662
|
if (usedNet) {
|
|
@@ -660,20 +665,21 @@ export class ExecutionContext {
|
|
|
660
665
|
}
|
|
661
666
|
}
|
|
662
667
|
else {
|
|
663
|
-
useValue =
|
|
668
|
+
useValue = rootValue
|
|
664
669
|
.parameters.get(trailersPath);
|
|
665
670
|
}
|
|
666
671
|
}
|
|
667
672
|
}
|
|
668
673
|
let found = false;
|
|
669
|
-
if (
|
|
674
|
+
if (rootValue !== undefined && useValue !== undefined) {
|
|
670
675
|
found = true;
|
|
671
676
|
}
|
|
672
677
|
return new AnyReference({
|
|
673
678
|
found,
|
|
674
679
|
type: type,
|
|
675
|
-
|
|
680
|
+
rootValue,
|
|
676
681
|
trailers,
|
|
682
|
+
trailerIndex: trailers.length,
|
|
677
683
|
value: useValue,
|
|
678
684
|
});
|
|
679
685
|
}
|
|
@@ -774,13 +780,16 @@ export class ExecutionContext {
|
|
|
774
780
|
childScope.sequence.forEach(sequenceAction => {
|
|
775
781
|
const [action] = sequenceAction;
|
|
776
782
|
if (action === SequenceAction.Wire) {
|
|
777
|
-
const [, innerWireId, segments] = sequenceAction;
|
|
778
|
-
this.scope.sequence.push([SequenceAction.Wire, wireIdOffset + innerWireId,
|
|
783
|
+
const [, innerWireId, segments, wire] = sequenceAction;
|
|
784
|
+
this.scope.sequence.push([SequenceAction.Wire, wireIdOffset + innerWireId,
|
|
785
|
+
segments, wire]);
|
|
779
786
|
this.scope.wires.push(new Wire(segments));
|
|
780
787
|
}
|
|
781
788
|
else if (action === SequenceAction.WireJump) {
|
|
782
789
|
const jumpWireId = wireIdOffset + sequenceAction[1];
|
|
783
|
-
this.scope.
|
|
790
|
+
const wireObject = this.scope.wires[jumpWireId];
|
|
791
|
+
this.scope.sequence.push([SequenceAction.WireJump, jumpWireId,
|
|
792
|
+
PinId.from(1), wireObject]);
|
|
784
793
|
}
|
|
785
794
|
else if (action === SequenceAction.At || action === SequenceAction.To) {
|
|
786
795
|
this.scope.sequence.push(sequenceAction);
|
|
@@ -828,7 +837,8 @@ export class ExecutionContext {
|
|
|
828
837
|
};
|
|
829
838
|
});
|
|
830
839
|
const wireId = this.scope.wires.length;
|
|
831
|
-
|
|
840
|
+
const newWire = new Wire(tmp);
|
|
841
|
+
this.scope.wires.push(newWire);
|
|
832
842
|
const output = [];
|
|
833
843
|
segments.forEach(item => {
|
|
834
844
|
const tmpArray = item.map(item2 => {
|
|
@@ -843,12 +853,13 @@ export class ExecutionContext {
|
|
|
843
853
|
});
|
|
844
854
|
this.log('add wire: ', output.join("|"));
|
|
845
855
|
this.scope.setActive(ActiveObject.Wire, wireId);
|
|
846
|
-
this.scope.sequence.push([SequenceAction.Wire, wireId, tmp]);
|
|
856
|
+
this.scope.sequence.push([SequenceAction.Wire, wireId, tmp, newWire]);
|
|
847
857
|
this.scope.currentComponent.pinWires.set(this.scope.currentPin, tmp);
|
|
848
858
|
if (!this.scope.currentComponent.didSetWireOrientationAngle) {
|
|
849
859
|
this.applyComponentAngleFromWire(this.scope.currentComponent, this.scope.currentPin, true);
|
|
850
860
|
this.scope.currentComponent.didSetWireOrientationAngle = true;
|
|
851
861
|
}
|
|
862
|
+
return newWire;
|
|
852
863
|
}
|
|
853
864
|
addPoint(pointId, userDefined = true) {
|
|
854
865
|
if (this.scope.instances.has(pointId)) {
|
package/dist/esm/graph.js
CHANGED
|
@@ -8,7 +8,7 @@ import { Frame, FixedFrameIds, FrameParamKeys } from "./objects/Frame.js";
|
|
|
8
8
|
import { numeric } from "./objects/ParamDefinition.js";
|
|
9
9
|
import { NetTypes, TypeProps } from "./objects/types.js";
|
|
10
10
|
import Matrix, { solve } from "ml-matrix";
|
|
11
|
-
import { getPinDefinition } from "./objects/PinDefinition.js";
|
|
11
|
+
import { getPinDefinition, PinId } from "./objects/PinDefinition.js";
|
|
12
12
|
export class NetGraph {
|
|
13
13
|
logger;
|
|
14
14
|
constructor(logger) {
|
|
@@ -81,8 +81,9 @@ export class NetGraph {
|
|
|
81
81
|
break;
|
|
82
82
|
}
|
|
83
83
|
case SequenceAction.Wire: {
|
|
84
|
-
const [, wireId,
|
|
84
|
+
const [, wireId, , wire] = sequenceStep;
|
|
85
85
|
let useNet;
|
|
86
|
+
const wireSegments = wire.path;
|
|
86
87
|
if (previousNode !== null) {
|
|
87
88
|
const [prevNodeType, prevNodeItem] = graph.node(previousNode);
|
|
88
89
|
if (prevNodeType === RenderItemType.Component) {
|
|
@@ -98,15 +99,15 @@ export class NetGraph {
|
|
|
98
99
|
useNet = prevNodeItem.net;
|
|
99
100
|
}
|
|
100
101
|
}
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const wireName = getWireName(
|
|
105
|
-
graph.setNode(wireName, [RenderItemType.Wire,
|
|
102
|
+
const renderWire = new RenderWire(useNet, numeric(0), numeric(0), wireSegments, wire);
|
|
103
|
+
renderWire.id = wireId;
|
|
104
|
+
renderWire.netName = useNet.toString();
|
|
105
|
+
const wireName = getWireName(renderWire.id);
|
|
106
|
+
graph.setNode(wireName, [RenderItemType.Wire, renderWire, index]);
|
|
106
107
|
let tmpPreviousNode = previousNode;
|
|
107
|
-
this.setGraphEdge(graph, previousNode, wireName, makeEdgeValue(previousNode, previousPin, wireName, 0, index));
|
|
108
|
+
this.setGraphEdge(graph, previousNode, wireName, makeEdgeValue(previousNode, previousPin, wireName, PinId.from(0), index));
|
|
108
109
|
previousNode = wireName;
|
|
109
|
-
previousPin = 1;
|
|
110
|
+
previousPin = PinId.from(1);
|
|
110
111
|
const wireSegmentsInfo = wireSegments.map(item => {
|
|
111
112
|
const tmp = {
|
|
112
113
|
direction: item.direction,
|
|
@@ -140,7 +141,7 @@ export class NetGraph {
|
|
|
140
141
|
wirePin = sequenceStep[2];
|
|
141
142
|
}
|
|
142
143
|
previousNode = wireName;
|
|
143
|
-
previousPin = wirePin;
|
|
144
|
+
previousPin = PinId.from(wirePin);
|
|
144
145
|
break;
|
|
145
146
|
}
|
|
146
147
|
case SequenceAction.Frame: {
|
package/dist/esm/helpers.js
CHANGED
|
@@ -19,6 +19,8 @@ import Big from "big.js";
|
|
|
19
19
|
import { Logger } from "./logger.js";
|
|
20
20
|
import { NetGraph } from "./graph.js";
|
|
21
21
|
import { RefdesAnnotationVisitor } from "./RefdesAnnotationVisitor.js";
|
|
22
|
+
import { EvaluateERCRules } from "./rules-check/rules.js";
|
|
23
|
+
import { generateBom, generateBomCSV, saveBomOutputCsv } from "./BomGeneration.js";
|
|
22
24
|
export var JSModuleType;
|
|
23
25
|
(function (JSModuleType) {
|
|
24
26
|
JSModuleType["CommonJs"] = "cjs";
|
|
@@ -155,7 +157,7 @@ export async function renderScript(scriptData, outputPath, options) {
|
|
|
155
157
|
return renderScriptCustom(scriptData, outputPath, options, parseHandlers);
|
|
156
158
|
}
|
|
157
159
|
export async function renderScriptCustom(scriptData, outputPath, options, parseHandlers) {
|
|
158
|
-
const { dumpNets = false, dumpData = false, showStats = false, environment, inputPath = null, updateSource = false, saveAnnotatedCopy = undefined, } = options;
|
|
160
|
+
const { dumpNets = false, dumpData = false, showStats = false, enableErc = false, enableBom = false, bomOutputPath = undefined, environment, inputPath = null, updateSource = false, saveAnnotatedCopy = undefined, } = options;
|
|
159
161
|
const errors = [];
|
|
160
162
|
const onErrorHandler = (message, context, error) => {
|
|
161
163
|
if (error && error instanceof RuntimeExecutionError) {
|
|
@@ -209,10 +211,10 @@ export async function renderScriptCustom(scriptData, outputPath, options, parseH
|
|
|
209
211
|
catch (err) {
|
|
210
212
|
throw new RenderError(`Error during component annotation: ${err}`, 'annotation');
|
|
211
213
|
}
|
|
212
|
-
const componentLinks = visitor.getComponentCtxLinks();
|
|
213
|
-
const refdesVisitor = new RefdesAnnotationVisitor(true, scriptData, tokens, componentLinks);
|
|
214
|
-
await refdesVisitor.visitAsync(tree);
|
|
215
214
|
if (inputPath && (updateSource || saveAnnotatedCopy !== undefined)) {
|
|
215
|
+
const componentLinks = visitor.getComponentCtxLinks();
|
|
216
|
+
const refdesVisitor = new RefdesAnnotationVisitor(true, scriptData, tokens, componentLinks);
|
|
217
|
+
await refdesVisitor.visitAsync(tree);
|
|
216
218
|
let usePath = inputPath;
|
|
217
219
|
if (saveAnnotatedCopy === true) {
|
|
218
220
|
const dir = path.dirname(inputPath);
|
|
@@ -239,6 +241,14 @@ export async function renderScriptCustom(scriptData, outputPath, options, parseH
|
|
|
239
241
|
if (errors.length === 0) {
|
|
240
242
|
const { frameComponent } = visitor.applySheetFrameComponent();
|
|
241
243
|
const { sequence, nets } = visitor.getGraph();
|
|
244
|
+
if (enableBom && bomOutputPath) {
|
|
245
|
+
const documentVariable = visitor.getScope().variables.get('document');
|
|
246
|
+
const bomConfig = documentVariable.bom;
|
|
247
|
+
const bomData = generateBom(bomConfig, visitor.getScope().getInstances());
|
|
248
|
+
const bomCsvOutput = generateBomCSV(bomData);
|
|
249
|
+
await saveBomOutputCsv(bomCsvOutput, bomOutputPath);
|
|
250
|
+
console.log('Generated BOM file', bomOutputPath);
|
|
251
|
+
}
|
|
242
252
|
const tmpSequence = generateDebugSequenceAction(sequence).map(item => sequenceActionString(item));
|
|
243
253
|
dumpData && writeFileSync(dumpDirectory + 'raw-sequence.txt', tmpSequence.join('\n'));
|
|
244
254
|
try {
|
|
@@ -267,6 +277,15 @@ export async function renderScriptCustom(scriptData, outputPath, options, parseH
|
|
|
267
277
|
try {
|
|
268
278
|
const { graph, containerFrames } = graphEngine.generateLayoutGraph(sequence, nets);
|
|
269
279
|
sheetFrames = layoutEngine.runLayout(graph, containerFrames, nets);
|
|
280
|
+
if (enableErc) {
|
|
281
|
+
const ercResults = EvaluateERCRules(visitor, graph, nets);
|
|
282
|
+
if (ercResults.length > 0) {
|
|
283
|
+
console.log(`ERC found ${ercResults.length} items:`);
|
|
284
|
+
ercResults.forEach((item, index) => {
|
|
285
|
+
console.log(`${(index + 1).toString().padStart(3)}. line ${item.start.line}, column ${item.start.column}: ${item.type} - ${item.message}`);
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
270
289
|
}
|
|
271
290
|
catch (err) {
|
|
272
291
|
throw new RenderError(`Error during layout generation: ${err}`, 'layout');
|
package/dist/esm/layout.js
CHANGED
|
@@ -51,23 +51,23 @@ export class LayoutEngine {
|
|
|
51
51
|
const sheetFrameObjects = sheetFrames.map(sheet => {
|
|
52
52
|
const items = this.flattenFrameItems(sheet);
|
|
53
53
|
const components = items.filter(item => item instanceof RenderComponent);
|
|
54
|
-
const
|
|
54
|
+
const renderWires = items.filter(item => item instanceof RenderWire);
|
|
55
55
|
const textObjects = items.filter(item => item instanceof RenderText);
|
|
56
56
|
const frames = items.filter(item => item instanceof RenderFrame);
|
|
57
|
-
const
|
|
58
|
-
|
|
57
|
+
const renderWireGroups = new Map();
|
|
58
|
+
renderWires.forEach(wire => {
|
|
59
59
|
const { netName } = wire;
|
|
60
|
-
if (!
|
|
61
|
-
|
|
60
|
+
if (!renderWireGroups.has(netName)) {
|
|
61
|
+
renderWireGroups.set(netName, []);
|
|
62
62
|
}
|
|
63
|
-
|
|
63
|
+
renderWireGroups.get(netName).push(wire);
|
|
64
64
|
});
|
|
65
|
-
const { junctions, mergedWires } = this.findJunctions(
|
|
65
|
+
const { junctions, mergedWires } = this.findJunctions(renderWireGroups, renderNets);
|
|
66
66
|
return {
|
|
67
67
|
frame: sheet,
|
|
68
68
|
frames,
|
|
69
69
|
components,
|
|
70
|
-
wires,
|
|
70
|
+
wires: renderWires,
|
|
71
71
|
textObjects,
|
|
72
72
|
junctions,
|
|
73
73
|
mergedWires
|
|
@@ -119,12 +119,12 @@ export class LayoutEngine {
|
|
|
119
119
|
});
|
|
120
120
|
return items;
|
|
121
121
|
}
|
|
122
|
-
findJunctions(
|
|
122
|
+
findJunctions(renderWireGroups, nets) {
|
|
123
123
|
const junctions = [];
|
|
124
124
|
const mergedWires = [];
|
|
125
125
|
const debugSegments = false;
|
|
126
|
-
for (const [netName,
|
|
127
|
-
const allLines =
|
|
126
|
+
for (const [netName, renderWires] of renderWireGroups) {
|
|
127
|
+
const allLines = renderWires.map(wire => {
|
|
128
128
|
return wire.points.map(pt => {
|
|
129
129
|
return {
|
|
130
130
|
x: wire.x.add(pt.x),
|
|
@@ -843,7 +843,7 @@ export class LayoutEngine {
|
|
|
843
843
|
item.y = fromY.sub(pinPosition.y);
|
|
844
844
|
}
|
|
845
845
|
else if (item instanceof RenderWire) {
|
|
846
|
-
if (pin === 0) {
|
|
846
|
+
if (pin.getValue() === 0) {
|
|
847
847
|
item.x = fromX;
|
|
848
848
|
item.y = fromY;
|
|
849
849
|
}
|
|
@@ -1017,12 +1017,14 @@ export class RenderWire extends RenderObject {
|
|
|
1017
1017
|
points = [];
|
|
1018
1018
|
netName;
|
|
1019
1019
|
net;
|
|
1020
|
-
|
|
1020
|
+
wire;
|
|
1021
|
+
constructor(net, x, y, segments, wire) {
|
|
1021
1022
|
super();
|
|
1022
1023
|
this.net = net;
|
|
1023
1024
|
this.x = x;
|
|
1024
1025
|
this.y = y;
|
|
1025
1026
|
this.segments = segments;
|
|
1027
|
+
this.wire = wire;
|
|
1026
1028
|
this.refreshPoints();
|
|
1027
1029
|
}
|
|
1028
1030
|
refreshPoints() {
|
package/dist/esm/main.js
CHANGED
|
@@ -21,7 +21,9 @@ export default async function main() {
|
|
|
21
21
|
.option('-n, --dump-nets', 'Dump out net information')
|
|
22
22
|
.option('-d, --dump-data', 'Dump data during parsing')
|
|
23
23
|
.option('-s, --stats', 'Show stats during generation')
|
|
24
|
-
.option('-x, --skip-output', 'Skip output generation')
|
|
24
|
+
.option('-x, --skip-output', 'Skip output generation')
|
|
25
|
+
.option('-e, --erc', 'Enable ERC output')
|
|
26
|
+
.option('-b, --bom [output-path]', 'Generate Bill of Materials in csv format');
|
|
25
27
|
program.addHelpText('before', figlet.textSync('circuitscript', {
|
|
26
28
|
font: 'Small Slant'
|
|
27
29
|
}));
|
|
@@ -34,6 +36,9 @@ export default async function main() {
|
|
|
34
36
|
const watchFileChanges = options.watch;
|
|
35
37
|
const dumpNets = options.dumpNets;
|
|
36
38
|
const dumpData = options.dumpData;
|
|
39
|
+
const enableErc = options.erc;
|
|
40
|
+
const enableBom = options.bom !== undefined;
|
|
41
|
+
let bomOutputPath = options.bom;
|
|
37
42
|
if (options.currentDirectory) {
|
|
38
43
|
throw "Parameter not supported yet";
|
|
39
44
|
}
|
|
@@ -72,10 +77,21 @@ export default async function main() {
|
|
|
72
77
|
if (options.annotatedPath !== undefined) {
|
|
73
78
|
saveAnnotatedCopyPath = options.annotatedPath;
|
|
74
79
|
}
|
|
80
|
+
if (enableBom && (bomOutputPath === true || bomOutputPath === undefined)) {
|
|
81
|
+
if (inputFilePath) {
|
|
82
|
+
bomOutputPath = inputFilePath + '.bom.csv';
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
bomOutputPath = 'output.bom.csv';
|
|
86
|
+
}
|
|
87
|
+
}
|
|
75
88
|
const scriptOptions = {
|
|
76
89
|
dumpNets,
|
|
77
90
|
dumpData,
|
|
78
91
|
showStats: options.stats,
|
|
92
|
+
enableErc,
|
|
93
|
+
enableBom,
|
|
94
|
+
bomOutputPath,
|
|
79
95
|
environment: env,
|
|
80
96
|
inputPath: inputFilePath,
|
|
81
97
|
updateSource,
|
|
@@ -165,6 +165,9 @@ export class ExecutionScope {
|
|
|
165
165
|
const propertyTree = this.findPropertyKeyTree(visitor);
|
|
166
166
|
lastHandler && lastHandler(propertyTree, value, valueCtx);
|
|
167
167
|
}
|
|
168
|
+
getInstances() {
|
|
169
|
+
return Array.from(this.instances.values());
|
|
170
|
+
}
|
|
168
171
|
}
|
|
169
172
|
export var SequenceAction;
|
|
170
173
|
(function (SequenceAction) {
|
|
@@ -28,10 +28,20 @@ export class PinId {
|
|
|
28
28
|
}
|
|
29
29
|
equals(other) {
|
|
30
30
|
if (other instanceof PinId) {
|
|
31
|
-
return this.value === other.value
|
|
31
|
+
return this.value === other.value
|
|
32
|
+
&& this.getType() === other.getType();
|
|
32
33
|
}
|
|
33
34
|
return this.value === other;
|
|
34
35
|
}
|
|
36
|
+
getHashValue() {
|
|
37
|
+
if (this.type === PinIdType.Int) {
|
|
38
|
+
return 'int-' + this.value;
|
|
39
|
+
}
|
|
40
|
+
else if (this.type === PinIdType.Str) {
|
|
41
|
+
return 'str-' + this.value;
|
|
42
|
+
}
|
|
43
|
+
return '';
|
|
44
|
+
}
|
|
35
45
|
static from(value) {
|
|
36
46
|
if (value instanceof NumericValue) {
|
|
37
47
|
return new PinId(value.toNumber());
|
|
@@ -20,9 +20,10 @@ export class AnyReference {
|
|
|
20
20
|
found = false;
|
|
21
21
|
name;
|
|
22
22
|
trailers = [];
|
|
23
|
+
trailerIndex = -1;
|
|
23
24
|
type;
|
|
24
25
|
value;
|
|
25
|
-
|
|
26
|
+
rootValue;
|
|
26
27
|
referenceName = 'AnyReference';
|
|
27
28
|
constructor(refType) {
|
|
28
29
|
if (refType.value instanceof AnyReference
|
|
@@ -32,9 +33,10 @@ export class AnyReference {
|
|
|
32
33
|
this.found = refType.found;
|
|
33
34
|
this.name = refType.name;
|
|
34
35
|
this.trailers = refType.trailers;
|
|
36
|
+
this.trailerIndex = refType.trailerIndex;
|
|
35
37
|
this.type = refType.type ?? ReferenceTypes.unknown;
|
|
36
38
|
this.value = refType.value;
|
|
37
|
-
this.
|
|
39
|
+
this.rootValue = refType.rootValue;
|
|
38
40
|
}
|
|
39
41
|
toString() {
|
|
40
42
|
return `[${this.referenceName} name: ${this.name} trailers:${this.trailers} found: ${this.found}]`;
|
|
@@ -65,13 +67,13 @@ export class DeclaredReference extends AnyReference {
|
|
|
65
67
|
referenceName = 'DeclaredReference';
|
|
66
68
|
toDisplayString() {
|
|
67
69
|
let returnValue = undefined;
|
|
68
|
-
if (this.
|
|
70
|
+
if (this.rootValue) {
|
|
69
71
|
const trailersString = this.trailers.join(".");
|
|
70
72
|
if (this.type === 'instance') {
|
|
71
|
-
returnValue = this.
|
|
73
|
+
returnValue = this.rootValue.parameters.get(trailersString);
|
|
72
74
|
}
|
|
73
75
|
else if (this.type === 'variable') {
|
|
74
|
-
returnValue = this.
|
|
76
|
+
returnValue = this.rootValue[trailersString];
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
else {
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { RenderItemType } from "../graph.js";
|
|
2
|
+
import { ERC_Rules } from "./rules.js";
|
|
3
|
+
export function RuleCheck_NoConnectOnConnectedPin(graph, nets) {
|
|
4
|
+
const allNodes = graph.nodes();
|
|
5
|
+
const items = [];
|
|
6
|
+
const netComponentPins = new Map();
|
|
7
|
+
const pinMapping = new Map();
|
|
8
|
+
const makeComponentPinHash = (instanceName, pin) => {
|
|
9
|
+
return instanceName + '-' + pin.getHashValue();
|
|
10
|
+
};
|
|
11
|
+
nets.forEach(item => {
|
|
12
|
+
const [component, pin, net] = item;
|
|
13
|
+
if (!netComponentPins.has(net)) {
|
|
14
|
+
netComponentPins.set(net, []);
|
|
15
|
+
}
|
|
16
|
+
const items = netComponentPins.get(net);
|
|
17
|
+
items.push([
|
|
18
|
+
component.instanceName,
|
|
19
|
+
pin
|
|
20
|
+
]);
|
|
21
|
+
netComponentPins.set(net, items);
|
|
22
|
+
pinMapping.set(makeComponentPinHash(component.instanceName, pin), net);
|
|
23
|
+
});
|
|
24
|
+
allNodes.forEach(node => {
|
|
25
|
+
const nodeInfo = graph.node(node);
|
|
26
|
+
if (nodeInfo[0] === RenderItemType.Component) {
|
|
27
|
+
const { component } = nodeInfo[1];
|
|
28
|
+
if (component.hasParam('no_connect')) {
|
|
29
|
+
const instanceName = component.instanceName;
|
|
30
|
+
const edges = graph.nodeEdges(node);
|
|
31
|
+
const otherNodes = [];
|
|
32
|
+
edges.forEach(edge => {
|
|
33
|
+
const edgeInfo = graph.edge(edge.v, edge.w);
|
|
34
|
+
let targetComponentName;
|
|
35
|
+
let targetPin;
|
|
36
|
+
if (edge.v === instanceName) {
|
|
37
|
+
otherNodes.push(edge.w);
|
|
38
|
+
targetComponentName = edge.w;
|
|
39
|
+
targetPin = edgeInfo[3];
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
targetComponentName = edge.v;
|
|
43
|
+
targetPin = edgeInfo[1];
|
|
44
|
+
}
|
|
45
|
+
const componentPinHash = makeComponentPinHash(targetComponentName, targetPin);
|
|
46
|
+
if (pinMapping.has(componentPinHash)) {
|
|
47
|
+
const net = pinMapping.get(componentPinHash);
|
|
48
|
+
const tmpNetComponentPins = netComponentPins.get(net);
|
|
49
|
+
const remainingItems = tmpNetComponentPins.filter(item => {
|
|
50
|
+
if (item[0] === instanceName) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
else if (item[0] === targetComponentName
|
|
54
|
+
&& item[1].getHashValue() === targetPin.getHashValue()) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
});
|
|
59
|
+
if (remainingItems.length > 0) {
|
|
60
|
+
const targetInfo = graph.node(targetComponentName);
|
|
61
|
+
const tmpComponent = targetInfo[1];
|
|
62
|
+
items.push({
|
|
63
|
+
type: ERC_Rules.NoConnectOnConnectedPin,
|
|
64
|
+
instance: component,
|
|
65
|
+
target: {
|
|
66
|
+
instance: tmpComponent.component,
|
|
67
|
+
pin: targetPin
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return items;
|
|
77
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { RuleCheck_UnconnectedPinsWires } from "./unconnected-pins.js";
|
|
2
|
+
import { RuleCheck_NoConnectOnConnectedPin } from "./no-connect-on-connected-pin.js";
|
|
3
|
+
export var ERC_Rules;
|
|
4
|
+
(function (ERC_Rules) {
|
|
5
|
+
ERC_Rules["UnconnectedPin"] = "UNCONNECTED-PIN";
|
|
6
|
+
ERC_Rules["UnconnectedWire"] = "UNCONNECTED-WIRE";
|
|
7
|
+
ERC_Rules["NoConnectOnConnectedPin"] = "NO-CONNECT-ON-CONNECTED-PIN";
|
|
8
|
+
})(ERC_Rules || (ERC_Rules = {}));
|
|
9
|
+
export function EvaluateERCRules(visitor, graph, nets) {
|
|
10
|
+
const ruleCheckItems = [];
|
|
11
|
+
const creationCtx = visitor.creationCtx;
|
|
12
|
+
ruleCheckItems.push(...RuleCheck_UnconnectedPinsWires(graph), ...RuleCheck_NoConnectOnConnectedPin(graph, nets));
|
|
13
|
+
const reportItems = [];
|
|
14
|
+
ruleCheckItems.forEach(item => {
|
|
15
|
+
const { type } = item;
|
|
16
|
+
switch (type) {
|
|
17
|
+
case ERC_Rules.UnconnectedPin:
|
|
18
|
+
{
|
|
19
|
+
const instance = item.instance;
|
|
20
|
+
const token = getComponentFirstCtxToken(instance);
|
|
21
|
+
if (token) {
|
|
22
|
+
reportItems.push({
|
|
23
|
+
type,
|
|
24
|
+
start: token,
|
|
25
|
+
message: `Unconnected pin ${item.pin} for component`
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
break;
|
|
30
|
+
case ERC_Rules.UnconnectedWire:
|
|
31
|
+
{
|
|
32
|
+
const wire = item.wire;
|
|
33
|
+
if (creationCtx.has(wire)) {
|
|
34
|
+
const tmpCtx = creationCtx.get(wire);
|
|
35
|
+
const startToken = tmpCtx.start;
|
|
36
|
+
reportItems.push({
|
|
37
|
+
type,
|
|
38
|
+
start: startToken,
|
|
39
|
+
message: `Unconnected wire end`
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
case ERC_Rules.NoConnectOnConnectedPin:
|
|
45
|
+
{
|
|
46
|
+
const instance = item.instance;
|
|
47
|
+
const token = getComponentFirstCtxToken(instance);
|
|
48
|
+
if (token) {
|
|
49
|
+
reportItems.push({
|
|
50
|
+
type,
|
|
51
|
+
start: token,
|
|
52
|
+
message: `No connect on connected pin`
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
const sortedReport = reportItems.toSorted((a, b) => {
|
|
60
|
+
return a.start.start - b.start.start;
|
|
61
|
+
});
|
|
62
|
+
return sortedReport;
|
|
63
|
+
}
|
|
64
|
+
function getComponentFirstCtxToken(instance) {
|
|
65
|
+
if (instance.ctxReferences.length > 0) {
|
|
66
|
+
const { ctx } = instance.ctxReferences[0];
|
|
67
|
+
return ctx.start;
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { RenderItemType } from "../graph.js";
|
|
2
|
+
import { ERC_Rules } from "./rules.js";
|
|
3
|
+
export function RuleCheck_UnconnectedPinsWires(graph) {
|
|
4
|
+
const items = [];
|
|
5
|
+
const allNodes = graph.nodes();
|
|
6
|
+
allNodes.forEach(node => {
|
|
7
|
+
const nodeInfo = graph.node(node);
|
|
8
|
+
if (nodeInfo[0] === RenderItemType.Component) {
|
|
9
|
+
const { component } = nodeInfo[1];
|
|
10
|
+
const edges = graph.nodeEdges(node);
|
|
11
|
+
const instanceName = component.instanceName;
|
|
12
|
+
const connectedPins = [];
|
|
13
|
+
edges.forEach(edge => {
|
|
14
|
+
const edgeInfo = graph.edge(edge.v, edge.w);
|
|
15
|
+
let pin;
|
|
16
|
+
if (edge.v === instanceName) {
|
|
17
|
+
pin = edgeInfo[1];
|
|
18
|
+
}
|
|
19
|
+
else if (edge.w === instanceName) {
|
|
20
|
+
pin = edgeInfo[3];
|
|
21
|
+
}
|
|
22
|
+
connectedPins.push(pin.getHashValue());
|
|
23
|
+
});
|
|
24
|
+
const pinIds = Array.from(component.pins.keys());
|
|
25
|
+
pinIds.forEach(pinId => {
|
|
26
|
+
const hashValue = pinId.getHashValue();
|
|
27
|
+
if (connectedPins.indexOf(hashValue) === -1) {
|
|
28
|
+
items.push({
|
|
29
|
+
type: ERC_Rules.UnconnectedPin,
|
|
30
|
+
instance: component,
|
|
31
|
+
pin: pinId,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
else if (nodeInfo[0] === RenderItemType.Wire) {
|
|
37
|
+
const renderWire = nodeInfo[1];
|
|
38
|
+
const edges = graph.nodeEdges(node);
|
|
39
|
+
if (edges.length < 2) {
|
|
40
|
+
items.push({
|
|
41
|
+
type: ERC_Rules.UnconnectedWire,
|
|
42
|
+
wire: renderWire.wire,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
return items;
|
|
48
|
+
}
|