Class: Origen::Generator::PatternThread

Inherits:
Object
  • Object
show all
Defined in:
lib/origen/generator/pattern_thread.rb

Overview

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id, sequence, block, primary = false, pre_block = nil) ⇒ PatternThread

Returns a new instance of PatternThread.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 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

Instance Attribute Details

#cycle_count_startObject (readonly)

Returns the value of attribute cycle_count_start.



12
13
14
# File 'lib/origen/generator/pattern_thread.rb', line 12

def cycle_count_start
  @cycle_count_start
end

#cycle_count_stopObject (readonly)

Returns the value of attribute cycle_count_stop.



13
14
15
# File 'lib/origen/generator/pattern_thread.rb', line 13

def cycle_count_stop
  @cycle_count_stop
end

#eventsObject (readonly)

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



15
16
17
# File 'lib/origen/generator/pattern_thread.rb', line 15

def events
  @events
end

#idObject (readonly)

Returns the value of attribute id.



10
11
12
# File 'lib/origen/generator/pattern_thread.rb', line 10

def id
  @id
end

#pending_cyclesObject (readonly)

Returns the value of attribute pending_cycles.



9
10
11
# File 'lib/origen/generator/pattern_thread.rb', line 9

def pending_cycles
  @pending_cycles
end

#reservationsObject (readonly)

Returns the value of attribute reservations.



11
12
13
# File 'lib/origen/generator/pattern_thread.rb', line 11

def reservations
  @reservations
end

#sequenceObject (readonly)

Returns the parent pattern sequence object



8
9
10
# File 'lib/origen/generator/pattern_thread.rb', line 8

def sequence
  @sequence
end

Instance Method Details

#advance(completed_cycles = nil) ⇒ Object

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)



170
171
172
173
174
# 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?Boolean

Returns:

  • (Boolean)


150
151
152
# File 'lib/origen/generator/pattern_thread.rb', line 150

def completed?
  @completed
end

#current_cycle_countObject



70
71
72
# File 'lib/origen/generator/pattern_thread.rb', line 70

def current_cycle_count
  tester.try(:cycle_count) || 0
end

#cycle(options) ⇒ Object

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



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# 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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



146
147
148
# 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) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# 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?Boolean

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

Returns:

  • (Boolean)


38
39
40
# File 'lib/origen/generator/pattern_thread.rb', line 38

def primary?
  @primary
end

#record_activeObject



66
67
68
# File 'lib/origen/generator/pattern_thread.rb', line 66

def record_active
  events << [:active, current_cycle_count]
end

#record_cycle_count_stopObject



60
61
62
63
64
# 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

#startObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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.



46
47
48
49
50
51
52
53
54
55
56
57
58
# 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

#waitObject

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



161
162
163
164
165
# File 'lib/origen/generator/pattern_thread.rb', line 161

def wait
  @running.reset
  @waiting.set
  @running.wait
end

#waiting?Boolean

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

Returns:

  • (Boolean)


155
156
157
# File 'lib/origen/generator/pattern_thread.rb', line 155

def waiting?
  @waiting.set?
end

#waiting_for_serialize(serialize_id, skip_event = false) ⇒ Object

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



110
111
112
113
114
# 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) ⇒ Object

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



118
119
120
121
# 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