Header menu logo issie

Parameter System Documentation

Overview

The parameter system in Issie allows users to define symbolic integer parameters on design sheets and use them in mathematical expressions to configure component properties. This enables parameterized component design where values can be dynamically calculated based on parameter bindings rather than being hardcoded. The system supports hierarchical parameter scoping and instance-specific parameter overrides.

Key Features

Architecture

The parameter system is implemented across several key modules with clear separation of concerns:

Core Data Types (ParameterTypes.fs)

The parameter system's foundation is built on these core types:

Basic Types

Expression AST

type ParamExpression =
    | PInt of ParamInt                              // Integer constant
    | PParameter of ParamName                       // Parameter reference
    | PAdd of ParamExpression * ParamExpression     // Addition
    | PSubtract of ParamExpression * ParamExpression // Subtraction
    | PMultiply of ParamExpression * ParamExpression // Multiplication
    | PDivide of ParamExpression * ParamExpression  // Division
    | PRemainder of ParamExpression * ParamExpression // Modulo

Constraints

type ParamConstraint =
    | MinVal of ParamExpression * ParamError  // Minimum value constraint
    | MaxVal of ParamExpression * ParamError  // Maximum value constraint

Component Slots

type CompSlotName =
    | Buswidth              // Component bus width
    | NGateInputs           // Number of gate inputs
    | IO of Label: string   // Input/Output port widths
    | CustomCompParam of ParamName: string // Custom component parameters

Sheet-Level Definitions

type ParameterDefs = {
    DefaultBindings: ParamBindings  // Parameter name to expression mappings
    ParamSlots: ComponentSlotExpr   // Component slots bound to expressions
}

UI Layer (ParameterView.fs)

Manages all parameter-related user interactions:

Sheet Parameter Management

Component Parameter Binding

Parameter Evaluation

Simulation Integration (GraphMerger.fs)

Handles parameter resolution during simulation graph construction using a two-stage process:

Stage 1 - Graph Merging

Stage 2 - Parameter Resolution

2a. Instance-specific (resolveCustomComponentParameters): - Apply component instance parameter bindings - Override default values from definitions - Process nested custom components recursively

2b. Sheet-level (resolveParametersInSimulationGraph): - Use default sheet parameter bindings - Evaluate expressions for all parameterized slots - Update component configurations with resolved values

This two-stage approach prevents forward reference issues and ensures proper parameter precedence.

Validation Layer (CanvasStateAnalyser.fs)

Provides lightweight parameter resolution for component validation: - Simplified evaluator supporting only PInt and PParameter - Resolves I/O port widths for label extraction - Optimized for validation performance

Component Creation (CatalogueView.fs)

Integrates parameters during component instantiation: - Merges parent sheet parameters with component defaults - Resolves parameters before extracting port labels - Passes parameter bindings to custom components - Creates parameter input dialogs for component properties

Data Flow

1. Parameter Definition Flow

User Input (Properties Panel)
    
ParameterView.addParameterBox
    
ParameterTypes.parseExpression (validate syntax)
    
Update Model.LoadedComponent.LCParameterSlots
    
Persist to .dgm file

2. Component Parameterization Flow

User selects component property
    
ParameterView.paramInputField
    
Parse & evaluate expression
    
Check constraints
    
Update ComponentSlotExpr map
    
Apply to component via Sheet messages

3. Simulation Resolution Flow

Simulation Start
    
GraphMerger.mergeDependencies
    
Stage 1: Merge graphs (defer parameters)
    
Stage 2a: Resolve instance parameters
    
Stage 2b: Resolve sheet parameters
    
FastSim with resolved values

4. Custom Component Flow

Parent Sheet Parameters
    
Merge with Component Defaults
    
Resolve Canvas State
    
Extract Port Labels
    
Create Custom Component Instance

Expression Language

The parameter expression parser supports:

Syntax Elements

Example Expressions

WIDTH           // Simple parameter reference
WIDTH + 1       // Increment parameter
(n * 8) - 1     // Complex calculation
baseAddr + (offset * 4)  // Address calculation
WIDTH / 2       // Division
SIZE % 8        // Modulo operation

Parser Implementation

The parser uses recursive descent with separate functions for each precedence level: - parsePrimary: Handles numbers, variables, and parentheses - parseFactors: Processes multiplication, division, modulo - parseExpressionTokens: Handles addition and subtraction

Parameter Scoping & Precedence

Scope Levels

  1. Sheet-level parameters: Defined in sheet properties, scope limited to that sheet
  2. Instance parameters: Override sheet defaults for specific component instances
  3. Custom component parameters: Inherited from parent sheet, can be overridden per instance

Precedence Rules (highest to lowest)

  1. Instance-specific bindings
  2. Parent sheet parameters
  3. Component default parameters

Example Scenario

Sheet A defines: WIDTH = 8
Custom Component B has default: WIDTH = 16
Instance of B in A with override: WIDTH = 32

Result: Instance uses WIDTH = 32

Constraint System

Constraints ensure parameter values remain within valid ranges:

Constraint Definition

type ParamConstraint =
    | MinVal of ParamExpression * ParamError
    | MaxVal of ParamExpression * ParamError

Features

Example

let widthConstraints = [
    MinVal (PInt 1, "Width must be at least 1 bit")
    MaxVal (PInt 64, "Width cannot exceed 64 bits")
]

Three-Tier Evaluation Architecture

The system implements three evaluation strategies optimized for different contexts:

1. Full Resolution (ParameterTypes.evaluateParamExpression)

2. Graph Resolution (GraphMerger.evalExpr)

3. Validation Resolution (CanvasStateAnalyser)

Persistence

Parameter data is stored across multiple locations:

File Storage

Runtime State

Component Support

Currently Parameterizable Components

Width-Configurable Components

Custom Components

I/O Components

Constants

Adding Parameter Support to New Components

  1. Add case to compSlot_ lens in ParameterView.fs
  2. Update component type in CommonTypes.fs
  3. Add UI support in component properties
  4. Handle in simulation resolution

Usage Examples

Example 1: Define Sheet Parameter

// User adds parameter "WIDTH" with value 8
1. Open sheet properties panel
2. Click "Add Parameter"
3. Enter name: "WIDTH"
4. Enter value: 8
5. Parameter available for use in expressions

Example 2: Use Parameter in Component

// Configure Register with parameterized width
1. Add Register component to sheet
2. Select Register
3. In properties, enter bus width: "WIDTH"
4. System evaluates to 8
5. Change WIDTH parameter 

Example 3: Override in Custom Component

// Custom component with parameter override
1. Create custom component from sheet with WIDTH parameter
2. Place instance in parent sheet
3. Select instance
4. Edit parameter binding: WIDTH = "parentWidth * 2"
5. Instance uses calculated value

Example 4: Complex Expression

// Address decoder with calculated ranges
1. Define parameters: BASE_ADDR = 0x1000, BLOCK_SIZE = 256
2. Create comparator with expression: "BASE_ADDR + (BLOCK_SIZE * 4)"
3. System evaluates to 0x1400

Error Handling

The system provides comprehensive error handling at multiple levels:

Parse Errors

Evaluation Errors

Constraint Violations

Type Errors

Implementation Details

Optics/Lenses Pattern

The system uses functional lenses for immutable state updates:

let paramSlotsOfModel_ = 
    lcParameterInfoOfModel_ >?> paramSlots_

model |> set paramSlotsOfModel_ newSlots

Message Dispatch

State changes flow through Elmish messages:

Sheet (SheetT.Wire (BusWireT.Symbol (SymbolT.ChangeWidth ...)))

Functional Patterns

Testing & Debugging

Debug Helpers

// Enable parameter debug tracing
if Set.contains "params" JSHelpers.debugTraceUI then
    printfn "Parameter evaluation: %A -> %A" expr value

Common Issues

  1. Forward references: Resolved by two-stage simulation
  2. Circular dependencies: Detected and reported
  3. Constraint conflicts: Validated before application
  4. Type mismatches: Caught by F# type system

Future Extensions

Potential enhancements identified in the codebase:

Type System

Advanced Features

UI Improvements

API Reference

Key Functions

Expression Parsing

parseExpression: string -> Result<ParamExpression, ParamError>

Expression Evaluation

evaluateParamExpression: ParamBindings -> ParamExpression -> Result<ParamInt, ParamError>

Expression Rendering

renderParamExpression: ParamExpression -> int -> string

Parameter Resolution

resolveParametersForComponent: ParamBindings -> Map<ParamSlot, ConstrainedExpr> -> Component -> Result<Component, string>

Constraint Checking

evaluateConstraints: ParamBindings -> ConstrainedExpr list -> (Msg -> unit) -> Result<Unit, ParamConstraint list>

Best Practices

  1. Use descriptive parameter names: DATA_WIDTH instead of W
  2. Define constraints early: Prevent invalid values at input time
  3. Document parameter meanings: In component descriptions
  4. Test edge cases: Min/max values, zero, negative numbers
  5. Keep expressions simple: Complex logic in simulation, not parameters
  6. Use consistent naming: Across sheets and components
  7. Validate before simulation: Check all parameters resolve correctly

Troubleshooting

Parameter Not Found

Expression Parse Error

Constraint Violation

Simulation Failure

type ParamExpression = | PInt of obj | PParameter of obj | PAdd of ParamExpression * ParamExpression | PSubtract of ParamExpression * ParamExpression | PMultiply of ParamExpression * ParamExpression | PDivide of ParamExpression * ParamExpression | PRemainder of ParamExpression * ParamExpression
type ParamConstraint = | MinVal of ParamExpression * obj | MaxVal of ParamExpression * obj
type CompSlotName = | Buswidth | NGateInputs | IO of Label: string | CustomCompParam of ParamName: string
Multiple items
val string: value: 'T -> string

--------------------
type string = System.String
type ParameterDefs = { DefaultBindings: obj ParamSlots: obj }
Multiple items
module Result from Microsoft.FSharp.Core

--------------------
[<Struct>] type Result<'T,'TError> = | Ok of ResultValue: 'T | Error of ErrorValue: 'TError
union case ParamConstraint.MinVal: ParamExpression * obj -> ParamConstraint
union case ParamConstraint.MaxVal: ParamExpression * obj -> ParamConstraint
union case ParamExpression.PInt: obj -> ParamExpression
namespace System
val set: elements: 'T seq -> Set<'T> (requires comparison)
Multiple items
module Set from Microsoft.FSharp.Collections

--------------------
type Set<'T (requires comparison)> = interface IReadOnlyCollection<'T> interface IStructuralEquatable interface IComparable interface IEnumerable interface IEnumerable<'T> interface ICollection<'T> new: elements: 'T seq -> Set<'T> member Add: value: 'T -> Set<'T> member Contains: value: 'T -> bool override Equals: obj -> bool ...

--------------------
new: elements: 'T seq -> Set<'T>
val contains: element: 'T -> set: Set<'T> -> bool (requires comparison)
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
Multiple items
val int: value: 'T -> int (requires member op_Explicit)

--------------------
type int = int32

--------------------
type int<'Measure> = int
Multiple items
module Map from Microsoft.FSharp.Collections

--------------------
type Map<'Key,'Value (requires comparison)> = interface IReadOnlyDictionary<'Key,'Value> interface IReadOnlyCollection<KeyValuePair<'Key,'Value>> interface IEnumerable interface IStructuralEquatable interface IComparable interface IEnumerable<KeyValuePair<'Key,'Value>> interface ICollection<KeyValuePair<'Key,'Value>> interface IDictionary<'Key,'Value> new: elements: ('Key * 'Value) seq -> Map<'Key,'Value> member Add: key: 'Key * value: 'Value -> Map<'Key,'Value> ...

--------------------
new: elements: ('Key * 'Value) seq -> Map<'Key,'Value>
type 'T list = List<'T>
type unit = Unit

Type something to start searching.