class Origen::Generator::PatternThread

An instance of PatternThread is created for each parallel thread of execution in a pattern sequence. One instance of this class is also created to represent the original main thread in addition to those created by calling seq.in_parallel

Attributes

cycle_count_start[R]
cycle_count_stop[R]
events[R]

A record of when the thread is active to construct the execution profile

id[R]
pending_cycles[R]
reservations[R]
sequence[R]

Returns the parent pattern sequence object

Public Class Methods

new(id, sequence, block, primary = false, pre_block = nil) click to toggle source
# File lib/origen/generator/pattern_thread.rb, line 17
def initialize(id, sequence, block, primary = false, pre_block = nil)
  if primary
    @cycle_count_start = 0
  else
    @cycle_count_start = current_cycle_count
  end
  @events = [[:active, cycle_count_start]]
  @id = id.to_sym
  @sequence = sequence
  @block = block
  @pre_block = pre_block
  @primary = primary
  @running = Concurrent::Event.new
  @waiting = Concurrent::Event.new
  @pending_cycles = nil
  @completed = false
  @reservations = {}
end

Public Instance Methods

advance(completed_cycles = nil) click to toggle source

This should be called only by the pattern sequence running in the main thread, it will un-block the pattern thread which is currently waiting, and it will block the main thread until the pattern thread reaches the next wait point (or completes)

# File lib/origen/generator/pattern_thread.rb, line 170
def advance(completed_cycles = nil)
  @waiting.reset
  @running.set         # Release the pattern thread
  @waiting.wait        # And wait for it to reach the next wait point
end
completed?() click to toggle source
# File lib/origen/generator/pattern_thread.rb, line 150
def completed?
  @completed
end
current_cycle_count() click to toggle source
# File lib/origen/generator/pattern_thread.rb, line 70
def current_cycle_count
  tester.try(:cycle_count) || 0
end
cycle(options) click to toggle source

Will be called when the thread is ready for the next cycle

# File lib/origen/generator/pattern_thread.rb, line 124
def cycle(options)
  @pending_cycles = options[:repeat] || 1
  # If there are threads pending start and we are about to enter a long delay, block for only
  # one cycle to give them a change to get underway and make use of this delay
  if @pending_cycles > 1 && sequence.send(:threads_waiting_to_start?)
    remainder = @pending_cycles - 1
    @pending_cycles = 1
  end
  wait
  @pending_cycles = remainder if remainder
  # If the sequence did not do enough cycles in that round to satisfy this thread, then go back
  # around to complete the remainder before continuing with the rest of the pattern
  if @pending_cycles == 0
    @pending_cycles = nil
  elsif @pending_cycles > 0
    @pending_cycles.cycles
  else
    fail "Something has gone wrong @pending_cycles is #{@pending_cycles}"
  end
end
executed_cycles(cycles) click to toggle source

@api private

# File lib/origen/generator/pattern_thread.rb, line 146
def executed_cycles(cycles)
  @pending_cycles -= cycles if @pending_cycles
end
execution_profile(start, stop, step) click to toggle source
# File lib/origen/generator/pattern_thread.rb, line 74
def execution_profile(start, stop, step)
  events = @events.dup
  cycles = start
  state = :inactive
  line = ''
  ((stop - start) / step).times do |i|
    active_cycles = 0
    while events.first && events.first[1] >= cycles && events.first[1] < cycles + step
      event = events.shift
      # Bring the current cycles up to this event point applying the current state
      if state == :active
        active_cycles += event[1] - cycles
      end
      state = event[0] == :active ? :active : :inactive
      cycles = event[1]
    end

    # Bring the current cycles up to the end of this profile tick
    if state == :active
      active_cycles += ((i + 1) * step) - cycles
    end
    cycles = ((i + 1) * step)

    if active_cycles == 0
      line += '_'
    elsif active_cycles > (step * 0.5)
      line += '█'
    else
      line += '▄'
    end
  end
  line
end
primary?() click to toggle source

Returns true if this is main thread (the one from which all in_parallel threads have been branched from)

# File lib/origen/generator/pattern_thread.rb, line 38
def primary?
  @primary
end
record_active() click to toggle source
# File lib/origen/generator/pattern_thread.rb, line 66
def record_active
  events << [:active, current_cycle_count]
end
record_cycle_count_stop() click to toggle source
# File lib/origen/generator/pattern_thread.rb, line 60
def record_cycle_count_stop
  @cycle_count_stop = current_cycle_count
  events << [:stopped, cycle_count_stop]
  events.freeze
end
start() click to toggle source

@api private

This method is called once by the pattern sequence to start a new thread. It will block until the thread is in the waiting state.

# File lib/origen/generator/pattern_thread.rb, line 46
def start
  @thread = Thread.new do
    PatSeq.send(:thread=, self)
    wait
    @pre_block.call if @pre_block
    @block.call(sequence)
    sequence.send(:thread_completed, self)
    record_cycle_count_stop
    @completed = true
    wait
  end
  @waiting.wait
end
wait() click to toggle source

This should be called only by the pattern thread itself, and will block it until it is told to advance by the pattern sequence running in the main thread

# File lib/origen/generator/pattern_thread.rb, line 161
def wait
  @running.reset
  @waiting.set
  @running.wait
end
waiting?() click to toggle source

Returns true if the thread is currently waiting for the pattern sequence to advance it

# File lib/origen/generator/pattern_thread.rb, line 155
def waiting?
  @waiting.set?
end
waiting_for_serialize(serialize_id, skip_event = false) click to toggle source

Will be called when the thread can’t execute its next cycle because it is waiting to obtain a lock on a serialized block

# File lib/origen/generator/pattern_thread.rb, line 110
def waiting_for_serialize(serialize_id, skip_event = false)
  # puts "Thread #{id} is blocked waiting for #{serialize_id}"
  events << [:waiting, current_cycle_count] unless skip_event
  wait
end
waiting_for_thread(skip_event = false) click to toggle source

Will be called when the thread can’t execute its next cycle because it is waiting for another thread to complete

# File lib/origen/generator/pattern_thread.rb, line 118
def waiting_for_thread(skip_event = false)
  events << [:waiting, current_cycle_count] unless skip_event
  wait
end