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

owner[R]

Returns the parent object that instantiated the driver, could be either a DUT object or a protocol abstraction

trn[RW]

Customiz-ible 'turn-round cycle' (TRN) parameter (in cycles)

Public Class Methods

new(owner, options = {}) click to toggle source

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(ap_dp, reg_or_val, options = {}) click to toggle source

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
read_ap(reg_or_val, options = {}) click to toggle source

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
read_dp(reg_or_val, options = {}) click to toggle source

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(ap_dp, reg_or_val, deprecated_wdata = nil, options = {}) click to toggle source

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_ap(reg_or_val, options = {}) click to toggle source

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_dp(reg_or_val, options = {}) click to toggle source

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

extract_address(reg_or_val, options) click to toggle source
# 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
extract_data_hex(reg_or_val) click to toggle source
# 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
extract_reg_overlay(reg) click to toggle source

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
log(msg) { || ... } click to toggle source
# File lib/origen_swd/driver.rb, line 212
def log(msg)
  cc "[SWD] #{msg}"
  if block_given?
    yield
    cc "[SWD] /#{msg}"
  end
end
receive_acknowledgement(confirm: :success, **options) click to toggle source

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
receive_payload(reg_or_val, options) click to toggle source

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_header(apndp, rnw, address) click to toggle source

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_payload(reg_or_val, options) click to toggle source

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_payload(reg_or_val, options) click to toggle source

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
swd_clk() click to toggle source

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
swd_dio() click to toggle source

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
swd_xor_calc(size, number) click to toggle source

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
to_reg(reg_or_val, options) click to toggle source

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
wait_trn() click to toggle source

Waits for TRN time delay

# File lib/origen_swd/driver.rb, line 208
def wait_trn
  $tester.cycle(repeat: trn + 1)
end