module OrigenARM
module Cores
module CortexM
class CM33Controller < OrigenARM::Cores::CortexM::BaseController
def initialize(options = {})
super
end
# Initializes the core, specifically geared towards LRE setup.
# @param pc [Fixnum] The absolute address to load into the program counter.
# @param sp [Fixnum] The absolute address to load into the current stack pointer.
# @param release_core [TrueClass, FalseClass] The core will need to be held in order to initialize. However, this parameter
# can indicate whether or not the core should be released following the setup.
# @param sp_lower_limit [Fixnum] Sets stack pointer's lower limit.
# @param sp_upper_limit [Fixnum] Sets stack pointer's upper limit.
# @todo Implement lower and upper stack pointer limit setting.
def initialize_core(pc:, sp:, release_core: false, sp_lower_limit: nil, sp_upper_limit: nil)
enter_debug_mode
set_sp(sp)
set_pc(pc)
# set_stack_limits(sp_lower_limit, sp_upper_limit) if (sp_lower_limit || sp_upper_limit)
exit_debug_mode(release_core: release_core)
end
alias_method :initialize_for_lre, :initialize_core
# Enters the core's debug mode.
# @param halt_core [true, false] Indicates whether the core should be held when entering debug mode.
# Some functionality may not work correctly if the core is not halted,
# but a halted core is not a requirement for debug mode.
def enter_debug_mode(halt_core: true)
pp('Entering Debug Mode...') do
reg(:dhcsr).bits(:dbgkey).write(OrigenARM::Cores::CortexM::CM33::Registers::DHCSR_DBGKEY)
reg(:dhcsr).bits(:c_debugen).write(1)
reg(:dhcsr).write!
enter_debug_mode_delay!
if halt_core
reg(:dhcsr).bits(:dbgkey).write(OrigenARM::Cores::CortexM::CM33::Registers::DHCSR_DBGKEY)
reg(:dhcsr).bits(:c_debugen).write(1)
reg(:dhcsr).bits(:c_halt).write(1)
reg(:dhcsr).write!
enter_debug_mode_delay!
end
end
end
# Exits the core's debug mode.
# @param release_core [true, false] Indicates whether the core should be held upon exiting debug mode.
def exit_debug_mode(release_core: true)
pp('Exiting Debug Mode...') do
reg(:dhcsr).bits(:dbgkey).write(OrigenARM::Cores::CortexM::CM33::Registers::DHCSR_DBGKEY)
reg(:dhcsr).bits(:c_halt).write(0) if release_core
reg(:dhcsr).bits(:c_debugen).write(0)
reg(:dhcsr).write!
cc 'Delay for the core to exit debug mode'
exit_debug_mode_delay!
end
end
# Sets the current stack pointer.
# @param sp [Fixnum] The new stack pointer.
# @note This sets the current stack pointer. The stack pointer in question
# depends on the core's/device's mode and security settings.
# @note This requires the core to be in debug mode, otherwise a bus error will occur.
def set_sp(sp)
pp('Patch the Stack Pointer') do
reg(:sp).write!(sp)
end
end
# Sets the program counter by writing the debug_return_address
register.
# The debug_return_address
will be loaded into the PC following
# debug mode exit, effectively moving the PC.
# @param pc [Fixnum] The new program counter (debug return address).
# @note This requires the core to be in debug mode, otherwise a bus error will occur.
# @note This method will also force Thumb
mode.
def set_pc(pc)
pp('Patch the Program Counter') do
# Force the thumb bit. Nothing will work otherwise as CM33 only support THUMB
reg(:xpsr).bits(:t).write(1)
reg(:xpsr).write!
# Write the debug return address with the new PC
# Add 1 to indicate thumb mode
reg(:debug_return_address).write!(pc + 1)
end
end
# def set_stack_limits(lower_limit, upper_limits, stack: :msp, **options)
# end
end
end
end
end