lib/origen/pins/pin_clock.rb in origen-0.7.45 vs lib/origen/pins/pin_clock.rb in origen-0.7.46

- old
+ new

@@ -1,124 +1,138 @@ module Origen module Pins class PinClock - attr_accessor :running - attr_accessor :cycles_per_half_period - attr_accessor :last_edge - attr_accessor :next_edge + attr_reader :cycles_per_duty, :last_edge, :next_edge def initialize(owner, options = {}) @owner = owner @running = false - @cycles_per_half_period = 0 - @ns_per_half_period = 0 - update_half_period(options) - end - def running? - @running + @clock_period_in_ns = 0 + @tester_period_in_ns = 0 + + update_clock_period(options) + update_tester_period_local + update_clock_parameters end def start_clock(options = {}) - fail "ERROR: Clock on #{@owner.name} already running." if running? + # Throw error if this pin is already a running clock + if running? + fail "PIN CLOCK ERROR: Clock on #{@owner.name} already running." + end - if update_required?(options) - update_half_period(options) + clock_updated = update_clock_period(options) + tester_updated = update_tester_period_local + if clock_updated || tester_updated + update_clock_parameters end - @last_edge = Origen.tester.cycle_count - @next_edge = Origen.tester.cycle_count + @cycles_per_half_period - cc "Start clock on #{@owner.name}: cycles_per_half_period=#{@cycles_per_half_period}, start cycle=#{@last_edge}" + cc "[PinClock] Start #{@owner.name}.clock at #{Origen.tester.cycle_count}: period=#{@clock_period_in_ns}ns, cycles=#{cycles_per_period}, duty=#{duty_str}" + update_edges Origen.tester.push_running_clock(@owner) unless running? @running = true end - def restart_clock(_options = {}) + def stop_clock(options = {}) + cc "[PinClock] Stop #{@owner.name}.clock: stop_cycle=#{Origen.tester.cycle_count}" if running? + Origen.tester.pop_running_clock(@owner) if running? + @running = false + end + + def restart_clock stop_clock update_clock start_clock end - def stop_clock(_options = {}) - cc "Stop clock on #{@owner.name}: stop cycle=#{Origen.tester.cycle_count}" if running? - Origen.tester.pop_running_clock(@owner) if running? - @running = false - end - def update_clock - unless update_half_period(period_in_ns: @ns_per_half_period) - @last_edge = Origen.tester.cycle_count - @next_edge = Origen.tester.cycle_count + @cycles_per_half_period + if update_tester_period_local + update_clock_parameters + cc "[PinClock] Update #{@owner.name}.clock at #{Origen.tester.cycle_count}: period=#{@clock_period_in_ns}ns, cycles=#{cycles_per_period}, duty=#{duty_str}" + update_edges end end + def running? + @running + end + def toggle @owner.toggle - @last_edge = Origen.tester.cycle_count - @next_edge = Origen.tester.cycle_count + @cycles_per_half_period + update_edges end + # The only caller to this should be legacy support so just force 50% duty cycle + def cycles_per_half_period + @cycles_per_duty.min + end + private - def update_half_period(options = {}) - old_cycles_per_half_period = @cycles_per_half_period - options = { cycles: 0, - period_in_s: 0, period_in_ms: 0, period_in_us: 0, period_in_ns: 0, - frequency_in_hz: 0, frequency_in_khz: 0, frequency_in_mhz: 0, - freq_in_hz: 0, freq_in_khz: 0, freq_in_mhz: 0 - }.merge(options) - - cycles = 0 - cycles += options[:cycles] - cycles += s_to_cycles(options[:period_in_s]) - cycles += ms_to_cycles(options[:period_in_ms]) - cycles += us_to_cycles(options[:period_in_us]) - cycles += ns_to_cycles(options[:period_in_ns]) - cycles += hz_to_cycles(options[:frequency_in_hz]) - cycles += khz_to_cycles(options[:frequency_in_khz]) - cycles += mhz_to_cycles(options[:frequency_in_mhz]) - cycles += hz_to_cycles(options[:freq_in_hz]) - cycles += khz_to_cycles(options[:freq_in_khz]) - cycles += mhz_to_cycles(options[:freq_in_mhz]) - - @cycles_per_half_period = cycles / 2 - @ns_per_half_period = cycles * Origen.tester.current_period_in_ns - @cycles_per_half_period == old_cycles_per_half_period + def update_clock_parameters + @cycles_per_duty = [(cycles_per_period / 2.0).floor, (cycles_per_period / 2.0).ceil] end - def s_to_cycles(time) # :nodoc: - ((time.to_f) * 1000 * 1000 * 1000 / Origen.tester.current_period_in_ns).to_int + def cycles_per_period + (@clock_period_in_ns / @tester_period_in_ns).to_int end - def ms_to_cycles(time) # :nodoc: - ((time.to_f) * 1000 * 1000 / Origen.tester.current_period_in_ns).to_int + def update_edges + @last_edge = Origen.tester.cycle_count + @next_edge = Origen.tester.cycle_count + @cycles_per_duty[0] + @cycles_per_duty.reverse! end - def us_to_cycles(time) # :nodoc: - ((time.to_f * 1000) / Origen.tester.current_period_in_ns).to_int + def update_tester_period_local + if Origen.tester.current_period_in_ns == @tester_period_in_ns + return false + else + @tester_period_in_ns = Origen.tester.current_period_in_ns + return true + end end - def ns_to_cycles(time) # :nodoc: - (time.to_f / Origen.tester.current_period_in_ns).to_int - end + def update_clock_period(options = {}) + new = get_clock_period(options) - def hz_to_cycles(freq) # :nodoc: - (freq == 0) ? freq : s_to_cycles(1 / freq.to_f) + if new == @clock_period_in_ns + false + else + @clock_period_in_ns = new + true + end end - def khz_to_cycles(freq) # :nodoc: - (freq == 0) ? freq : ms_to_cycles(1 / freq.to_f) - end + def get_clock_period(options = {}) + return @clock_period_in_ns if options.empty? - def mhz_to_cycles(freq) # :nodoc: - (freq == 0) ? freq : us_to_cycles(1 / freq.to_f) + p = [] + + # Passed in as time + p << (options[:period_in_s] * 1_000_000_000) if options[:period_in_s] + p << (options[:period_in_ms] * 1_000_000) if options[:period_in_ms] + p << (options[:period_in_us] * 1_000) if options[:period_in_us] + p << (options[:period_in_ns] * 1) if options[:period_in_ns] + + # Passed in as frequency (or freq.) + p << ((1.0 / options[:frequency_in_hz]) * 1_000_000_000) if options[:frequency_in_hz] + p << ((1.0 / options[:freq_in_hz]) * 1_000_000_000) if options[:freq_in_hz] + p << ((1.0 / options[:frequency_in_khz]) * 1_000_000) if options[:frequency_in_khz] + p << ((1.0 / options[:freq_in_khz]) * 1_000_000) if options[:freq_in_khz] + p << ((1.0 / options[:frequency_in_mhz]) * 1_000) if options[:frequency_in_mhz] + p << ((1.0 / options[:freq_in_mhz]) * 1_000) if options[:freq_in_mhz] + + # Passed in as cycles (not advised) + p << (options[:cycles] * Origen.tester.period_in_ns) if options[:cycles] + + return @clock_period_in_ns if p.empty? + fail "[Pin Clock] ERROR: Multiple unit declarations for #{@owner.name}.clock" if p.size > 1 + p[0].to_int end - def update_required?(options) - options[:cycles] || - options[:period_in_s] || options[:period_in_ms] || options[:period_in_us] || options[:period_in_ns] - options[:frequency_in_hz] || options[:frequency_in_khz] || options[:frequency_in_mhz] || - options[:freq_in_hz] || options[:freq_in_khz] || options[:freq_in_mhz] + def duty_str + "#{@cycles_per_duty[0]}/#{@cycles_per_duty[1]}" end end end end