-
2
module OrigenNexus
-
2
class Driver
-
# Include JTAG driver instance to fall back on (if owner doesn't have)
-
2
include OrigenJTAG
-
-
# Allow for JTAG optionality
-
# blank for now
-
2
JTAG_CONFIG = {}
-
-
# Include registers as Nexus has its own registers
-
2
include Origen::Registers
-
-
2
alias_method :local_jtag, :jtag
-
-
# Returns the underlying JTAG driver. If the owner has its own JTAG driver
-
# then this will be returned, otherwise it will be a fall back driver included
-
# by the Nexus module.
-
2
def jtag
-
741
owner.respond_to?(:jtag) ? owner.jtag : local_jtag
-
end
-
-
# Returns the object that included the Nexus module,
-
# should always be the top-level model
-
2
attr_reader :owner
-
-
# OnCE Command Register (OCMD) width in bits
-
# OnCE (On-Chip Emulation)
-
2
attr_reader :once_ocmd_width
-
-
# The OnCE Nexus access instruction (NEXUS-ACCESS)
-
# OnCE command value to enable Nexus
-
2
attr_reader :once_nexus_access_instr
-
-
# The OnCE bypass instruction (BYPASS)
-
# OnCE command value to bypass OnCE
-
2
attr_reader :once_bypass_instr
-
-
# Nexus command width
-
# width of commands used in first DR pass to read/write
-
# a Nexus register
-
2
attr_reader :nexus_command_width
-
-
2
attr_reader :cpuscr_reg_width
-
-
2
attr_reader :once_cpuscr_go_exit_instr
-
-
2
def initialize(owner, options = {})
-
17
if defined?(owner.class::NEXUS_CONFIG)
-
16
options = owner.class::NEXUS_CONFIG.merge(options)
-
end
-
-
# Fallback defaults
-
17
options = {
-
tclk_format: :rh, # format of JTAG clock used: ReturnHigh (:rh), ReturnLo (:rl)
-
tclk_multiple: 1, # number of cycles for one clock pulse, assumes 50% duty cycle. Uses tester non-return format to spread TCK across multiple cycles.
-
# e.g. @tclk_multiple = 2, @tclk_format = :rh, means one cycle with Tck low (non-return), one with Tck high (NR)
-
# @tclk_multiple = 4, @tclk_format = :rl, means 2 cycles with Tck high (NR), 2 with Tck low (NR)
-
tdo_strobe: :tclk_high, # when using multiple cycles for TCK, which state of TCK to strobe for TDO, :tclk_high or :tclk_low or :tclk_all
-
tdo_store_cycle: 0, # store vector cycle within TCK (i.e. when to indicate to tester to store vector within TCK cycle. 0 is first vector, 1 is second, etc.)
-
#
-
once_ocmd_width: 10, # Width of OnCE OCMD instruction reg in bits
-
once_nexus_access_instr: 0b0001111100, # Instruction used to access nexus via OnCE, default: 0x07C.
-
once_bypass_instr: 0b0001111111, # Instruction used to bypass OnCE, default: 0x07F.
-
once_cpuscr_go_exit_instr: 0b0110010000, # Instruction used to exit debug mode and kick off code execution from desired address.
-
nexus_command_width: 8, # Width of Nexus command data regs, default: 8.
-
cpuscr_reg_width: 192, # Width of cpuscr reg
-
}.merge(options)
-
-
# Define JTAG configs based on Nexus config
-
17
JTAG_CONFIG[:tclk_format] = options[:tclk_format]
-
17
JTAG_CONFIG[:tclk_multiple] = options[:tclk_multiple]
-
17
JTAG_CONFIG[:tdo_strobe] = options[:tdo_strobe]
-
17
JTAG_CONFIG[:tdo_store_cycle] = options[:tdo_store_cycle]
-
-
17
@once_ocmd_width = options[:once_ocmd_width]
-
17
@once_nexus_access_instr = options[:once_nexus_access_instr]
-
17
@once_bypass_instr = options[:once_bypass_instr]
-
17
@once_cpuscr_go_exit_instr = options[:once_cpuscr_go_exit_instr]
-
17
@nexus_command_width = options[:nexus_command_width]
-
17
@cpuscr_reg_width = options[:cpuscr_reg_width]
-
-
# Define nexus registers
-
17
define_nexus_registers
-
-
# Define CPU registers
-
17
define_cpu_registers
-
-
17
@owner = owner
-
end
-
-
2
def on_created
-
end
-
-
# This proxies all pin requests from our local JTAG driver to
-
# our parent DUT model
-
2
def pin(*args)
-
176684
owner.pin(*args)
-
end
-
2
alias_method :pins, :pin
-
-
# Define Nexus registers
-
# For now only those related to RWA will be defined.
-
# RWA (read/write access) provides DMA-like access to memory-mapped resources on
-
# the AHB system bus either while the processor is halted or during runtime.
-
2
def define_nexus_registers
-
# Each register has a Nexus Opcode, which we will use as 'address' below, and
-
# corresponding read addresses and write addresses
-
-
# RWCS - Read/Write Access Control Register
-
# read addr = 0x0E, write addr = 0x0F
-
17
reg :rwcs, 0x0E, size: 32 do
-
17
bit 31, :ac
-
17
bit 30, :rw
-
17
bit 29..27, :sz
-
17
bit 26..24, :map
-
17
bit 23..22, :pr
-
17
bit 15..2, :cnt
-
17
bit 1, :err, writable: false
-
17
bit 0, :dv, writable: false
-
end
-
-
# RWD - Read/Write Access Data
-
# read addr = 0x12, write addr = 0x13
-
17
reg :rwa, 0x12, size: 32 do
-
17
bit 31..0, :addr
-
end
-
-
# RWD - Read/Write Access Data
-
# read addr = 0x14, write addr = 0x15
-
17
reg :rwd, 0x14, size: 32 do
-
17
bit 31..0, :data
-
end
-
end
-
-
2
def define_cpu_registers
-
17
reg :cpuscr, 0x0, size: 192 do
-
17
bit 191..160, :ctl
-
17
bit 159..128, :ir
-
17
bit 127..96, :pc
-
17
bit 95..64, :msr
-
17
bit 63..32, :wbbrh
-
17
bit 31..0, :wbbrl
-
end
-
end
-
-
# Enable Nexus module
-
# Loads NEXUS-ACCESS instruction into JTAG Instruction
-
# Register (OnCE OCMD register).
-
# repeated calls will not generate vectors if the instruction
-
# is already loaded
-
#
-
# Optionally also accepts a block to allow temporary Nexus access
-
#
-
# nexus.enable_nexus_access do
-
# # Do something with nexus enabled
-
# end
-
# # Nexus access disabled
-
#
-
2
def enable_nexus_access
-
96
if @ir_reg_value != once_nexus_access_instr
-
20
jtag.write_ir once_nexus_access_instr, size: once_ocmd_width, msg: log2("Enable Nexus Access: OnCE_Send(#{once_ocmd_width}, 0x%02X)" % [once_nexus_access_instr])
-
20
@ir_reg_value = once_nexus_access_instr
-
end
-
96
if block_given?
-
4
yield
-
4
disable_once
-
end # whether to mark all bits in RWD for read
-
end
-
-
# Disable OnCE
-
2
def disable_once
-
8
if @ir_reg_value != once_bypass_instr
-
8
jtag.write_ir once_bypass_instr, size: once_ocmd_width, msg: log2("Bypass OnCE: OnCE_Send(#{once_ocmd_width}, 0x%02X)" % [once_bypass_instr])
-
8
@ir_reg_value = once_bypass_instr
-
end
-
end
-
-
2
def go_exit(code_start_address = 0x4)
-
jtag.write_ir once_cpuscr_go_exit_instr, size: once_ocmd_width, msg: log2('Enabling CPUSCR register for read/write access')
-
regs(:cpuscr).bit(:wbbrl).write(0x00000000)
-
regs(:cpuscr).bit(:wbbrh).write(0x00000000)
-
regs(:cpuscr).bit(:msr).write(0x00000000)
-
regs(:cpuscr).bit(:pc).write(code_start_address - 4)
-
regs(:cpuscr).bit(:ir).write(0x7c0004ac)
-
regs(:cpuscr).bit(:ctl).write(0x00000000)
-
jtag.write_dr regs(:cpuscr).value, size: cpuscr_reg_width, msg: log2('Writing GO+EXIT to CPUSCR')
-
end
-
-
# Write a given Nexus register
-
2
def write_nexus_register(reg_or_val, options = {})
-
348
options = { write: true, # whether to write or read
-
overlay: false,
-
care_out: false
-
}.merge(options)
-
348
addr = exact_address(reg_or_val, options)
-
348
addr += 1 if options[:write] # offset address by 1 since writing
-
348
data = exact_data(reg_or_val, options)
-
348
size = exact_size(reg_or_val, options)
-
348
name = exact_name(reg_or_val, options)
-
-
348
if options[:write]
-
244
log "Write Nexus Reg: #{name.upcase} at 0x%04X with 0x%08X" % [addr, data]
-
else
-
104
log "Read Nexus Reg: #{name.upcase} at 0x%04X with 0x%08X" % [addr, data]
-
end
-
-
# first pass : select register via nexus command
-
348
jtag.write_dr addr, size: nexus_command_width, msg: log2("OnCE_Send(#{nexus_command_width}, 0x%02X)" % [addr])
-
348
if options[:overlay] == true
-
# if we want to overlay expect values, then
-
# put dummy data in vectors to force them to be uncompressable by pattern generator.
-
reg_or_val.data = 0x55555555
-
data = exact_data(reg_or_val, options)
-
end
-
-
348
if options[:capture]
-
16
reg(reg_or_val.name).store
-
end
-
-
348
if options[:write]
-
# second pass : pass data to register
-
244
jtag.write_dr reg_or_val, overlay: options[:overlay], overlay_label: options[:overlay_label], size: size, msg: log2("OnCE_Send(#{size}, 0x%08X)" % [data])
-
else
-
104
if options[:care_output]
-
16
reg(reg_or_val.name).read
-
end
-
# second pass : read data from register
-
104
jtag.read_dr(reg_or_val, overlay: options[:overlay], overlay_label: options[:overlay_label], size: size, msg: log2("OnCE_Read(#{size}, 0x%08X)" % [data]))
-
end
-
end
-
-
# Read a given Nexus register
-
2
def read_nexus_register(reg_or_val, options = {})
-
104
write_nexus_register(reg_or_val, options.merge(write: false))
-
end
-
-
# Write data cycles only for a Register
-
# Used if only want data cycles for overlay subroutines
-
2
def write_data_only(reg_or_val, options = {})
-
16
options = { write: true, # whether to write or read
-
}.merge(options)
-
-
16
data = exact_data(reg_or_val, options)
-
-
# Size of RWD register being used for output
-
16
size = reg(:rwd).size
-
-
# if reading a real register then need to handle copying over all data and flags
-
# undefined regs will be handled in lower function so that default is to treat
-
# as undefined reg (just simple accesses)
-
16
reg(:rwd).overlay(nil) # clear overlay flags if there, as sticky
-
16
if real_reg?(reg_or_val)
-
8
reg(:rwd).copy_all(reg_or_val)
-
end
-
-
16
if options[:write]
-
# Send command to write RWD reg
-
# Send data value to be written to RWD reg
-
8
reg(:rwd).write(data)
-
-
8
jtag.shift(reg(:rwd), options.merge(size: size, cycle_last: true, includes_last_bit: true))
-
-
else
-
# Mark all bits for read
-
8
reg(:rwd).read
-
-
8
jtag.shift(reg(:rwd), options.merge(size: size, read: true, cycle_last: true, includes_last_bit: true))
-
-
end
-
-
# Clear flags so as to not affect subsequent reg reads/writes
-
16
reg(:rwd).clear_flags
-
16
reg_or_val.clear_flags if reg_or_val.respond_to?(:clear_flags)
-
end
-
-
# Read data cycles only for RWD Register
-
2
def read_data_only(reg_or_val, options = {})
-
8
write_data_only(reg_or_val, options.merge(write: false))
-
end
-
-
# Single Write to memory-mapped resource
-
# for now only supports 32-bit data
-
2
def single_write_access(address, data, options = {})
-
92
options = { write: true, # whether to write or read the register
-
undef: true, # whether IPS being accessed is a register or undefined
-
count: 1, # by default use single address access mode
-
overlay: false, # default: assume not a real register
-
nexus_init: true,
-
width: 32, # default write width to 32 bits
-
}.merge(options)
-
92
if options[:width] == 8
-
write_width = 0b0
-
elsif options[:width] == 16
-
write_width = 0b1
-
elsif options[:width] == 32
-
84
write_width = 0b10
-
elsif options[:width] == 64
-
8
write_width = 0b11
-
else
-
Origen.log.warn 'Nexus 3 width supplied is invalid, defaulting to 32 bit width.'
-
end
-
-
92
if options[:nexus_init]
-
92
enable_nexus_access
-
end
-
# Send command to write RWA reg
-
# Send address value to RWA reg
-
92
reg(:rwa).write(address)
-
92
write_nexus_register(reg(:rwa))
-
-
# Send command to write RWCS reg
-
# Send settings to RWCS
-
92
reg(:rwcs).bits(:ac).write(1)
-
92
reg(:rwcs).bits(:rw).write(options[:write] ? 1 : 0)
-
92
reg(:rwcs).bits(:sz).write(write_width) # write_width, defaul value = 32 bits.
-
92
reg(:rwcs).bits(:map).write(0b000) # map select = primary
-
92
reg(:rwcs).bits(:pr).write(0b11) # priority = highest
-
92
reg(:rwcs).bits(:cnt).write(options[:count]) # single access
-
92
reg(:rwcs).bits(:err).write(0) # read/write access error
-
92
reg(:rwcs).bits(:dv).write(0) # read/write access data valid
-
92
write_nexus_register(reg(:rwcs))
-
-
92
if options[:write]
-
# Send command to write RWD reg
-
# Send data value to be written to RWD reg
-
36
reg(:rwd).write(data)
-
268
write_nexus_register(reg(:rwd), options.reject { |x| x == :address })
-
else
-
# If undefined reg, then mark all bits for read
-
56
if options[:undef]
-
24
reg(:rwd).read
-
end
-
# Send command to read RWD reg
-
# Read RWD reg value
-
56
reg(:rwd).write(data)
-
428
read_nexus_register(reg(:rwd), options.reject { |x| x == :address })
-
end
-
end
-
-
# Single Read from memory-mapped resource
-
# for now only supports 32-bit data
-
2
def single_read_access(address, data, options = {})
-
4
single_write_access(address, data, options.merge(write: false))
-
end
-
-
# Block Write to memory-mapped resources
-
# for now only supports 32-bit data
-
#
-
# address = address at start of block
-
# block_data = array of 32-bit values of block data to write
-
2
def block_write_access(address, block_data = [], options = {})
-
24
options = { write: true, # whether to write or read the block
-
width: 32 # width default to 32 bits
-
}.merge(options)
-
24
block_data.each_index do |i|
-
96
if i == 0 # first do single write access with count > 1
-
24
single_write_access(address, block_data[0], options.merge(count: block_data.count))
-
24
if options[:width] > 32
-
8
reg(:rwd).write(block_data[i = i + 1])
-
8
if options[:write]
-
4
write_nexus_register(reg(:rwd), options)
-
else
-
4
read_nexus_register(reg(:rwd), options)
-
end
-
end
-
else
-
72
next if i.odd? && options[:width] > 32
-
56
reg(:rwd).write(block_data[i])
-
56
if options[:write]
-
16
write_nexus_register(reg(:rwd), options)
-
else
-
40
read_nexus_register(reg(:rwd), options)
-
end
-
56
if options[:width] > 32
-
8
reg(:rwd).write(block_data[i = i + 1])
-
8
if options[:write]
-
4
write_nexus_register(reg(:rwd), options)
-
else
-
4
read_nexus_register(reg(:rwd), options)
-
end
-
end
-
end
-
end
-
end
-
-
# Block Read of memory-mapped resources
-
# for now only supports 32-bit data
-
#
-
# address = address at start of block
-
# block_data = array of 32-bit values of block data to read
-
2
def block_read_access(address, block_data = [], options = {})
-
16
block_write_access(address, block_data, options.merge(write: false))
-
end
-
-
# def test_read_flag(reg_to_check)
-
# reg_to_check.size.times do |i|
-
# if reg_to_check.bit(i).is_to_be_read?
-
# print "\t\tBIT #{i} of #{reg_to_check.name.upcase} has read flag!\n"
-
# else
-
# print "\t\tBIT #{i} of #{reg_to_check.name.upcase} DOES NOT HAVE read flag!\n"
-
# end
-
# end
-
# end
-
#
-
# def test_store_flag(reg_to_check)
-
# reg_to_check.size.times do |i|
-
# if reg_to_check.bit(i).is_to_be_stored?
-
# print "\t\tBIT #{i} of #{reg_to_check.name.upcase} has store flag!\n"
-
# else
-
# print "\t\tBIT #{i} of #{reg_to_check.name.upcase} DOES NOT HAVE store flag!\n"
-
# end
-
# end
-
# end
-
#
-
# def test_overlay_flag(reg_to_check, options={})
-
# options={:msg => ""}.merge(options)
-
# reg_to_check.size.times do |i|
-
# if reg_to_check.bit(i).has_overlay?
-
# print "\t\t#{options[:msg]}: BIT #{i} of #{reg_to_check.name.upcase} has overlay flag!\n"
-
# else
-
# print "\t\t#{options[:msg]}: BIT #{i} of #{reg_to_check.name.upcase} DOES NOT HAVE overlay flag!\n"
-
# end
-
# end
-
-
# determines whether real register or not
-
2
def real_reg?(reg_or_val)
-
1772
reg_or_val.respond_to?(:name)
-
end
-
-
# Write the given register (or system memory location) or given value to a specified address
-
# reg_or_val := register symbol to use -- assumes register preloaded with
-
# required data to use, can override by using :address option
-
# in which case data to use provided here
-
#
-
# options[:address] := address to write to. This is mandatory in the case of the
-
# reg_or_val argument being a value (for data), if it is a
-
# Register object then this is optional and if present then
-
# will override the register's address.
-
#
-
2
def write_register(reg_or_val, options = {})
-
60
options = { write: true, # whether to write or read the register
-
overlay: false
-
}.merge(options)
-
60
address = exact_address(reg_or_val, options)
-
60
data = exact_data(reg_or_val, options)
-
60
size = exact_size(reg_or_val, options)
-
60
name = (exact_name(reg_or_val, options)).upcase
-
-
60
op = options[:write] ? 'Write' : 'Read'
-
-
# Set undefined register flag to override option for simple_write_access below
-
60
options[:undef] = !real_reg?(reg_or_val)
-
-
# if reading a real register then need to handle copying over all data and flags
-
# undefined regs will be handled in lower function so that default is to treat
-
# as undefined reg (just simple accesses)
-
60
reg(:rwd).overlay(nil) # clear overlay flags if there, as sticky
-
60
if real_reg?(reg_or_val)
-
48
reg(:rwd).copy_all(reg_or_val)
-
end
-
-
60
cc "**************************** NEXUS REGISTER #{op.upcase} BEGIN ****************************"
-
60
cc "- #{op} Register #{name}: addr: 0x%08X, data: 0x%08X\n" % [address, data]
-
60
single_write_access(address, data, options)
-
60
cc "**************************** NEXUS REGISTER #{op.upcase} END ****************************"
-
-
# Clear flags so as to not affect subsequent reg reads/writes
-
60
reg(:rwd).clear_flags
-
60
reg_or_val.clear_flags if reg_or_val.respond_to?(:clear_flags)
-
end
-
2
alias_method :write, :write_register
-
-
# Read the given register (or system memory location) or given value from a specified address
-
# reg_or_val := register symbol to use -- assumes register preloaded with
-
# required data to use, can override by using :address option
-
# in which case data to use provided here
-
#
-
# options[:address] := address to read from. This is mandatory in the case of the
-
# reg_or_val argument being a value (for data), if it is a
-
# Register object then this is optional and if present then
-
# will override the register's address.
-
#
-
2
def read_register(reg_or_val, options = {})
-
36
write_register(reg_or_val, options.merge(write: false))
-
end
-
2
alias_method :read, :read_register
-
-
# Provides exact address value either if a defined register is
-
# provided or if an address is provided
-
2
def exact_address(reg_or_val, options = {})
-
408
address = options[:addr] || options[:address]
-
408
unless address
-
# if no address provided as option then use register address
-
396
if real_reg?(reg_or_val) # if real register
-
396
address = reg_or_val.address # use register address
-
else
-
fail "An :address option must be supplied when not providing a register to Nexus!\n"
-
end
-
end
-
408
address
-
end
-
-
# Provides exact data value either if a defined register is
-
# provided or if an address is provided
-
2
def exact_data(reg_or_val, _options = {})
-
# if no data provided as option then use register data
-
424
if real_reg?(reg_or_val) # if real register
-
404
data = reg_or_val.data # use register value
-
else
-
20
data = reg_or_val # use reg_or_val passed as data
-
end
-
424
data
-
end
-
-
# Provide size of register if real register passed--
-
# otherwise indicate number of bits of data value
-
2
def exact_size(reg_or_val, _options = {})
-
408
if real_reg?(reg_or_val) # if real register
-
396
size = reg_or_val.size # use register size
-
else
-
12
size = reg_or_val.to_s(2).size # get number of bits in value
-
end
-
408
size
-
end
-
-
# Provide name of register, if real register passed
-
# otherwise given 'undef' as name
-
2
def exact_name(reg_or_val, _options = {})
-
408
if real_reg?(reg_or_val) # if real register
-
396
name = reg_or_val.name # use register name
-
else
-
12
name = 'undef' # undefined register
-
end
-
408
name
-
end
-
-
2
def log2(msg)
-
1072
"Nexus::Driver - #{msg}"
-
end
-
-
2
def log(msg)
-
348
cc "#{log2(msg)}"
-
end
-
end
-
end