Streaming-friendly VCD waveform parser and digital signal analysis toolkit for MoonBit
moon run cmd/vcd-report
moon check --deny-warn
moon test --deny-warnmatch @vcd.parse(source) {
Ok(trace) => {
println(trace.summary())
println(@vcd.markdown_report(trace, @vcd.markdown_report_options()))
}
Err(error) => println(@vcd.parse_error_message(error))
}moon run cmd/vcd-report -- --help
moon run cmd/vcd-report -- --json
moon run cmd/vcd-report -- --markdown
moon run cmd/vcd-report -- --csv
moon run cmd/vcd-report -- --benchmark| Layer | Responsibility |
|---|---|
| Model and parser | VCD declarations, values, timestamps, and errors |
| Value and scope tools | Four-state logic, widths, paths, and glob queries |
| Index and query | Signal-local lookup, windows, snapshots, and timelines |
| Analysis | Edges, intervals, states, frequency, jitter, glitches, latency |
| Transform and compare | Filtering, clipping, merging, decimation, and diffs |
| Protocol and verification | UART, SPI, I²C, APB, clock quality, coverage, assertions, replay |
| Operations | Repair, schema, dependency graph, cache, checkpoints, package artifacts |
| Streaming and pipeline | Chunked decode, online digest, validation, and stage reports |
| Export and CLI | JSON, CSV, VCD, Markdown, text, and benchmark output |
| Fixture | Operation | Iterations | Input chars | Parsed | Changes | Checksum |
|---|---|---|---|---|---|---|
| synthetic-8x128 | parse | 20 | 6476 | 20 | 23040 | 12880 |
| synthetic-8x128 | indexed-queries | 20 | 0 | 1 | 23040 | 240 |
| synthetic-8x128 | analysis | 20 | 0 | 1 | 20320 | 101600 |
moon run cmd/vcd-report -- --benchmarkpub struct ActivitySegment {
start : Int64
end : Int64
changes : Int
active : Bool
density : Double
} derive(Debug)pub struct ActivitySegmentOptions {
bucket_width : Int64
active_threshold : Int
include_empty : Bool
} derive(Debug)fn ActivitySegmentOptions::with_empty(self : ActivitySegmentOptions, include_empty : Bool) -> ActivitySegmentOptionsfn ActivitySegmentOptions::with_threshold(self : ActivitySegmentOptions, threshold : Int) -> ActivitySegmentOptionspub struct AlignmentEstimate {
mode : AlignmentMode
left_marker : String?
right_marker : String?
left_time : Int64?
right_time : Int64?
offset : Int64
confidence : Double
} derive(Debug)pub struct AlignmentResult {
left : Trace
right : Trace
estimate : AlignmentEstimate
overlap_start : Int64
overlap_end : Int64
comparable : Bool
} derive(Debug)pub struct AnalysisDocument {
title : String
version : String
verdict : DocumentSeverity
sections : Array[DocumentSection]
generated_by : String
} derive(Debug)fn AnalysisDocument::add_line(self : AnalysisDocument, kind : DocumentSectionKind, line : String) -> AnalysisDocumentfn AnalysisDocument::add_metric(self : AnalysisDocument, kind : DocumentSectionKind, metric : DocumentMetric) -> AnalysisDocumentfn AnalysisDocument::add_section(self : AnalysisDocument, section : DocumentSection) -> AnalysisDocumentfn AnalysisDocument::with_verdict(self : AnalysisDocument, version : String, verdict : DocumentSeverity) -> AnalysisDocumentpub struct AnalysisWorkflow {
trace : Trace
options : WorkflowOptions
stages : Array[WorkflowStageResult]
index : TraceIndex?
windows : Array[TraceWindow]
coverage : CoverageReport?
assertions : AssertionSummary?
protocol_stats : Array[ProtocolStats]
passed : Bool
} derive(Debug)pub struct AssertionSummary {
total : Int
passed : Int
failed : Int
fatal : Int
violations : Array[AssertionViolation]
} derive(Debug)pub struct AssertionViolation {
name : String
kind : AssertionKind
signal_id : String
time : Int64
end_time : Int64
severity : AssertionSeverity
observed : String
expected : String
message : String
} derive(Eq, Debug)pub struct CheckpointSet {
trace_digest : Int64
checkpoints : Array[TraceCheckpoint]
ordered : Bool
} derive(Debug)pub struct ClockReport {
signal_id : String
edge_count : Int
cycle_count : Int
missing_falling_edges : Int
missing_next_edges : Int
periods : Array[Int64]
minimum_period : Int64?
maximum_period : Int64?
mean_period : Double?
period_jitter : Double?
mean_duty_cycle : Double?
out_of_tolerance : Int
} derive(Debug)pub struct CoverageBin {
group : String
key : String
label : String
kind : CoverageKind
hits : Int
target : Int
first_time : Int64?
last_time : Int64?
} derive(Debug)pub struct CoverageReport {
name : String
bins : Array[CoverageBin]
observations : Int
covered : Int
target : Int
score : Double
} derive(Debug)pub struct DependencyReport {
dependencies : Array[SignalDependency]
signal_count : Int
observation_count : Int
threshold : Int64
} derive(Debug)pub enum DerivedExpr {
SignalRef(String)
Constant(Value)
Not(DerivedExpr)
And(DerivedExpr, DerivedExpr)
Or(DerivedExpr, DerivedExpr)
Xor(DerivedExpr, DerivedExpr)
Add(DerivedExpr, DerivedExpr)
Sub(DerivedExpr, DerivedExpr)
Concat(DerivedExpr, DerivedExpr)
ShiftLeft(DerivedExpr, Int)
ShiftRight(DerivedExpr, Int)
Mux(DerivedExpr, DerivedExpr, DerivedExpr)
SampleAt(DerivedExpr, Int64)
EdgeRise(String)
EdgeFall(String)
} derive(Eq, Debug)pub struct DerivedSignalSpec {
id : String
name : String
width : Int
kind : String
expr : DerivedExpr
} derive(Eq, Debug)pub struct DocumentMetric {
name : String
value : String
unit : String?
severity : DocumentSeverity
} derive(Debug)pub struct DocumentSection {
kind : DocumentSectionKind
title : String
summary : String
metrics : Array[DocumentMetric]
lines : Array[String]
} derive(Debug)pub struct GraphEdge {
from : String
to : String
kind : GraphEdgeKind
weight : Int
evidence : String
} derive(Debug)pub struct GraphNode {
id : String
kind : GraphNodeKind
label : String
signal_id : String?
time : Int64?
weight : Int
} derive(Debug)pub struct Header {
date : String?
version : String?
timescale : String?
comment : String?
} derive(Debug)pub struct I2cByte {
index : Int
time : Int64
value : Int
text : String
address : Bool
read : Bool
acknowledged : Bool?
bit_count : Int
} derive(Debug)pub struct I2cConfig {
clock : String
data : String
address_bits : Int
include_ack : Bool
address_is_seven_bit : Bool
} derive(Debug)pub struct I2cReport {
config : I2cConfig
transactions : Array[I2cTransaction]
events : Int
bytes : Int
acknowledged : Int
not_acknowledged : Int
first_time : Int64?
last_time : Int64?
} derive(Debug)pub struct MergeOptions {
mode : MergeTimeMode
offset : Int64
align_signal : String?
include_duplicate_changes : Bool
rename_conflicts : Bool
sort_changes : Bool
} derive(Eq, Debug)pub struct MonitorFinding {
channel : String
rule : MonitorRule
severity : MonitorSeverity
transaction_index : Int?
time : Int64
observed : String
expected : String
message : String
} derive(Debug)pub struct MonitorOptions {
require_completed : Bool
maximum_latency : Int64?
minimum_gap : Int64?
require_payload : Bool
require_acceptance : Bool
minimum_throughput : Double?
} derive(Debug)pub struct MonitorReport {
channel : String
transactions : Array[ProtocolTransaction]
findings : Array[MonitorFinding]
passed : Bool
score : Int
} derive(Debug)fn MonitorReport::findings_by_severity(self : MonitorReport, severity : MonitorSeverity) -> Array[MonitorFinding]pub struct PacketField {
name : String
lsb : Int
width : Int
signed : Bool
display : String
} derive(Debug)pub struct PacketLayout {
name : String
total_bits : Int
fields : Array[PacketField]
byte_order : String
} derive(Debug)fn PacketLayout::with_field(self : PacketLayout, name : String, lsb : Int, width : Int, signed : Bool) -> PacketLayoutpub struct PacketRecord {
index : Int
time : Int64
payload : Value?
fields : Array[PacketFieldValue]
valid : Bool
error : String?
} derive(Debug)pub struct PipelineResult {
stage : PipelineStage
ok : Bool
items : Int
detail : String
} derive(Eq, Debug)pub struct ProfileMetric {
signal_id : String
kind : ProfileMetricKind
value : Double?
count : Int?
unit : String
quality : Int
} derive(Debug)pub struct ProtocolChannel {
name : String
mode : ProtocolMode
clock_id : String?
valid_id : String?
ready_id : String?
request_id : String?
response_id : String?
payload_id : String?
reset_id : String?
active_high : Bool
minimum_gap : Int64
} derive(Eq, Debug)pub struct ProtocolReplay {
channel : String
steps : Array[ReplayStep]
accepted : Int
rejected : Int
incomplete : Int
final_state : String
deterministic : Bool
} derive(Debug)pub struct QueryPlanNode {
index : Int
kind : QueryPlanNodeKind
input_rows : Int
output_rows : Int
estimated_cost : Double
detail : String
} derive(Debug)pub struct QueryPlanV2 {
predicates : Array[QueryPredicate]
signals : Array[String]
limit : Int?
nodes : Array[QueryPlanNode]
estimated_rows : Int
estimated_cost : Double
} derive(Debug)pub struct QueryPredicate {
kind : QueryPredicateKind
field : String
argument : String
lower : Int64?
upper : Int64?
} derive(Debug)pub struct QueryResultV2 {
trace : Trace
scanned_rows : Int
returned_rows : Int
elapsed_units : Int64
plan : QueryPlanV2
} derive(Debug)pub struct RegressionReportV2 {
comparison : RegressionComparison
findings : Array[RegressionFinding]
compared_signals : Int
compared_changes : Int
passed : Bool
score : Int
} derive(Debug)fn RegressionReportV2::for_signal(self : RegressionReportV2, signal_id : String) -> Array[RegressionFinding]pub struct RepairFinding {
rule : RepairRule
level : RepairFindingLevel
signal_id : String?
time : Int64?
message : String
} derive(Debug)pub struct RepairOptions {
rules : Array[RepairRule]
preserve_unknown_values : Bool
end_time : Int64?
deduplicate_changes : Bool
} derive(Debug)pub struct RepairResult {
trace : Trace
findings : Array[RepairFinding]
changed : Bool
rejected_changes : Int
repaired_changes : Int
} derive(Debug)pub struct ReplayStep {
index : Int
start : Int64
end : Int64
state_before : String
state_after : String
outcome : ReplayOutcome
payload : Value?
note : String
} derive(Debug)pub struct ReportOptions {
format : ReportFormat
include_changes : Bool
include_validation : Bool
signal_pattern : String?
} derive(Eq, Debug)pub struct SampledTrace {
source_end : Int64
config : SamplingConfig
points : Array[SamplingPoint]
sample_count : Int
known_count : Int
} derive(Debug)pub struct SamplingConfig {
start : Int64
end : Int64
step : Int64
mode : SamplingMode
include_unknown : Bool
} derive(Debug)pub struct SchemaFinding {
signal_id : String
constraint : SchemaConstraint
valid : Bool
observed : String
expected : String
message : String
} derive(Debug)pub struct SignalDependency {
source_id : String
target_id : String
kind : DependencyKind
evidence_count : Int
average_lag : Double
confidence : Double
first_time : Int64?
last_time : Int64?
} derive(Debug)pub struct SignalRun {
signal_id : String
start : Int64
end : Int64
token : String
duration : Int64
change_count : Int
} derive(Debug)pub struct SignalSchema {
signal_id : String
path : String
declared_width : Int
observed_width : Int
kind : String
constraints : Array[SchemaConstraint]
samples : Int
valid : Bool
} derive(Debug)pub struct SignalStats {
changes : Int
first_time : Int64?
last_time : Int64?
rising_edges : Int
falling_edges : Int
unknown_values : Int
} derive(Debug)pub struct SpiConfig {
clock : String
chip_select : String
mosi : String?
miso : String?
polarity : SpiPolarity
phase : SpiPhase
order : SpiBitOrder
word_bits : Int
active_low : Bool
} derive(Debug)pub struct SpiWord {
index : Int
start_time : Int64
end_time : Int64
clock_edges : Int
mosi_bits : String
miso_bits : String
mosi_value : Int64?
miso_value : Int64?
complete : Bool
chip_select_active : Bool
} derive(Debug)pub struct SynthPlan {
end_time : Int64
signals : Array[SynthSignal]
timescale : String
} derive(Debug)fn SynthPlan::with_signal(self : SynthPlan, id : String, name : String, width : Int, pattern : SynthPattern, period : Int64) -> SynthPlanpub struct SynthSignal {
id : String
name : String
width : Int
pattern : SynthPattern
period : Int64
phase : Int64
seed : Int64
} derive(Debug)pub struct TraceArtifact {
name : String
kind : TraceArtifactKind
format : String
bytes : Int
digest : Int64
ready : Bool
} derive(Debug)pub struct TraceCache {
policy : TraceCachePolicy
entries : Array[TraceCacheEntry]
lookups : Int
hits : Int
misses : Int
capacity : Int
} derive(Debug)fn TraceCache::value_at(self : TraceCache, trace : Trace, signal_id : String, time : Int64) -> (TraceCache, Value?)pub struct TraceCatalogV2 {
items : Array[TraceCatalogItem]
total_signals : Int
total_changes : Int
total_duration : Int64
} derive(Debug)pub struct TraceDistribution {
signal_id : String
sample_count : Int
distinct_tokens : Int
minimum_run : Int64?
maximum_run : Int64?
mean_run : Double?
median_run : Int64?
p95_run : Int64?
entropy : Double
transition_rate : Double
} derive(Debug)fn TraceIndex::between(self : TraceIndex, trace : Trace, signal_id : String, start~ : Int64, end~ : Int64) -> Array[Change]fn TraceIndex::value_at(self : TraceIndex, trace : Trace, signal_id : String, timestamp : Int64) -> Value?pub struct TracePackage {
descriptor : TracePackageDescriptor
manifest : TraceManifest
readme : String
} derive(Debug)pub struct TracePipeline {
source : SourceStatistics
trace : Trace?
results : Array[PipelineResult]
} derive(Debug)pub struct TraceProfile {
trace_end : Int64
signal_count : Int
metrics : Array[ProfileMetric]
quality : Int
} derive(Debug)fn TraceProfile::metric(self : TraceProfile, signal_id : String, kind : ProfileMetricKind) -> ProfileMetric?pub struct TraceSchemaReport {
version : String
entries : Array[SignalSchema]
findings : Array[SchemaFinding]
valid : Bool
} derive(Debug)pub struct TraceSliceRequest {
name : String
start : Int64
end : Int64
signal_ids : Array[String]
context : SliceContext
keep_empty : Bool
} derive(Debug)fn TraceSliceRequest::with_context(self : TraceSliceRequest, context : SliceContext) -> TraceSliceRequestfn TraceSliceRequest::with_signals(self : TraceSliceRequest, signal_ids : Array[String]) -> TraceSliceRequestpub struct UartConfig {
signal_id : String
bit_period : Int64
data_bits : Int
stop_bits : Int
parity : UartParity
idle_high : Bool
sample_offset : Int64
lsb_first : Bool
} derive(Eq, Debug)pub struct WaveformAssertion {
name : String
kind : AssertionKind
signal_id : String
companion_id : String?
start : Int64
end : Int64
limit : Int64
lower : Int64
upper : Int64
severity : AssertionSeverity
message : String
} derive(Eq, Debug)pub struct WindowPlan {
source_start : Int64
source_end : Int64
windows : Array[TraceWindow]
policy : WindowPolicy
dropped_changes : Int
} derive(Debug)pub struct WindowSpec {
policy : WindowPolicy
width : Int64
count : Int
overlap : Int64
minimum_changes : Int
include_empty : Bool
} derive(Eq, Debug)pub struct WorkflowOptions {
window_width : Int64
coverage_signal_ids : Array[String]
assertions : Array[WaveformAssertion]
protocol_channels : Array[ProtocolChannel]
stop_on_failure : Bool
} derive(Debug)fn WorkflowOptions::with_assertion(self : WorkflowOptions, assertion : WaveformAssertion) -> WorkflowOptionsfn WorkflowOptions::with_coverage_signal(self : WorkflowOptions, signal_id : String) -> WorkflowOptionsfn WorkflowOptions::with_protocol(self : WorkflowOptions, channel : ProtocolChannel) -> WorkflowOptionspub struct WorkflowStageResult {
stage : WorkflowStage
status : WorkflowStageStatus
duration_units : Int64
rows : Int
message : String
} derive(Debug)fn activity_coverage_bins(trace : Trace, bucket_width : Int64, threshold : Int) -> Array[CoverageBin]fn align_traces(left : Trace, right : Trace, left_marker : String?, right_marker : String?, mode : AlignmentMode) -> AlignmentResultfn apb_config(pclk : String, psel : String, penable : String, pwrite : String, paddr : String) -> ApbConfigfn artifact_format_supported(format : String) -> Boolfn assert_known(name : String, signal_id : String, start : Int64, end : Int64, severity : AssertionSeverity) -> WaveformAssertionfn assert_minimum_gap(name : String, signal_id : String, gap : Int64, severity : AssertionSeverity) -> WaveformAssertionfn assert_minimum_pulse(name : String, signal_id : String, width : Int64, severity : AssertionSeverity) -> WaveformAssertionfn assert_monotonic(name : String, signal_id : String, severity : AssertionSeverity) -> WaveformAssertionfn assert_no_activity(name : String, signal_id : String, start : Int64, end : Int64, severity : AssertionSeverity) -> WaveformAssertionfn assert_one_hot(name : String, signal_id : String, severity : AssertionSeverity) -> WaveformAssertionfn assert_response_within(name : String, request_id : String, response_id : String, limit : Int64, severity : AssertionSeverity) -> WaveformAssertionfn assert_stable(name : String, signal_id : String, start : Int64, end : Int64, severity : AssertionSeverity) -> WaveformAssertionfn assert_unsigned_range(name : String, signal_id : String, lower : Int64, upper : Int64, severity : AssertionSeverity) -> WaveformAssertionfn cdc_observations(trace : Trace, source_id : String, destination_id : String, guard_band : Int64) -> Array[CdcObservation]fn cli_usage() -> Stringfn clock_fixture(period : Int, cycles : Int) -> Stringfn compare_regression_v2(left : Trace, right : Trace, comparison : RegressionComparison, tolerance : Int64) -> RegressionReportV2fn correlate_rising_edges(trace : Trace, source_signal : String, target_signal : String, maximum_latency : Int64) -> Array[LatencySample]fn coverage_bin(group : String, key : String, label : String, kind : CoverageKind, target : Int) -> CoverageBinfn coverage_report(name : String, trace : Trace, include_values : Bool, include_transitions : Bool, include_toggles : Bool, include_widths : Bool, include_activity : Bool) -> CoverageReportfn decode_value_token(token : String, signal_id : String, time : Int64) -> Result[Change, ParseError]fn derived_mux(condition : DerivedExpr, when_true : DerivedExpr, when_false : DerivedExpr) -> DerivedExprfn directive_inventory(input : String) -> Stringfn document_metric(name : String, value : String, unit : String?, severity : DocumentSeverity) -> DocumentMetricfn document_section(kind : DocumentSectionKind, title : String, summary : String) -> DocumentSectionfn edge_fixture() -> Stringfn ensure_final_newline(input : String) -> Stringfn escape_text(text : String) -> Stringfn estimate_alignment(left : Trace, right : Trace, left_marker : String?, right_marker : String?, mode : AlignmentMode) -> AlignmentEstimatefn find_analysis_metric(metrics : Array[AnalysisMetric], signal_id : String, name : String) -> AnalysisMetric?fn fixture_expectations(name : String) -> (Int, Int)fn fixture_size(name : String) -> Intfn fixture_size_report(signal_count : Int, time_count : Int) -> Stringfn fixture_validation_report() -> Stringfn fixture_workload_report() -> Stringfn fixtures_meet_expectations() -> Boolfn glob_matches(pattern : String, text : String) -> Boolfn has_complete_definition_block(input : String) -> Boolfn has_dumpvars(source : String) -> Boolfn hierarchy_fixture() -> Stringfn is_known_scalar(value : Char) -> Boolfn is_logic_char(value : Char) -> Boolfn is_vcd_directive(line : String) -> Boolfn is_vcd_timestamp(line : String) -> Boolfn latency_report(trace : Trace, source_signal : String, target_signal : String, maximum_latency : Int64) -> LatencyReportfn looks_like_vcd(input : String) -> Boolfn make_trace_patch(trace : Trace, source : String, start : Int64, end : Int64, selection : MergeSelection) -> TracePatchfn malformed_fixture() -> Stringfn minimal_fixture() -> Stringfn mixed_fixture() -> Stringfn monitor_protocol(trace : Trace, channel : ProtocolChannel, options : MonitorOptions) -> MonitorReportfn multi_signal_fixture(signal_count : Int, time_count : Int) -> Stringfn normalize_vcd_text(input : String) -> Stringfn normalized_text_equal(left : String, right : String) -> Boolfn parser_counters(input : String) -> (Int, Int, Int)fn physical_line_count(input : String) -> Intfn replay_protocol(channel : ProtocolChannel, transactions : Array[ProtocolTransaction]) -> ProtocolReplayfn request_response_channel(name : String, request_id : String, response_id : String, payload_id : String?) -> ProtocolChannelfn sample_trace_signal(trace : Trace, signal_id : String, config : SamplingConfig) -> Array[SamplingPoint]fn synthetic_vcd(signal_count : Int, time_count : Int) -> Stringfn text_diagnostic(input : String) -> Stringfn trace_artifact(name : String, kind : TraceArtifactKind, format : String, content : String) -> TraceArtifactfn trace_catalog_item(name : String, category : String, description : String, trace : Trace, tags : Array[String]) -> TraceCatalogItemfn trigger_hits(trace : Trace, signal_id : String, condition : TriggerCondition) -> Array[TriggerHit]fn trigger_window(trace : Trace, signal_id : String, condition : TriggerCondition, before : Int64, after : Int64) -> Array[(Int64, Int64)]fn unmatched_rising_edges(trace : Trace, source_signal : String, target_signal : String, maximum_latency : Int64) -> Array[LatencySample]fn valid_ready_channel(name : String, clock_id : String, valid_id : String, ready_id : String, payload_id : String?) -> ProtocolChannelInstall
Download zipStreaming-friendly VCD waveform parser and digital signal analysis toolkit for MoonBit