internal static void VisitSimCmd(VCDLexer lexer, IDToVarDef idToVariable, SimPass pass, BitAllocator bitAlloc) { ReadOnlyMemory <byte> declWordMem = lexer.NextWordAsMem(); ReadOnlySpan <byte> declWord = declWordMem.Span; ReadOnlySpan <byte> endToken = new byte[] { (byte)'$', (byte)'e', (byte)'n', (byte)'d' }; ReadOnlySpan <byte> commentToken = new byte[] { (byte)'$', (byte)'c', (byte)'o', (byte)'m', (byte)'m', (byte)'e', (byte)'n', (byte)'t' }; ReadOnlySpan <byte> dumpAllToken = new byte[] { (byte)'$', (byte)'d', (byte)'u', (byte)'m', (byte)'p', (byte)'a', (byte)'l', (byte)'l' }; ReadOnlySpan <byte> dumpOffToken = new byte[] { (byte)'$', (byte)'d', (byte)'u', (byte)'m', (byte)'p', (byte)'o', (byte)'f', (byte)'f' }; ReadOnlySpan <byte> dumpOnToken = new byte[] { (byte)'$', (byte)'d', (byte)'u', (byte)'m', (byte)'p', (byte)'o', (byte)'n' }; ReadOnlySpan <byte> dumpVarsToken = new byte[] { (byte)'$', (byte)'d', (byte)'u', (byte)'m', (byte)'p', (byte)'v', (byte)'a', (byte)'r', (byte)'s' }; ReadOnlySpan <byte> hashtagToken = new byte[] { (byte)'#' }; //It may be the case that it's first discovered now that // the end of the file has been reached. if (declWord.Length == 0) { if (lexer.IsWordsRemaining()) { throw new Exception("Invalid simulation command."); } return; } if (declWord.SequenceEqual(commentToken)) { string text = lexer.NextUntil(endToken).ToCharString(); lexer.ExpectNextWord(endToken); pass.SimCmd = new Comment(text); } else if (declWord.SequenceEqual(dumpAllToken)) { pass.SimCmd = new DumpAll(VisitValueChangeStream(lexer, idToVariable, pass, bitAlloc)); } else if (declWord.SequenceEqual(dumpOffToken)) { pass.SimCmd = new DumpOff(VisitValueChangeStream(lexer, idToVariable, pass, bitAlloc)); } else if (declWord.SequenceEqual(dumpOnToken)) { pass.SimCmd = new DumpOn(VisitValueChangeStream(lexer, idToVariable, pass, bitAlloc)); } else if (declWord.SequenceEqual(dumpVarsToken)) { pass.SimCmd = new DumpVars(VisitValueChangeStream(lexer, idToVariable, pass, bitAlloc)); } else if (declWord.StartsWith(hashtagToken)) { pass.SimCmd = VisitSimTime(declWord); } else { VisitValueChange(lexer, declWordMem, idToVariable, pass, bitAlloc); } }
public VCDTimeline(VCD vcd) { this.TimeScale = vcd.Time; var simCommands = vcd.GetSimulationCommands(); SimPass firstCmd = simCommands.First(); CircuitState segmentStartState; if (firstCmd.SimCmd is DumpVars initDump) { segmentStartState = new CircuitState(initDump); } else { segmentStartState = new CircuitState(vcd.Variables.ToList()); simCommands = simCommands.Prepend(firstCmd); } CircuitState followState = segmentStartState.Copy(); ulong startTime = 0; const int maxChangesPerSegment = 100_000; List <BinaryVarValue> binChanges = new List <BinaryVarValue>(maxChangesPerSegment); List <TimeStepChanges> stepChanges = new List <TimeStepChanges>(); int currTimeStepStart = 0; int currTimeStepLength = 0; foreach (var simCmd in simCommands) { if (simCmd.SimCmd is SimTime time) { if (currTimeStepLength > 0) { StateCount++; TimeStepChanges timeStep = new TimeStepChanges(startTime, currTimeStepStart, currTimeStepLength); currTimeStepStart += currTimeStepLength; currTimeStepLength = 0; stepChanges.Add(timeStep); //If segment is full then store the segment and //prepare for the next segment if (binChanges.Count > maxChangesPerSegment) { TimeSpan tSpan = new TimeSpan(stepChanges.First().Time, time.Time); SegmentChanges.Add(new TimeSegmentChanges(tSpan, segmentStartState, binChanges.ToArray(), stepChanges)); currTimeStepStart = 0; currTimeStepLength = 0; segmentStartState = followState; followState = segmentStartState.Copy(); binChanges.Clear(); stepChanges = new List <TimeStepChanges>(); } } startTime = time.Time; } else if (simCmd.BinValue.HasValue) { followState.AddChange(simCmd.BinValue.Value); binChanges.Add(simCmd.BinValue.Value); currTimeStepLength++; } } //Add last segment if it's not empty. //Segment isn't added by above loop if the vcd file doesn't //end with a simulation time command. if (currTimeStepLength > 0) { stepChanges.Add(new TimeStepChanges(startTime, currTimeStepStart, currTimeStepLength)); } if (stepChanges.Count > 0) { TimeSpan tSpan = new TimeSpan(stepChanges.First().Time, stepChanges.Last().Time + 1); SegmentChanges.Add(new TimeSegmentChanges(tSpan, segmentStartState, binChanges.ToArray(), stepChanges)); } this.TimeInterval = new TimeSpan(SegmentChanges.First().TimeInterval.StartInclusive, SegmentChanges.Last().TimeInterval.EndExclusive); }
internal static void VisitScalarValueChange(ReadOnlyMemory <byte> text, IDToVarDef idToVariable, SimPass pass, BitAllocator bitAlloc) { UnsafeMemory <BitState> bits = bitAlloc.GetBits(1); BitState bit = ToBitState(text.Span[0]); var id = text.Slice(1); bits.Span[0] = bit; if (idToVariable.TryGetValue(id, out List <VarDef>?variable)) { pass.BinValue = new BinaryVarValue(bits, variable, ((int)bit & 0b10) == 0); } else { throw new Exception($"Unknown variable identifier: {id}"); } }
internal static void VisitRealVectorValueChange(VCDLexer lexer, ReadOnlySpan <byte> valueText, IDToVarDef idToVariable, SimPass pass, BitAllocator bitAlloc) { Span <char> chars = stackalloc char[valueText.Length]; valueText.CopyToCharArray(chars); double value = double.Parse(chars, NumberStyles.Float, CultureInfo.InvariantCulture); var id = lexer.NextWordAsMem(); if (idToVariable.TryGetValue(id, out List <VarDef>?variable)) { pass.RealValue = new RealVarValue(value, variable); } else { throw new Exception($"Unknown variable identifier: {id}"); } }
internal static void VisitBinaryVectorValueChange(VCDLexer lexer, ReadOnlySpan <byte> valueText, IDToVarDef idToVariable, SimPass pass, BitAllocator bitAlloc) { (UnsafeMemory <BitState> bits, bool isValidBinary) = ToBitStates(valueText, bitAlloc); var id = lexer.NextWordAsMem(); if (idToVariable.TryGetValue(id, out List <VarDef>?variables)) { pass.BinValue = new BinaryVarValue(bits, variables, isValidBinary); } else { throw new Exception($"Unknown variable identifier: {id}"); } }
internal static void VisitValueChange(VCDLexer lexer, ReadOnlyMemory <byte> text, IDToVarDef idToVariable, SimPass pass, BitAllocator bitAlloc) { if (text.Length < 2) { throw new Exception($"Invalid value change: {text.ToString()}"); } ReadOnlySpan <byte> textSpan = text.Span; if (textSpan[0] == 'b' || textSpan[0] == 'B') { VisitBinaryVectorValueChange(lexer, textSpan.Slice(1), idToVariable, pass, bitAlloc); } else if (textSpan[0] == 'r' || textSpan[0] == 'R') { VisitRealVectorValueChange(lexer, textSpan.Slice(1), idToVariable, pass, bitAlloc); } else { VisitScalarValueChange(text, idToVariable, pass, bitAlloc); } }
internal static List <VarValue> VisitValueChangeStream(VCDLexer lexer, IDToVarDef idToVariable, SimPass pass, BitAllocator bitAlloc) { List <VarValue> changes = new List <VarValue>(); while (!lexer.IsEmpty()) { ReadOnlyMemory <byte> text = lexer.NextWordAsMem(); ReadOnlySpan <byte> endToken = new byte[] { (byte)'$', (byte)'e', (byte)'n', (byte)'d' }; if (text.Span.SequenceEqual(endToken)) { break; } VisitValueChange(lexer, text, idToVariable, pass, bitAlloc); if (pass.BinValue.HasValue) { changes.Add(pass.BinValue); } else if (pass.RealValue.HasValue) { changes.Add(pass.RealValue); } else { throw new Exception("Expected to read a value change but found none."); } } pass.Reset(); return(changes); }