Class: VCD::Reader

Inherits:
Object
  • Object
show all
Defined in:
lib/libfst/vcd.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(io) ⇒ Reader

Returns a new instance of Reader.

Parameters:

  • io (String, IO)

    either a file name or an opened IO.



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/libfst/vcd.rb', line 137

def initialize(io)
  @io_is_file = false
  if io.is_a?(String) then
    @io_is_file = true
    @io = File.open(io)
  else
    @io = io
  end
  @buf = []
  @root = Scope.new('root', :module, nil)
  @scope_stack = [@root]
  @state = :process_definitions
  @comments = []
  @stop_parsing = false
  @io.each_line do |line|
    process_line(line.chomp)
    break if @stop_parsing
  end
  if @io_is_file then
    @io.close 
    @io = io
  end

  remove_instance_variable :@stop_parsing
  remove_instance_variable :@state
  remove_instance_variable :@buf
  remove_instance_variable :@scope_stack

  @on_comment = nil
  @on_time_change = nil
end

Instance Attribute Details

#commentsArray<String> (readonly)

Returns:

  • (Array<String>)


130
131
132
# File 'lib/libfst/vcd.rb', line 130

def comments
  @comments
end

#dateString? (readonly)

Returns:

  • (String, nil)


128
129
130
# File 'lib/libfst/vcd.rb', line 128

def date
  @date
end

#rootScope (readonly)

Returns:



132
133
134
# File 'lib/libfst/vcd.rb', line 132

def root
  @root
end

#timescaleFloat (readonly)

Returns:

  • (Float)


131
132
133
# File 'lib/libfst/vcd.rb', line 131

def timescale
  @timescale
end

#tracesHash{String => Trace} (readonly)

Returns Traces stored by ID.

Returns:

  • (Hash{String => Trace})

    Traces stored by ID



133
134
135
# File 'lib/libfst/vcd.rb', line 133

def traces
  @traces
end

#versionString? (readonly)

Returns:

  • (String, nil)


129
130
131
# File 'lib/libfst/vcd.rb', line 129

def version
  @version
end

Instance Method Details

#[](path) ⇒ Scope, ...

Returns the scope or variable corresponding to the specified path

Parameters:

  • path (String)

Returns:

Raises:

  • (ArgumentError)


186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/libfst/vcd.rb', line 186

def [](path)
  return @root if path == '/'
  raise ArgumentError, "expecting a String, not a #{path.class}" unless path.is_a?(String)
  a = path.split('/').reject(&:empty?)
  return nil if a.empty?
  scope = @root
  var = nil
  a.each do |w|
    var = scope.variables.select{ |v| v.name == w }.first
    return var if var
    s = scope.children.select{ |v| v.name == w }.first
    return nil if s.nil?
    scope = s
  end
  scope
end

#on_comment {|comment, time, vcd| ... } ⇒ self

Set the block of code to be executed when a comment is found while reading the value change section of the file

Yield Parameters:

  • comment (String)
  • time (Integer)

    this integer is to be multiplied with #timescale the get the real time

  • vcd (self)

Returns:

  • (self)


209
210
211
212
# File 'lib/libfst/vcd.rb', line 209

def on_comment(&block)
  @on_comment = block
  self
end

#on_time_change {|time, vcd| ... } ⇒ self

Set the block of code to be called when a time change is encountered.

Yield Parameters:

  • time (Integer)

    this integer is to be multiplied with #timescale the get the real time

  • vcd (self)

Returns:

  • (self)


219
220
221
222
# File 'lib/libfst/vcd.rb', line 219

def on_time_change(&block)
  @on_time_change = block
  self
end

#pretty_time(t = nil) ⇒ String?

When called in one of the callbacks, returns the current time as a string, nil otherwise.

Parameters:

  • t (Integer, nil) (defaults to: nil)

Returns:

  • (String, nil)

    example: "2.57 µs"



329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
# File 'lib/libfst/vcd.rb', line 329

def pretty_time(t = nil)
  t ||= @time
  return nil unless t
  return '0 s' if t == 0
  e = Math.log10(@timescale).round
  while (-e % 3) != 0 do
    t *= 10
    e -= 1
  end
  while e < -15 do
    t /= 10
    e += 1
  end

  while e < 0 and (t % 1000) == 0 do
    t /= 1000
    e += 3
  end

  ent = t
  qe = e
  mf = 1
  while qe < 0 and (ent / 1000) != 0 do
    ent /= 1000
    qe += 3
    mf *= 1000
  end

  rem = t - mf*ent
  while rem != 0 and (rem % 10) == 0 do
    rem /= 10
    e += 1
  end

  s = ent.to_s
  if rem != 0 then
    s += '.' + rem.to_s.rjust(qe - e, '0')
  end
  s += case qe
       when   0; ' s'
       when  -3; ' ms'
       when  -6; ' µs'
       when  -9; ' ns'
       when -12; ' ps'
       when -15; ' fs'
       else
         raise "unknown unit for exponent #{qe}"
       end
  s
end

#read(*signals, start_time: nil, end_time: nil) {|trace, value, time, vcd| ... } ⇒ self

Read the value change section of the VCD file.

Parameters:

  • signals (Trace, Variable, Scope, String)

    if signals are specified, only those will trigger the block. A path can be provided as a string, which correspond to a Variable or a Scope. In the case of a Scope, all its variables will be added (NOT recursively).

  • start_time (Integer, Float, String, nil) (defaults to: nil)

    start time from which to trigger the block

  • end_time (Integer, Float, String, nil) (defaults to: nil)

    end time until which to trigger the block

Yield Parameters:

  • trace (Trace)
  • value (String, Float)
  • time (Integer)

    this integer is to be multiplied with #timescale the get the real time

  • vcd (self)

Returns:

  • (self)


245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# File 'lib/libfst/vcd.rb', line 245

def read(*signals, start_time: nil, end_time: nil, &block)
  @time_win_start = nil
  @time_win_end = nil
  @trace_mask = nil

  @time_win_start = time_to_itime(start_time, false) if start_time
  @time_win_end   = time_to_itime(end_time,   true)  if end_time

  unless signals.empty? then
    @trace_mask = {}
    signals.each do |sig|
      if sig.is_a?(String) then
        s = self[sig] 
        raise "Cannot find #{sig.inspect} in the hierarchy" if s.nil?
        sig = s
      end
      case sig
      when Variable
        @trace_mask[sig.trace.id] = true
      when Trace
        @trace_mask[sig.id] = true
      when Scope
        sig.variables.each do |var|
          @trace_mask[var.trace.id] = true
        end
      else
        raise TypeError, "Expecting a path, a #{Variable}, a #{Trace} or a #{Scope}, not a #{sig.class}"
      end
    end
  end

  @on_read = block

  if @io_is_file then
    io = @io
    @io = File.open(io)
    @io.seek(@value_change_pos, IO::SEEK_SET)
  end

  @stop_parsing = false
  @state = nil
  @buf = nil
  @time = 0

  @io.each_line do |line|
    process_line(line.chomp)
    break if @stop_parsing
  end

  remove_instance_variable :@time_win_start
  remove_instance_variable :@time_win_end
  remove_instance_variable :@trace_mask
  remove_instance_variable :@on_read
  remove_instance_variable :@stop_parsing
  remove_instance_variable :@state
  remove_instance_variable :@buf

  if @io_is_file then
    @io.close 
    @io = io
  end

  @time = nil
end

#real_timeFloat?

When called in one of the callbacks, returns the current time in seconds, nil otherwise.

Returns:

  • (Float, nil)


320
321
322
323
# File 'lib/libfst/vcd.rb', line 320

def real_time
  return nil unless @time
  @time*@timescale
end

#stop_parsingself

Stop the parsing of the file. This method can be called from an #on_comment or #read block.

Returns:

  • (self)


228
229
230
231
# File 'lib/libfst/vcd.rb', line 228

def stop_parsing
  @stop_parsing = true
  self
end

#timeInteger?

When called in one of the callbacks, returns the current time as an integer, nil otherwise.

Returns:

  • (Integer, nil)

    this value is to be multiplied with #timescale the get the real time



313
314
315
# File 'lib/libfst/vcd.rb', line 313

def time
  @time
end

#to_sString

Returns:

  • (String)


382
383
384
385
386
387
388
389
390
391
# File 'lib/libfst/vcd.rb', line 382

def to_s
  [
    "Date:      #{@date.inspect}",
    "Version:   #{@version.inspect}",
    "Timescale: #{@timescale}",
    "Comments:",
    @comments.collect{|s| "    " + s.inspect},
    @root.tree
  ].flatten.join("\n")
end

#variable(name) ⇒ Variable?

Find a Variable by its name or path

Parameters:

  • name (String)

    name or path to look for

Returns:



173
174
175
176
177
178
179
180
# File 'lib/libfst/vcd.rb', line 173

def variable(name)
  @traces.each_value do |t|
    t.variables.each do |v|
      return v if v.name == name or v.path == name
    end
  end
  nil
end