module OrigenTesters
module Timing
class InvalidModification < Origen::OrigenError
end
class Timeset
attr_accessor :name, :cycled, :called
attr_reader :period_in_ns
def initialize(attrs = {})
@cycled = false
@locked = false
@called = false
attrs.each do |name, value|
send("#{name}=", value)
end
self.period_in_ns = attrs[:period_in_ns]
end
# Returns true if the timeset has a shorter period than the supplied timeset
def shorter_period_than?(timeset)
period_in_ns < timeset.period_in_ns
end
# Returns true if tester.cycle
has been called while this
# timeset was the current timeset.
# @return [true, false] true
if this timeset has been cycled, false
otherwise.
def cycled?
@cycled
end
# Returns true if this timeset does not allow changes to its period_in_ns
def locked?
@locked
end
alias_method :period_in_ns_locked?, :locked?
alias_method :period_locked?, :locked?
alias_method :locked, :locked?
# Locks the current value of the timeset's period_in_ns. Attempts to further
# adjust the period_in_ns will results in an exception.
# @return [true, false] true
if the period_in_ns has been locked, false
otherwise.
def lock!
@locked = true
end
alias_method :lock_period!, :lock!
alias_method :lock_period_in_ns!, :lock!
# Sets the period_in_ns of this timeset and issues a callback to the tester's #set_timeset
# method, if this timeset is the current timeset, keeping the tester in
# sync with the changes to this timeset.
# @raise [InvalidModification] If the timeset is locked.
# @raise [InvalidModification] If period_in_ns is changed after the tester has been cycled using this timeset.
# @return [Fixnum] The updated period in ns.
def period_in_ns=(p)
self._period_in_ns_ = p
# If this is the current timeset, reset the timeset from the tester
# side to verify that everything is in sync. Otherwise, the period_in_ns
# here may not match what the tester/DUT has.
if current_timeset?
OrigenTesters::Timing.set_timeset(name, p)
end
# Return the period
p
end
# Indicates whether a period_in_ns has been defined for this timeset.
# @return [true, false] true
if the period_in_ns has been set, false
otherwise.
def period_in_ns?
!@period_in_ns.nil?
end
# Returns the current timeset in seconds
# @return [Float] Current period in seconds
def period_in_secs
if period_in_ns
period_in_ns * (10**-9)
end
end
alias_method :period_in_seconds, :period_in_secs
# Indicates whether this timeset is the current timeset.
# @return [true, false] true
if this timeset is the current timeset, false
otherwise.
def current_timeset?
OrigenTesters::Timing.timeset == self
end
# Indicates whether this timeset is or has been set as the current timeset.
# @return [true, false] true
if this timeset is or has beent he current timeset, false
otherwise.
def called?
@called
end
# Alias for the {#name} attr_reader.
def id
name.to_sym
end
def dut_timeset
dut.timesets[id]
end
def method_missing(m, *args, &block)
if dut_timeset && (dut_timeset.methods.include?(m) || dut_timeset.private_methods.include?(m))
dut_timeset.send(m, *args, &block)
else
super
end
end
# @api private
def _period_in_ns_=(p)
if locked?
Origen.app.fail(
exception_class: InvalidModification,
message: "Timeset :#{@name}'s period_in_ns is locked to #{@period_in_ns} ns!"
)
end
# Adding this causes examples in Origen (not OrigenTesters) to fail.
# Needs further discussion and potentially an Origen examples change.
# if cycled? && p != period_in_ns
# Origen.app!.fail(
# exception_class: InvalidModification,
# message: [
# "Timeset :#{name}'s period_in_ns cannot be changed after a cycle has occurred using this timeset!",
# " period_in_ns change occurred at #{caller[0]}",
# " Attempted to change period from #{@period_in_ns} to #{p}"
# ].join("\n")
# )
# end
@period_in_ns = p
@period_in_ns
end
end
end
end