Skip to content
Draft

wip #59

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/pages/edit/Editor/components/NodePinPropertyEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ export function CCComponentEditorNodePinPropertyEditor() {
"NodePinPropertyEditor can only be used for node pins with user specified bit width",
);
const componentPinAttributes = nullthrows(
IntrinsicComponentDefinition.intrinsicComponentPinAttributesByComponentPinId.get(
target.componentPinId,
),
IntrinsicComponentDefinition.getPinAttributesByPinId(target.componentPinId),
"NodePinPropertyEditor can only be used for intrinsic component pins",
);

Expand Down
29 changes: 27 additions & 2 deletions src/store/componentPin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
xor,
} from "./intrinsics/definitions";
import type { CCNodePinId } from "./nodePin";
// import { IntrinsicComponentDefinition } from "./intrinsics/base";

export type CCComponentPin = {
readonly id: CCComponentPinId;
Expand All @@ -36,16 +37,25 @@ export const ccPinTypes: CCComponentPinType[] = ["input", "output"];
/** null for intrinsic components */
export type CCPinImplementation = CCNodePinId | null;

/**
* The resolved bit width status of a node pin instance.
* - `isFixed: false` — the bit width has not yet been determined.
* - `isFixed: true` — the bit width is known and available as `bitWidth`.
*/
export type CCNodePinBitWidthStatus =
| { isFixed: false }
| { isFixed: true; bitWidth: number };

/**
* The bit width status of a component pin definition.
* - `isFixed: false, fixMode: "automatic"` — the bit width is not yet determined and will be inferred automatically from connections.
* - `isFixed: false, fixMode: "manual"` — the bit width is not yet determined and must be specified manually by the user.
* - `isFixed: true` — the bit width is known and available as `bitWidth`.
*/
export type CCComponentPinBitWidthStatus =
| { isFixed: false; fixMode: "automatic" | "manual" }
| { isFixed: true; bitWidth: number };

export type CCNodePinFixedBitWidth = number;

export type CCComponentPinStoreEvents = {
didRegister(pin: CCComponentPin): void;
willUnregister(pin: CCComponentPin): void;
Expand Down Expand Up @@ -217,6 +227,21 @@ export class CCComponentPinStore extends EventEmitter<CCComponentPinStoreEvents>
): CCComponentPinBitWidthStatus {
const pin = this.#pins.get(pinId);
invariant(pin);

// const intrinsicPinAttributes =
// IntrinsicComponentDefinition.getPinAttributesByPinId(pin.id);
// if (intrinsicPinAttributes) {
// if (intrinsicPinAttributes.bitWidthPolicy.type === "inferred")
// return { isFixed: false, fixMode: "automatic" };
// if (intrinsicPinAttributes.bitWidthPolicy.type === "configurable")
// return { isFixed: false, fixMode: "manual" };
// if (intrinsicPinAttributes.bitWidthPolicy.type === "fixed") {
// const definition = nullthrows(IntrinsicComponentDefinition.getByComponentId(pin.componentId));
// }
// throw new Error(`Unknown bit width policy: ${intrinsicPinAttributes.bitWidthPolicy}`);
// }

// TODO: Remove hardcoded intrinsic component pin IDs and replace with a more flexible system, such as metadata on the component definitions.
switch (pin.id) {
case nullthrows(and.inputPin.A.id):
case nullthrows(and.inputPin.B.id):
Expand Down
65 changes: 40 additions & 25 deletions src/store/intrinsics/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,37 @@ export type CCComponentPinInstanceShapes = {
export type ComponentEvaluationContext = {
previousFrame: SimulationFrame | null;
currentFrame: SimulationFrame;
defaultBitWidth: number;
};

export type Context = {
componentId: CCComponentId;
};

type IntrinsicComponentPinAttributes = {
type IntrinsicComponentPinBitWidthPolicy<
Spec extends CCIntrinsicComponentSpec,
> =
| { type: "inferred" }
| {
type: "fixed";
calculateBitWidth: (
config: Spec["config"],
manualBitWidths: Partial<Record<Spec["in" | "out"], number[]>>,
) => number;
}
| { type: "configurable"; isSplittable: boolean };

type IntrinsicComponentPinAttributes<Spec extends CCIntrinsicComponentSpec> = {
name: string;
bitWidthPolicy: IntrinsicComponentPinBitWidthPolicy<Spec>;
isBitWidthConfigurable?: boolean;
isSplittable?: boolean;
};
type Props<Spec extends CCIntrinsicComponentSpec> = {
type: CCIntrinsicComponentType;
name: string;
in: Record<Spec["in"], IntrinsicComponentPinAttributes>;
out: Record<Spec["out"], IntrinsicComponentPinAttributes>;
in: Record<Spec["in"], IntrinsicComponentPinAttributes<Spec>>;
out: Record<Spec["out"], IntrinsicComponentPinAttributes<Spec>>;
initialConfig: Spec["config"];
evaluate: (
context: ComponentEvaluationContext,
Expand All @@ -48,11 +63,6 @@ type Props<Spec extends CCIntrinsicComponentSpec> = {
export class IntrinsicComponentDefinition<
Spec extends CCIntrinsicComponentSpec = CCIntrinsicComponentSpec,
> {
static intrinsicComponentPinAttributesByComponentPinId: Map<
CCComponentPinId,
IntrinsicComponentPinAttributes
> = new Map();

readonly id: CCComponentId;
readonly type: CCIntrinsicComponentType;
readonly name: string;
Expand Down Expand Up @@ -88,7 +98,9 @@ export class IntrinsicComponentDefinition<
intrinsicType: props.type,
name: this.name,
};
IntrinsicComponentDefinition._byId.set(this.id, this);
this.evaluate = props.evaluate;

this.inputPin = mapValues(props.in, (attributes) => {
const pin: CCComponentPin = {
id: this._generateId() as CCComponentPinId,
Expand All @@ -98,9 +110,9 @@ export class IntrinsicComponentDefinition<
order: this._lastLocalIndex++,
name: attributes.name,
};
IntrinsicComponentDefinition.intrinsicComponentPinAttributesByComponentPinId.set(
IntrinsicComponentDefinition._pinAttributesByPinId.set(
pin.id,
attributes,
attributes as IntrinsicComponentPinAttributes<CCIntrinsicComponentSpec>,
);
this.allPins.push(pin);
return pin;
Expand All @@ -114,26 +126,29 @@ export class IntrinsicComponentDefinition<
order: this._lastLocalIndex++,
name: attributes.name,
};
IntrinsicComponentDefinition.intrinsicComponentPinAttributesByComponentPinId.set(
IntrinsicComponentDefinition._pinAttributesByPinId.set(
pin.id,
attributes,
attributes as IntrinsicComponentPinAttributes<CCIntrinsicComponentSpec>,
);
this.allPins.push(pin);
return pin;
});
this.initialConfig = props.initialConfig;
// this.outputPin = {
// id: this._generateId() as CCComponentPinId,
// componentId: this.id,
// type: "output",
// implementation: null,
// order: this._lastLocalIndex++,
// name: props.out.name,
// };
// IntrinsicComponentDefinition.intrinsicComponentPinAttributesByComponentPinId.set(
// this.outputPin.id,
// props.out
// );
// this.allPins.push(this.outputPin);
}

private static _byId: Map<CCComponentId, IntrinsicComponentDefinition> =
new Map();
static getByComponentId(componentId: CCComponentId) {
return IntrinsicComponentDefinition._byId.get(componentId) ?? null;
}

private static _pinAttributesByPinId: Map<
CCComponentPinId,
IntrinsicComponentPinAttributes<CCIntrinsicComponentSpec>
> = new Map();
static getPinAttributesByPinId(pinId: CCComponentPinId) {
return (
IntrinsicComponentDefinition._pinAttributesByPinId.get(pinId) ?? null
);
}
}
96 changes: 77 additions & 19 deletions src/store/intrinsics/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ function createUnaryOperator(
{
type,
name,
in: { In: { name: "In" } },
out: { Out: { name: "Out" } },
in: { In: { name: "In", bitWidthPolicy: { type: "inferred" } } },
out: { Out: { name: "Out", bitWidthPolicy: { type: "inferred" } } },
initialConfig: null,
evaluate: (context, nodeId, shape) => {
const inputShape = shape.inputShape.In;
Expand Down Expand Up @@ -57,8 +57,11 @@ function createBinaryOperator(
{
type,
name,
in: { A: { name: "A" }, B: { name: "B" } },
out: { Out: { name: "Out" } },
in: {
A: { name: "A", bitWidthPolicy: { type: "inferred" } },
B: { name: "B", bitWidthPolicy: { type: "inferred" } },
},
out: { Out: { name: "Out", bitWidthPolicy: { type: "inferred" } } },
initialConfig: null,
evaluate: (context, nodeId, shape) => {
const inputShapeA = shape.inputShape.A;
Expand All @@ -73,7 +76,15 @@ function createBinaryOperator(
}
invariant(
inputValueA.length === inputValueB.length,
"Input lengths must match",
"Input lengths must match (name: " +
name +
", nodeId: " +
nodeId +
", inputValueA: " +
inputValueA +
", inputValueB: " +
inputValueB +
")",
);
const outputValue = Array.from({ length: inputValueA.length }, (_, i) =>
evaluate(nullthrows(inputValueA[i]), nullthrows(inputValueB[i])),
Expand All @@ -98,7 +109,7 @@ function createNullaryOperator(
type,
name,
in: {},
out: { Out: { name: "Out" } },
out: { Out: { name: "Out", bitWidthPolicy: { type: "inferred" } } },
initialConfig: null,
evaluate: (context, nodeId, shape) => {
const outputShape = shape.outputShape.Out;
Expand Down Expand Up @@ -149,7 +160,7 @@ export const input =
type: ccIntrinsicComponentTypes.INPUT,
name: "Input",
in: {},
out: { Out: { name: "Out" } },
out: { Out: { name: "In", bitWidthPolicy: { type: "inferred" } } },
initialConfig: null,
evaluate: (_context, _nodeId, _shape) => {
return true;
Expand All @@ -160,7 +171,7 @@ export const output =
new IntrinsicComponentDefinition<CCIntrinsicComponentOutputSpec>({
type: ccIntrinsicComponentTypes.OUTPUT,
name: "Output",
in: { In: { name: "In" } },
in: { In: { name: "Out", bitWidthPolicy: { type: "inferred" } } },
out: {},
initialConfig: null,
evaluate: (_context, _nodeId, _shape) => {
Expand All @@ -173,9 +184,24 @@ export const aggregate =
type: ccIntrinsicComponentTypes.AGGREGATE,
name: "Aggregate",
in: {
In: { name: "In", isBitWidthConfigurable: true, isSplittable: true },
In: {
name: "In",
bitWidthPolicy: { type: "configurable", isSplittable: true },
isBitWidthConfigurable: true,
isSplittable: true,
},
},
out: {
Out: {
name: "Out",
bitWidthPolicy: {
type: "fixed",
calculateBitWidth: (_, manualBitWidths) =>
manualBitWidths?.In?.reduce((sum, bitWidth) => sum + bitWidth, 0) ??
0,
},
},
},
out: { Out: { name: "Out" } },
initialConfig: null,
evaluate: (context, nodeId, shape) => {
const inputShape = shape.inputShape.In;
Expand All @@ -200,10 +226,25 @@ export const decompose =
type: ccIntrinsicComponentTypes.DECOMPOSE,
name: "Decompose",
in: {
In: { name: "In" },
In: {
name: "In",
bitWidthPolicy: {
type: "fixed",
calculateBitWidth: (_, manualBitWidths) =>
manualBitWidths?.Out?.reduce(
(sum, bitWidth) => sum + bitWidth,
0,
) ?? 0,
},
},
},
out: {
Out: { name: "Out", isBitWidthConfigurable: true, isSplittable: true },
Out: {
name: "Out",
bitWidthPolicy: { type: "configurable", isSplittable: true },
isBitWidthConfigurable: true,
isSplittable: true,
},
},
initialConfig: null,
evaluate: (context, nodeId, shape) => {
Expand Down Expand Up @@ -232,9 +273,18 @@ export const broadcast =
type: ccIntrinsicComponentTypes.BROADCAST,
name: "Broadcast",
in: {
In: { name: "In" },
In: {
name: "In",
bitWidthPolicy: { type: "fixed", calculateBitWidth: () => 1 },
},
},
out: {
Out: {
name: "Out",
bitWidthPolicy: { type: "configurable", isSplittable: false },
isBitWidthConfigurable: true,
},
},
out: { Out: { name: "Out", isBitWidthConfigurable: true } },
initialConfig: null,
evaluate: (context, nodeId, shape) => {
const inputShape = shape.inputShape.In;
Expand All @@ -261,17 +311,16 @@ export const flipflop =
new IntrinsicComponentDefinition<CCIntrinsicComponentUnaryOperatorSpec>({
type: ccIntrinsicComponentTypes.FLIPFLOP,
name: "FlipFlop",
in: {
In: { name: "In" },
},
out: { Out: { name: "Out" } },
in: { In: { name: "In", bitWidthPolicy: { type: "inferred" } } },
out: { Out: { name: "Out", bitWidthPolicy: { type: "inferred" } } },
initialConfig: null,
evaluate: (context, nodeId, shape) => {
const inputShape = shape.inputShape.In;
invariant(inputShape[0] && !inputShape[1]);
const outputShape = shape.outputShape.Out;
invariant(outputShape[0] && !outputShape[1]);
const nodePinIdToValue = context.currentFrame.nodes.get(nodeId)?.pins;
console.log("FlipFlop evaluate", { nodeId, inputShape, outputShape });
const previousValue =
context.previousFrame?.nodes
.get(nodeId)
Expand All @@ -289,7 +338,16 @@ export const display =
new IntrinsicComponentDefinition<CCIntrinsicComponentDisplaySpec>({
type: ccIntrinsicComponentTypes.DISPLAY,
name: "Display",
in: { Pixels: { name: "Pixels" } },
in: {
Pixels: {
name: "Pixels",
bitWidthPolicy: {
type: "fixed",
calculateBitWidth: (config) =>
config.resolution.x * config.resolution.y,
},
},
},
out: {},
initialConfig: { resolution: { x: 20, y: 15 } },
evaluate: () => true,
Expand Down
15 changes: 14 additions & 1 deletion src/store/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,20 @@ export class CCNodeStore extends EventEmitter<CCNodeStoreEvents> {
}
}

mount() {}
mount() {
this.#store.components.on("willUnregister", (component) => {
const ids = [...this.#nodes.values()]
.filter(
(node) =>
node.parentComponentId === component.id ||
node.componentId === component.id,
)
.map((node) => node.id);
if (ids.length > 0) {
this.unregister(ids);
}
});
}

/**
* Register a node
Expand Down
Loading
Loading