-
1
module OrigenSWD
-
# To use this driver the owner model must define the following pins (an alias is fine):
-
# :swd_clk
-
# :swd_dio
-
#
-
1
class Driver
-
1
REQUIRED_PINS = [:swd_clk, :swd_dio]
-
-
1
include Origen::Registers
-
-
# Returns the parent object that instantiated the driver, could be
-
# either a DUT object or a protocol abstraction
-
1
attr_reader :owner
-
-
# Customiz-ible 'turn-round cycle' (TRN) parameter (in cycles)
-
1
attr_accessor :trn
-
-
# 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
-
#
-
1
def initialize(owner, options = {})
-
2
@owner = owner
-
-
2
@current_apaddr = 0
-
2
@orundetect = 0
-
2
@trn = 0
-
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
-
1
def read_dp(reg_or_val, options = {})
-
3
reg_or_val, options = nil, reg_or_val if reg_or_val.is_a?(Hash)
-
3
read(0, reg_or_val, options.merge(compare_data: reg_or_val.is_a?(Numeric)))
-
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
-
1
def read_ap(reg_or_val, options = {})
-
3
reg_or_val, options = nil, reg_or_val if reg_or_val.is_a?(Hash)
-
3
read(1, reg_or_val, options.merge(compare_data: reg_or_val.is_a?(Numeric)))
-
end
-
-
# 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
-
1
def read(ap_dp, reg_or_val, options = {})
-
12
addr = extract_address(reg_or_val, options.merge(use_reg_or_val_if_you_must: true))
-
12
send_header(ap_dp, 1, addr) # send read-specific header (rnw = 1)
-
12
receive_acknowledgement(options)
-
12
receive_payload(reg_or_val, options)
-
12
swd_dio.drive(0)
-
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
-
1
def write_dp(reg_or_val, options = {})
-
2
write(0, reg_or_val, options)
-
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
-
1
def write_ap(reg_or_val, options = {})
-
2
write(1, reg_or_val, options)
-
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
-
1
def write(ap_dp, reg_or_val, deprecated_wdata = nil, options = {})
-
10
deprecated_wdata, options = nil, deprecated_wdata if deprecated_wdata.is_a?(Hash)
-
-
10
if deprecated_wdata
-
4
addr = reg_or_val.respond_to?(:address) ? reg_or_val.address : reg_or_val
-
else
-
6
addr = extract_address(reg_or_val, options)
-
end
-
-
10
send_header(ap_dp, 0, addr) # send write-specific header (rnw = 0)
-
10
receive_acknowledgement
-
-
10
if deprecated_wdata
-
4
if reg_or_val.respond_to?(:data)
-
4
reg_or_val.data = deprecated_wdata
-
else
-
reg_or_val = deprecated_wdata
-
end
-
end
-
10
send_payload(reg_or_val, options)
-
10
swd_dio.drive(0)
-
end
-
-
1
private
-
-
1
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
-
-
1
def extract_address(reg_or_val, options)
-
18
addr = options[:address] || options[:addr]
-
18
return addr if addr
-
11
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
-
-
# 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
-
1
def send_header(apndp, rnw, address)
-
22
addr = address >> 2
-
22
parity = apndp ^ rnw ^ (addr >> 3) ^ (addr >> 2) & (0x01) ^ (addr >> 1) & (0x01) ^ addr & 0x01
-
-
22
cc '[SWD] -----------------------------------------------------------------'
-
22
cc '[SWD] | Start | AP | Read | AD[2] | AD[3] | Par | Stop | Park |'
-
22
cc "[SWD] | 1 | #{apndp} | #{rnw} | #{addr[0]} | #{addr[1]} | #{parity[0]} | 0 | 1 |"
-
22
cc '[SWD] -----------------------------------------------------------------'
-
22
swd_clk.drive(1)
-
22
swd_dio.drive!(1) # send start bit (always 1)
-
22
swd_dio.drive!(apndp) # send apndp bit
-
22
swd_dio.drive!(rnw) # send rnw bit
-
22
swd_dio.drive!(addr[0]) # send address[2] bit
-
22
swd_dio.drive!(addr[1]) # send address[3] bit
-
22
swd_dio.drive!(parity[0]) # send parity bit
-
22
swd_dio.drive!(0) # send stop bit
-
22
swd_dio.drive!(1) # send park bit
-
22
swd_dio.dont_care
-
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.
-
1
def receive_acknowledgement(confirm: :success, **options)
-
22
wait_trn
-
22
if [:ignore, :none, :skip].include?(confirm)
-
log('Ignoring Acknowledgement Phase')
-
tester.cycle(repeat: 3)
-
22
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)
-
22
elsif confirm == :success
-
22
log('Confirming Success During Acknowledgement Phase')
-
22
swd_dio.assert!(1)
-
22
swd_dio.assert!(0)
-
22
swd_dio.assert!(0)
-
else
-
Origen.app!.fail!(message: "OrigenSWD: Origen SWD does not know how to confirm :#{confirm}")
-
end
-
22
swd_dio.dont_care
-
end
-
-
# Waits for TRN time delay
-
1
def wait_trn
-
44
$tester.cycle(repeat: trn + 1)
-
end
-
-
1
def log(msg)
-
44
cc "[SWD] #{msg}"
-
44
if block_given?
-
22
yield
-
22
cc "[SWD] /#{msg}"
-
end
-
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
-
1
def receive_payload(reg_or_val, options)
-
12
log "Read: #{Origen::Utility.read_hex(reg_or_val)}" do
-
12
options[:read] = true
-
12
shift_payload(reg_or_val, options)
-
end
-
12
swd_dio.dont_care
-
12
$tester.cycle
-
12
wait_trn
-
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
-
1
def send_payload(reg_or_val, options)
-
10
wait_trn
-
10
wdata = reg_or_val.respond_to?(:data) ? reg_or_val.data : reg_or_val
-
-
10
log "Write: #{wdata.to_hex}" do
-
10
options[:read] = false
-
10
shift_payload(reg_or_val, options)
-
end
-
-
10
parity_bit = swd_xor_calc(32, wdata)
-
10
swd_dio.drive!(parity_bit)
-
10
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
-
1
def shift_payload(reg_or_val, options)
-
22
options = { no_subr: false }.merge(options)
-
-
22
reg = to_reg(reg_or_val, options)
-
22
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
-
22
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
-
-
22
cc options[:arm_debug_comment] if options.key?(:arm_debug_comment)
-
22
swd_clk.drive(1)
-
-
22
reg_overlay = extract_reg_overlay(reg)
-
22
if reg_overlay && !options[:no_subr] && !Origen.mode.simulation?
-
2
Origen.tester.call_subroutine(reg[0].overlay_str)
-
else
-
20
last_overlay_label = ''
-
20
size.times do |i|
-
640
swd_dio.dont_care
-
640
if options[:read]
-
352
if reg[i].is_to_be_stored?
-
33
Origen.tester.store_next_cycle(swd_dio)
-
33
swd_dio.dont_care if Origen.tester.j750?
-
319
elsif reg[i].is_to_be_read?
-
129
swd_dio.assert(reg[i] ? reg[i] : 0, meta: { position: i })
-
end
-
else
-
288
swd_dio.drive(reg_or_val[i])
-
end
-
-
640
if reg[i].has_overlay? && !Origen.mode.simulation? && tester.respond_to?('label')
-
65
if reg[i].overlay_str != last_overlay_label
-
3
Origen.tester.label(reg[i].overlay_str)
-
3
last_overlay_label = reg[i].overlay_str
-
end
-
65
tester.cycle dont_compress: true
-
else
-
575
tester.cycle
-
end
-
end
-
end
-
-
# Clear read and similar flags to reflect that the request has just
-
# been fulfilled
-
22
reg_or_val.clear_flags if reg_or_val.respond_to?(:clear_flags)
-
22
swd_dio.dont_care
-
end
-
-
# Calculate exclusive OR
-
#
-
# @param [Integer] size The number of bits in the number
-
# @param [Integer] number The number being operated on
-
1
def swd_xor_calc(size, number)
-
10
xor = 0
-
10
size.times do |bit|
-
320
xor ^= (number >> bit) & 0x01
-
end
-
10
xor
-
end
-
-
# Provides shortname access to top-level SWD clock pin
-
1
def swd_clk
-
44
owner.pin(:swd_clk)
-
end
-
-
# Provides shortname access to top-level SWD data I/O pin
-
1
def swd_dio
-
1485
owner.pin(:swd_dio)
-
end
-
-
# Converts reg_or_val to reg
-
1
def to_reg(reg_or_val, options)
-
22
if reg_or_val.respond_to?(:data)
-
15
reg = reg_or_val.dup
-
else
-
7
reg = Reg.dummy(32)
-
7
if reg_or_val.nil?
-
2
reg.read(options[:compare_data]) if options[:compare_data]
-
else
-
5
reg.write(reg_or_val)
-
5
reg.read if options[:read]
-
end
-
end
-
22
reg.overlay(options[:arm_debug_overlay]) if options.key?(:arm_debug_overlay)
-
22
reg.overlay(options[:overlay_label]) if options.key?(:overlay)
-
22
reg
-
end
-
-
# Return overlay sting if same for all bits, otherwise return nil
-
1
def extract_reg_overlay(reg)
-
22
ovl = reg[0].overlay_str
-
22
reg.size.times do |i|
-
146
return nil unless reg[i].has_overlay?
-
128
return nil if ovl != reg[i].overlay_str || ovl.nil?
-
end
-
4
ovl
-
end
-
end
-
end
-
1
module OrigenSWDDev
-
# This is a dummy DUT model which is used
-
# to instantiate and test the SWD locally
-
# during development.
-
#
-
# It is not included when this library is imported.
-
1
class DUT
-
1
include Origen::TopLevel
-
1
include OrigenSWD
-
-
# Initializes simple dut model with test register and required swd pins
-
#
-
# @param [Hash] options Options to customize the operation
-
#
-
# @example
-
# $dut = OrigenSWD::DUT.new
-
#
-
1
def initialize(options = {})
-
# Sample DPACC register
-
3
add_reg :test, 0x04, 32, data: { pos: 0, bits: 32 },
-
bit: { pos: 2 }
-
-
# Sample DPACC register
-
3
add_reg :select, 0x08, 32, data: { pos: 0, bits: 32 }
-
-
# Sample APACC register
-
3
add_reg :stat, 0x00, 32, data: { pos: 0, bits: 32 }
-
3
add_reg :control, 0x01, 32, data: { pos: 0, bits: 32 }
-
-
3
add_pin :swd_clk
-
3
add_pin :swd_dio
-
end
-
-
# Add any custom startup business here.
-
#
-
# @param [Hash] options Options to customize the operation
-
1
def startup(options = {})
-
2
$tester.set_timeset('swd', 40)
-
end
-
end
-
end