class OrigenSWD::Driver
To use this driver the owner model must define the following pins (an alias is fine):
:swd_clk :swd_dio
Constants
- REQUIRED_PINS
Attributes
Returns the parent object that instantiated the driver, could be either a DUT object or a protocol abstraction
Customiz-ible 'turn-round cycle' (TRN) parameter (in cycles)
Public Class Methods
Initialize class variables
@param [Object] owner Parent object @param [Hash] options Options to customize the operation
@example
# Create new SWD::Driver object DUT.new.swd
# File lib/origen_swd/driver.rb, line 27 def initialize(owner, options = {}) @owner = owner @current_apaddr = 0 @orundetect = 0 @trn = 0 end
Public Instance Methods
Read data from Debug Port or Access Port
@param [Integer] ap_dp A single bit indicating whether the Debug Port or the Access Port
Register is to be accessed. This bit is 0 for an DPACC access, or 1 for a APACC access
@param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
Value to be shifted. If a reg/bit collection is supplied this can be pre-marked for read, store or overlay and which will result in the requested action being applied to the cycles corresponding to those bits only (don't care cycles will be generated for the others).
@param [Hash] options Options to customize the operation
# File lib/origen_swd/driver.rb, line 68 def read(ap_dp, reg_or_val, options = {}) addr = extract_address(reg_or_val, options.merge(use_reg_or_val_if_you_must: true)) send_header(ap_dp, 1, addr) # send read-specific header (rnw = 1) receive_acknowledgement(options) receive_payload(reg_or_val, options) swd_dio.drive(0) end
Write data from Access Port
@param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
Value to be shifted. If a reg/bit collection is supplied this can be pre-marked for read, store or overlay and which will result in the requested action being applied to the cycles corresponding to those bits only (don't care cycles will be generated for the others).
@param [Hash] options Options to customize the operation
# File lib/origen_swd/driver.rb, line 54 def read_ap(reg_or_val, options = {}) reg_or_val, options = nil, reg_or_val if reg_or_val.is_a?(Hash) read(1, reg_or_val, options.merge(compare_data: reg_or_val.is_a?(Numeric))) end
Write data from Debug Port
@param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
Value to be shifted. If a reg/bit collection is supplied this can be pre-marked for read, store or overlay and which will result in the requested action being applied to the cycles corresponding to those bits only (don't care cycles will be generated for the others).
@param [Hash] options Options to customize the operation
# File lib/origen_swd/driver.rb, line 42 def read_dp(reg_or_val, options = {}) reg_or_val, options = nil, reg_or_val if reg_or_val.is_a?(Hash) read(0, reg_or_val, options.merge(compare_data: reg_or_val.is_a?(Numeric))) end
Write data to Debug Port or Access Port
@param [Integer] ap_dp A single bit indicating whether the Debug Port or the Access Port Register
is to be accessed. This bit is 0 for an DPACC access, or 1 for a APACC access
@param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
Value to be shifted. If a reg/bit collection is supplied this can be pre-marked for read, store or overlay and which will result in the requested action being applied to the cycles corresponding to those bits only (don't care cycles will be generated for the others).
@param [Hash] options Options to customize the operation
# File lib/origen_swd/driver.rb, line 107 def write(ap_dp, reg_or_val, deprecated_wdata = nil, options = {}) deprecated_wdata, options = nil, deprecated_wdata if deprecated_wdata.is_a?(Hash) if deprecated_wdata addr = reg_or_val.respond_to?(:address) ? reg_or_val.address : reg_or_val else addr = extract_address(reg_or_val, options) end send_header(ap_dp, 0, addr) # send write-specific header (rnw = 0) receive_acknowledgement if deprecated_wdata if reg_or_val.respond_to?(:data) reg_or_val.data = deprecated_wdata else reg_or_val = deprecated_wdata end end send_payload(reg_or_val, options) swd_dio.drive(0) end
Write data to Access Port
@param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
Value to be shifted. If a reg/bit collection is supplied this can be pre-marked for read, store or overlay and which will result in the requested action being applied to the cycles corresponding to those bits only (don't care cycles will be generated for the others).
@param [Hash] options Options to customize the operation
# File lib/origen_swd/driver.rb, line 94 def write_ap(reg_or_val, options = {}) write(1, reg_or_val, options) end
Write data to Debug Port
@param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
Value to be shifted. If a reg/bit collection is supplied this can be pre-marked for read, store or overlay and which will result in the requested action being applied to the cycles corresponding to those bits only (don't care cycles will be generated for the others).
@param [Hash] options Options to customize the operation
# File lib/origen_swd/driver.rb, line 83 def write_dp(reg_or_val, options = {}) write(0, reg_or_val, options) end
Private Instance Methods
# File lib/origen_swd/driver.rb, line 140 def extract_address(reg_or_val, options) addr = options[:address] || options[:addr] return addr if addr return reg_or_val.address if reg_or_val.respond_to?(:address) return reg_or_val.addr if reg_or_val.respond_to?(:addr) return reg_or_val if reg_or_val && options[:use_reg_or_val_if_you_must] fail 'No address given, if supplying a data value instead of a register object, you must supply an :address option' end
# File lib/origen_swd/driver.rb, line 132 def extract_data_hex(reg_or_val) if reg_or_val.respond_to?(:data) reg_or_val.data.to_s(16).upcase else reg_or_val.to_s(16).upcase end end
Return overlay sting if same for all bits, otherwise return nil
# File lib/origen_swd/driver.rb, line 361 def extract_reg_overlay(reg) ovl = reg[0].overlay_str reg.size.times do |i| return nil unless reg[i].has_overlay? return nil if ovl != reg[i].overlay_str || ovl.nil? end ovl end
# File lib/origen_swd/driver.rb, line 212 def log(msg) cc "[SWD] #{msg}" if block_given? yield cc "[SWD] /#{msg}" end end
Waits appropriate number of cycles for the acknowledgement phase @param confirm [Symbol] Indicates what type of acknowledgement confirmation should be used. Options are:
* [:ignore, :none, :skip] -> Ignore the acknowledgement completely. * [:failure, :fail, :error] -> Verify that the acknowledgement failured; that is, * [:success] (Default) -> Verify the acknowledgement as normal.
@param options [Hash] Placeholder for other/future options. @raise [RuntimeError] When an unrecongized :confirm option is given.
# File lib/origen_swd/driver.rb, line 186 def receive_acknowledgement(confirm: :success, **options) wait_trn if [:ignore, :none, :skip].include?(confirm) log('Ignoring Acknowledgement Phase') tester.cycle(repeat: 3) elsif [:failure, :fail, :error].include?(confirm) log('Confirming Error Encountered During Acknowledgement Phase') swd_dio.assert!(0) swd_dio.assert!(0) swd_dio.assert!(1) elsif confirm == :success log('Confirming Success During Acknowledgement Phase') swd_dio.assert!(1) swd_dio.assert!(0) swd_dio.assert!(0) else Origen.app!.fail!(message: "OrigenSWD: Origen SWD does not know how to confirm :#{confirm}") end swd_dio.dont_care end
Get (read) the data payload
@param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
Value to be read. If a reg/bit collection is supplied this can be pre-marked for read, store or overlay and which will result in the requested action being applied to the cycles corresponding to those bits only (don't care cycles will be generated for the others).
@option options [String] :overlay String for pattern label to
facilitate pattern overlay
# File lib/origen_swd/driver.rb, line 228 def receive_payload(reg_or_val, options) log "Read: #{Origen::Utility.read_hex(reg_or_val)}" do options[:read] = true shift_payload(reg_or_val, options) end swd_dio.dont_care $tester.cycle wait_trn end
Send SWD Packet header
------------------------------------------------------------------------ | Start | APnDP | 1 | ADDR[2] | ADDR[3] | Parity | Stop | Park | ------------------------------------------------------------------------
@param [Integer] apndp A single bit indicating whether the Debug Port or the Access Port
Register is to be accessed. This bit is 0 for an DPACC access, or 1 for a APACC access
@param [Integer] rnw A single bit, indicating whether the access is a read or a write.
This bit is 0 for a write access, or 1 for a read access.
@param [Integer] address Address of register that is being accessed
# File lib/origen_swd/driver.rb, line 159 def send_header(apndp, rnw, address) addr = address >> 2 parity = apndp ^ rnw ^ (addr >> 3) ^ (addr >> 2) & (0x01) ^ (addr >> 1) & (0x01) ^ addr & 0x01 cc '[SWD] -----------------------------------------------------------------' cc '[SWD] | Start | AP | Read | AD[2] | AD[3] | Par | Stop | Park |' cc "[SWD] | 1 | #{apndp} | #{rnw} | #{addr[0]} | #{addr[1]} | #{parity[0]} | 0 | 1 |" cc '[SWD] -----------------------------------------------------------------' swd_clk.drive(1) swd_dio.drive!(1) # send start bit (always 1) swd_dio.drive!(apndp) # send apndp bit swd_dio.drive!(rnw) # send rnw bit swd_dio.drive!(addr[0]) # send address[2] bit swd_dio.drive!(addr[1]) # send address[3] bit swd_dio.drive!(parity[0]) # send parity bit swd_dio.drive!(0) # send stop bit swd_dio.drive!(1) # send park bit swd_dio.dont_care end
Send (write) the data payload
@param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
Value to be written. If a reg/bit collection is supplied this can be pre-marked for read, store or overlay and which will result in the requested action being applied to the cycles corresponding to those bits only (don't care cycles will be generated for the others).
@option options [String] :overlay String for pattern label to
facilitate pattern overlay
# File lib/origen_swd/driver.rb, line 246 def send_payload(reg_or_val, options) wait_trn wdata = reg_or_val.respond_to?(:data) ? reg_or_val.data : reg_or_val log "Write: #{wdata.to_hex}" do options[:read] = false shift_payload(reg_or_val, options) end parity_bit = swd_xor_calc(32, wdata) swd_dio.drive!(parity_bit) swd_dio.dont_care end
Shift the data payload
@param [Integer, Origen::Register::Reg, Origen::Register::BitCollection, Origen::Register::Bit] reg_or_val
Value to be shifted. If a reg/bit collection is supplied this can be pre-marked for read, store or overlay and which will result in the requested action being applied to the cycles corresponding to those bits only (don't care cycles will be generated for the others).
@option options [String] :overlay String for pattern label to
facilitate pattern overlay
# File lib/origen_swd/driver.rb, line 268 def shift_payload(reg_or_val, options) options = { no_subr: false }.merge(options) reg = to_reg(reg_or_val, options) size = 32 # SWD only used to write to DP and AP registers of ARM Debugger (32 bits) # tester does not support direct labels, so can't do if options[:no_subr] && !$tester.respond_to?('label') cc 'This tester does not support use of labels, cannot do no_subr option as requested' cc ' going with subroutine overlay instead' options[:no_subr] = false end cc options[:arm_debug_comment] if options.key?(:arm_debug_comment) swd_clk.drive(1) reg_overlay = extract_reg_overlay(reg) if reg_overlay && !options[:no_subr] && !Origen.mode.simulation? Origen.tester.call_subroutine(reg[0].overlay_str) else last_overlay_label = '' size.times do |i| swd_dio.dont_care if options[:read] if reg[i].is_to_be_stored? Origen.tester.store_next_cycle(swd_dio) swd_dio.dont_care if Origen.tester.j750? elsif reg[i].is_to_be_read? swd_dio.assert(reg[i] ? reg[i] : 0, meta: { position: i }) end else swd_dio.drive(reg_or_val[i]) end if reg[i].has_overlay? && !Origen.mode.simulation? && tester.respond_to?('label') if reg[i].overlay_str != last_overlay_label Origen.tester.label(reg[i].overlay_str) last_overlay_label = reg[i].overlay_str end tester.cycle dont_compress: true else tester.cycle end end end # Clear read and similar flags to reflect that the request has just # been fulfilled reg_or_val.clear_flags if reg_or_val.respond_to?(:clear_flags) swd_dio.dont_care end
Provides shortname access to top-level SWD clock pin
# File lib/origen_swd/driver.rb, line 333 def swd_clk owner.pin(:swd_clk) end
Provides shortname access to top-level SWD data I/O pin
# File lib/origen_swd/driver.rb, line 338 def swd_dio owner.pin(:swd_dio) end
Calculate exclusive OR
@param [Integer] size The number of bits in the number @param [Integer] number The number being operated on
# File lib/origen_swd/driver.rb, line 324 def swd_xor_calc(size, number) xor = 0 size.times do |bit| xor ^= (number >> bit) & 0x01 end xor end
Converts reg_or_val to reg
# File lib/origen_swd/driver.rb, line 343 def to_reg(reg_or_val, options) if reg_or_val.respond_to?(:data) reg = reg_or_val.dup else reg = Reg.dummy(32) if reg_or_val.nil? reg.read(options[:compare_data]) if options[:compare_data] else reg.write(reg_or_val) reg.read if options[:read] end end reg.overlay(options[:arm_debug_overlay]) if options.key?(:arm_debug_overlay) reg.overlay(options[:overlay_label]) if options.key?(:overlay) reg end
Waits for TRN time delay
# File lib/origen_swd/driver.rb, line 208 def wait_trn $tester.cycle(repeat: trn + 1) end