OrigenARMDebug (1.3.0)

Purpose

This library provides register and memory read/write and debug control capability via the ARM Debug Interface v5 Spec.

How To Import

In your Gemfile add:

gem "origen_arm_debug", ">= 1.3.0"

or if your application is a plugin add this to your .gemspec

spec.add_development_dependency "origen_arm_debug", ">= 1.3.0"

NOTE: You will also need to include require 'origen_arm_debug' somewhere in your environment if your app is a plugin.

How To Use

The most common way to use the Arm Debugger plugin is through the Origen register API via read_register and write_register methods.

You must include a compatible physical driver depending on what debug interface your device has, one of the following can be used:

class DUT
  include Origen::TopLevel

  # Include the required physical driver, JTAG in this example
  include OrigenJTAG

  def initialize
    reg :myreg, 0x0012, size: 16 do |reg|
      reg.bits 15..8, :upper_byte
      reg.bits 7..0,  :lower_byte
    end
    
    # Simple example using default wait-states and latency:
    #   mem_ap:  APSEL = 0x00 (base_address[31:24])
    #   mem2_ap: APSEL = 0x01 (base_address[31:24], is_axi: true)        # is_axi: true for AXI-AP
    mem_aps = {
      mem_ap: { base_address: 0x00000000 },
      mem2_ap: { base_address: 0x10000000 }
    }
    sub_block :arm_debug, class_name: 'OrigenARMDebug::DAP', mem_aps: mem_aps                           
  end

  # Hook the ARMDebug module into the register API, any register read
  # requests will use the ARM Debug protocol by default
  def read_register(reg, options={})
    arm_debug.mem_ap.read_register(reg, options)
  end

  # As above for write requests
  def write_register(reg, options={})
    arm_debug.mem_ap.write_register(reg, options)
  end
end

DUT.new.myreg.write!(0x55AA)  # => Will generate the required vectors using the ARM debug protocol

You can access the lower-level API using conventional Origen register transactions:

arm_debug.sw_dp.idcode.read!(0x2BA01477)
arm_debug.sw_dp.ctrlstat.write!(0x5000_0000)  # Power-up
arm_debug.sw_dp.ctrlstat.read!(0xF0000000)    # Verify
arm_debug.ahb_ap.idr.read!(0x24770011)
arm_debug.sw_dp.select.write!(0)              # Select AHB-AP, bank 0       

# Set the SIZE field of CSW to 0x2 (32-bit transfers) + AddrInc=1
arm_debug.ahb_ap.csw.write!(0x23000052)

You can also adjust the intermediate wait-states and latency parameters:

# Assuming ahb_ap has been previously defined
dut.arm_debug.ahb_ap.apmem_access_wait = 16
dut.arm_debug.ahb_ap.apreg_access_wait = 12
dut.arm_debug.ahb_ap.latency = 8

# You can define these at instantiation as well
mem_aps = {
  mem_ap: { base_address: 0x00000000, latency: 8, apreg_access_wait: 12, apmem_access_wait: 16 }
  mem2_ap: { base_address: 0x10000000, latency: 8, apreg_access_wait: 12, apmem_access_wait: 16 }
}
sub_block :arm_debug, class_name: 'OrigenARMDebug::DAP', mem_aps: mem_aps

When used with the JTAG physical driver the default IR size is 4 and the default register select values are:

idcode_select = 0b1110
abort_select  = 0b1000
dpacc_select  = 0b1010
apacc_select  = 0b1011

You can set non-default values at instantiation like this:

mem_aps = {
  mem_ap: { base_address: 0x00000000 }
  mem2_ap: { base_address: 0x10000000 }
}
instantiation_options[:class_name] = 'OrigenARMDebug::DAP'
instantiation_options[:mem_aps] = mem_aps

instantiation_options[:ir_size] = 8
instantiation_options[:idcode_select] = 0xFE
instantiation_options[:abort_select] = 0xF8
instantiation_options[:dpacc_select] = 0xFA
instantiation_options[:apacc_select] = 0xFB
instantiation_options[:dp_select_reset] = 0xC2_0D00

sub_block :arm_debug, instantiation_options

DAP Version 6 instantiation example:

mem_aps = {
  mem_ap: { base_address: 0x001C_1000 }
  mem2_ap: { base_address: 0x001C_2000 }
}
instantiation_options[:class_name] = 'OrigenARMDebug::DAP'
instantiation_options[:mem_aps] = mem_aps

instantiation_options[:dapv6] = true

sub_block :arm_debug, instantiation_options

Company Customization

It may be the case that your application needs additional, customized Access Ports (AP) which are allowed but not defined by the standard ARM Debug Interface. The following example shows how you can use the generic AP class as a starting point and add extra registers as defined by your specific implementation.

require 'origen_arm_debug'
module ARMDebugCOMPANY
  # New AP class inherited from generic AP class provided by origen_arm_debug
  class CustomAP < OrigenARMDebug::AP
    # Initialize AP parameters and registers
    def initialize(options = {})
      super

      instantiate_registers(options)

      # Standard AP-register latency for most devices.  Can be overriden by
      #   top-level if necessary
      @apreg_access_wait = 8
    end

    # Add example registers associated with CustomAP.
    # 
    # Custom registers can also be added by ARMDebug owner with add_reg or
    #   overloading entire instantiate_registers methd
    #
    #   Ex:  arm_debug.company_ap.add_reg(:custom_reg_3, 0x08)
    def instantiate_registers(options = {})
      add_reg :custom_reg_1, 0x00
      add_reg :custom_reg_2, 0x04
    end
  end
end


class DUT
  include Origen::TopLevel
  include ARMDebugCOMPANY

  # Also include the required physical driver, JTAG in this example
  include OrigenJTAG

  def initialize
    reg :myreg, 0x0012, size: 16 do |reg|
      reg.bits 15..8, :upper_byte
      reg.bits 7..0,  :lower_byte
    end
    
    # Some standard AP parameters values
    std_memap_config = { latency: 16, apreg_access_wait: 8, apmem_access_wait: 8, csw_reset: 0x23000040 }  

    # 2 MemAPs using standard parameters (above)
    mem_aps = {
      mem_ap_0: { base_address: 0x00000000 }.merge(std_memap_config),    # AP Select = 0x00
      mem_ap_1: { base_address: 0x01000000 }.merge(std_memap_config),    # AP Select = 0x01
    }

    # Add Company-Customized AP class @ APSEL = 0x04
    custom_ap = {
      company_ap:  { class_name: 'ARMDebugCOMPANY::CustomAP', base_address: 0x04000000, apreg_access_wait: 8 }
    }

    sub_block :arm_debug, class_name: 'OrigenARMDebug::DAP',
                          base_address: 0,
                          mem_aps: mem_aps,
                          aps: custom_ap
  end
end
DUT.new.arm_debug.company_ap.custom_reg_1.write!(0x55AA)

How To Setup a Development Environment

Clone the repository from Github.

An instance of the OrigenARMDebug driver is hooked up to a dummy DUT object for use in the console:

origen i

> dut.arm_debug
=> #<OrigenARMDebug::Driver:0x0000001ee48e78>

Follow the instructions here if you want to make a 3rd party app workspace use your development copy of the OrigenARMDebug plugin: Setting up a Plugin Development Environment

This plugin also contains a test suite, makes sure this passes before committing any changes!

origen examples

Comments


Comments