Created
March 6, 2024 15:26
-
-
Save xypron/43b58aac1232e73b8eff749fbcc3b4b3 to your computer and use it in GitHub Desktop.
OpenOCD specification for PolarFire Icicle Board
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#************************************************************************** | |
# Copyright (C) 2015-2020 by Microchip Technology Inc. * | |
# http://www.microchip.com/support * | |
# * | |
# This program is free software; you can redistribute it and/or modify * | |
# it under the terms of the GNU General Public License as published by * | |
# the Free Software Foundation; either version 2 of the License, or * | |
# (at your option) any later version. * | |
# * | |
# This program is distributed in the hope that it will be useful, * | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
# GNU General Public License for more details. * | |
# * | |
# You should have received a copy of the GNU General Public License * | |
# along with this program. If not, see <http://www.gnu.org/licenses/>. * | |
#************************************************************************** | |
#------------------------------------------------------------------------------ | |
# Microsemi RISC-V | |
# | |
# https://www.microsemi.com/product-directory/embedded-processing/4406-cpus | |
#------------------------------------------------------------------------------ | |
# Device name to device family name lookup table | |
array set device_family { | |
AFS090 Fusion | |
AFS250 Fusion | |
M1AFS250 Fusion | |
U1AFS250 Fusion | |
AFS600 Fusion | |
M1AFS600 Fusion | |
P1AFS600 Fusion | |
U1AFS600 Fusion | |
AFS1500 Fusion | |
M1AFS1500 Fusion | |
P1AFS1500 Fusion | |
U1AFS1500 Fusion | |
M2GL005 IGLOO2 | |
M2GL010 IGLOO2 | |
M2GL025 IGLOO2 | |
M2GL050 IGLOO2 | |
M2GL060 IGLOO2 | |
M2GL090 IGLOO2 | |
M2GL150 IGLOO2 | |
A2F060 SmartFusion | |
A2F200 SmartFusion | |
A2F500 SmartFusion | |
M2S005 SmartFusion2 | |
M2S010 SmartFusion2 | |
M2S025 SmartFusion2 | |
M2S050 SmartFusion2 | |
M2S060 SmartFusion2 | |
M2S090 SmartFusion2 | |
M2S150 SmartFusion2 | |
A4P200 SmartFusion2 | |
} | |
# MPFS PolarFireSoC | |
# MPFS025 PolarFireSoC | |
# MPFS095 PolarFireSoC | |
# MPFS160 PolarFireSoC | |
# MPFS250 PolarFireSoC | |
# MPFS460 PolarFireSoC | |
# Device name to device IDCODEs lookup table | |
# MPFS devices each have three IDCODEs, one for each type of access - | |
# system controller, debug and trace | |
array set device_idcodes { | |
MPFS "0x0f8581cf 0x0f8781cf 0x0f8771cf 0x0f8181cf 0x0f8381cf 0x0f83c1cf 0x0f8191cf 0x0f8391cf 0x0f83d1cf 0x0f81a1cf 0x0f83a1cf 0x0f83e1cf 0x0f81b1cf 0x0f83b1cf 0x0f83f1cf" | |
MPFS025 "0x0f8581cf 0x0f8781cf 0x0f8771cf" | |
MPFS095 "0x0f8181cf 0x0f8381cf 0x0f83c1cf" | |
MPFS160 "0x0f8191cf 0x0f8391cf 0x0f83d1cf" | |
MPFS250 "0x0f81a1cf 0x0f83a1cf 0x0f83e1cf" | |
MPFS460 "0x0f81b1cf 0x0f83b1cf 0x0f83f1cf" | |
RTPFS "0x0F8991CF 0x0F8B91CF 0x0F8BD1CF 0x0F89B1CF 0x0F8BB1CF 0x0F8BF1CF" | |
RTPFS160 "0x0F8991CF 0x0F8B91CF 0x0F8BD1CF" | |
RTPFS460 "0x0F89B1CF 0x0F8BB1CF 0x0F8BF1CF" | |
} | |
# Device name to device eNVM size lookup table | |
array set device_envm_size { | |
AFS090 0x40000 | |
AFS250 0x40000 | |
M1AFS250 0x40000 | |
U1AFS250 0x40000 | |
AFS600 0x80000 | |
M1AFS600 0x80000 | |
P1AFS600 0x80000 | |
U1AFS600 0x80000 | |
AFS1500 0x100000 | |
M1AFS1500 0x100000 | |
P1AFS1500 0x100000 | |
U1AFS1500 0x100000 | |
M2GL005 0x20000 | |
M2GL010 0x40000 | |
M2GL025 0x40000 | |
M2GL050 0x40000 | |
M2GL060 0x40000 | |
M2GL090 0x80000 | |
M2GL150 0x80000 | |
A2F060 0x20000 | |
A2F200 0x40000 | |
A2F500 0x80000 | |
M2S005 0x20000 | |
M2S010 0x40000 | |
M2S025 0x40000 | |
M2S050 0x40000 | |
M2S060 0x40000 | |
M2S090 0x80000 | |
M2S150 0x80000 | |
A4P200 0x20000 | |
} | |
# What size is MPFS envm? | |
# MPFS 0x20000 | |
# MPFS025 0x20000 | |
# MPFS095 0x20000 | |
# MPFS160 0x20000 | |
# MPFS250 0x20000 | |
# MPFS460 0x20000 | |
# Device family name to device eNVM driver name lookup table | |
# Note that microsemi-smartfusion2-envm works for SmartFusion2 and IGLOO2 | |
array set envm_driver { | |
Fusion microsemi-fusion-coreahbnvm | |
IGLOO2 microsemi-smartfusion2-envm | |
SmartFusion microsemi-smartfusion-envm | |
SmartFusion2 microsemi-smartfusion2-envm | |
} | |
# PolarFireSoC microsemi-polarfire-soc-envm | |
# Device family name to device eNVM default base address lookup table | |
# Fusion envm base address arbitrarily defaulted to 0x00000000 | |
array set envm_base { | |
Fusion 0x00000000 | |
IGLOO2 0x60000000 | |
SmartFusion 0x60000000 | |
SmartFusion2 0x60000000 | |
} | |
# PolarFireSoC 0x20200000 or 0x20220000? | |
# PolarFire SoC (MPFS) hart id to name lookup table | |
array set mpfs_hart_name { | |
0 hart0_e51 | |
1 hart1_u54_1 | |
2 hart2_u54_2 | |
3 hart3_u54_3 | |
4 hart4_u54_4 | |
} | |
# | |
# Process DEVICE variable | |
# | |
if {![exists DEVICE]} { | |
# Not set so default to the generic "FPGA" | |
set DEVICE "FPGA" | |
} else { | |
# Normalise - convert to lowercase | |
set DEVICE [string toupper $DEVICE] | |
# PolarFire SoC/MPFS TODOs | |
# device size (MPFSxxx) | |
# envm | |
# soft core Mi-V in PF SoC fabric | |
# Treat "G5SOC" as legacy synonym for "MPFS" | |
if {[string range $DEVICE 0 4] eq "G5SOC"} { | |
set DEVICE "MPFS" | |
} | |
# MPFS has one FPGA top level TAP for FPGA access & RISC-V multi-core debug | |
if {[string range $DEVICE 0 3] eq "MPFS"} { | |
set DEVICE [string range $DEVICE 0 6] | |
set FPGA_TAP "N" | |
} | |
# Look up DEVICE envm/flash details | |
if {[exists device_family($DEVICE)]} { | |
# if found then default flash parameters unless already set | |
if {![exists FLASH_DRIVER]} { | |
set FLASH_DRIVER $envm_driver($device_family($DEVICE)) | |
} | |
if {![exists FLASH_BASE]} { | |
set FLASH_BASE $envm_base($device_family($DEVICE)) | |
} | |
if {![exists FLASH_SIZE]} { | |
set FLASH_SIZE $device_envm_size($DEVICE) | |
} | |
} | |
} | |
# IRCODE needed to address UJTAG/uj_jtag slave | |
if {![exists UJ_JTAG_IRCODE]} { | |
# TODO: validate - e.g. 2 hex digit value | |
set UJ_JTAG_IRCODE 0x55 | |
} | |
# COREID | |
# For PolarFire SoC (MPFS) check COREID, default to -1 (single debug connection | |
# to all harts) if unspecified or invalid (out of range [-1..4]) | |
if {[string range $DEVICE 0 3] eq "MPFS"} { | |
if {[exists COREID]} { | |
if {[expr (($COREID < -1) || ($COREID > 4))]} { | |
echo [format "Warn : COREID %s not in range (-1..4), defaulting to -1 (single connection to all harts)" $COREID] | |
set COREID -1 | |
} | |
} else { | |
# echo "Info : COREID not specified so defaulting to -1 (single debug connection to all harts)" | |
set COREID -1 | |
} | |
} | |
# Convert DEVICE to lowercase | |
set DEVICE [string tolower $DEVICE] | |
if {$FPGA_TAP eq "Y"} { | |
# FPGA TAP present, occludes RISC-V CPU DTM TAP and must be disabled/bypassed first | |
# Start off in standard JTAG mode | |
microsemi_flashpro tunnel_jtag_via_ujtag off | |
# | |
# FPGA TAP | |
# | |
jtag newtap $DEVICE tap -irlen 8 -expected-id 0 -ignore-version | |
jtag configure $DEVICE.tap -event tap-disable "disable_fpga_tap $DEVICE.tap" | |
jtag configure $DEVICE.tap -event setup "switch_from_fpga_tap_to_riscv_tap $DEVICE.tap $DEVICE.cpu" | |
# | |
# RISC-V CPU DTM TAP - disabled/not visible by default until FPGA TAP disabled/bypassed | |
# | |
jtag newtap $DEVICE cpu -irlen 5 -expected-id 0x10e31913 -expected-id 0x1c0011cf -disable | |
jtag configure $DEVICE.cpu -event tap-enable enable_riscv_tap | |
# | |
# TAP management event handlers/procedures | |
# | |
# Switch from FPGA TAP to RISC-V CPU DTM TAP (by tunnelling JTAG via UJTAG) | |
proc switch_from_fpga_tap_to_riscv_tap {fpga_tap riscv_tap} { | |
jtag tapdisable $fpga_tap | |
jtag tapenable $riscv_tap | |
# Read RISC-V CPU DTM IDCODE as a sanity check | |
irscan $riscv_tap 0x01 | |
set idcode [string tolower [drscan $riscv_tap 32 0]] | |
echo [format "Info : RISC-V IDCODE = 0x%s" $idcode] | |
} | |
# Disable/bypass FPGA TAP | |
proc disable_fpga_tap {fpga_tap} { | |
global UJ_JTAG_IRCODE | |
# Tell UJTAG/uj_jtag to address RISC-V CPU DTM | |
irscan $fpga_tap $UJ_JTAG_IRCODE -endstate IRPAUSE | |
runtest 8 | |
# Enable tunnelled JTAG mode | |
microsemi_flashpro tunnel_jtag_via_ujtag on | |
} | |
# Enable RISC-V CPU DTM TAP | |
proc enable_riscv_tap {} { | |
# Nothing to do here - the work is done in disable_fpga_tap | |
# but the handler still needs to be defined | |
} | |
} else { | |
# "Direct" debugging not via FPGA TAP | |
# Select appropriate irlen and expected idcodes | |
if {[string range $DEVICE 0 3] eq "mpfs"} { | |
set IRLEN 8 | |
set EXPECTED_IDS "-expected-id 0x0f8581cf -expected-id 0x0f8781cf -expected-id 0x0f8771cf -expected-id 0x0f8181cf -expected-id 0x0f8381cf -expected-id 0x0f83c1cf -expected-id 0x0f8191cf -expected-id 0x0f8391cf -expected-id 0x0f83d1cf -expected-id 0x0f81a1cf -expected-id 0x0f83a1cf -expected-id 0x0f83e1cf -expected-id 0x0f81b1cf -expected-id 0x0f83b1cf -expected-id 0x0f83f1cf" | |
} else { | |
set IRLEN 5 | |
set EXPECTED_IDS "-expected-id 0x10e31913 -expected-id 0x1c0011cf -expected-id 0x1e50105f -ignore-version" | |
} | |
# RISC-V CPU DTM TAP | |
eval jtag newtap $DEVICE cpu -irlen $IRLEN $EXPECTED_IDS | |
} | |
# | |
# Target CPU | |
# | |
if {[string range $DEVICE 0 3] eq "mpfs"} { | |
# PolarFire SoC (MPFS) | |
if {$COREID eq -1} { | |
# Single debug connection to all harts | |
set _TARGETNAME_0 $DEVICE.$mpfs_hart_name(0) | |
set _TARGETNAME_1 $DEVICE.$mpfs_hart_name(1) | |
set _TARGETNAME_2 $DEVICE.$mpfs_hart_name(2) | |
set _TARGETNAME_3 $DEVICE.$mpfs_hart_name(3) | |
set _TARGETNAME_4 $DEVICE.$mpfs_hart_name(4) | |
target create $_TARGETNAME_0 riscv -chain-position $DEVICE.cpu -coreid 0 -rtos hwthread | |
target create $_TARGETNAME_1 riscv -chain-position $DEVICE.cpu -coreid 1 | |
target create $_TARGETNAME_2 riscv -chain-position $DEVICE.cpu -coreid 2 | |
target create $_TARGETNAME_3 riscv -chain-position $DEVICE.cpu -coreid 3 | |
target create $_TARGETNAME_4 riscv -chain-position $DEVICE.cpu -coreid 4 | |
target smp $_TARGETNAME_0 $_TARGETNAME_1 $_TARGETNAME_2 $_TARGETNAME_3 $_TARGETNAME_4 | |
$_TARGETNAME_1 configure -event reset-init init_regs | |
$_TARGETNAME_2 configure -event reset-init init_regs | |
$_TARGETNAME_3 configure -event reset-init init_regs | |
$_TARGETNAME_4 configure -event reset-init init_regs | |
} else { | |
# Debug connection to a specific hart | |
set _TARGETNAME_0 $DEVICE.$mpfs_hart_name($COREID) | |
target create $_TARGETNAME_0 riscv -chain-position $DEVICE.cpu -coreid $COREID | |
} | |
} else { | |
# Mi-V soft core - implicitly single hart | |
set _TARGETNAME_0 $DEVICE.miv | |
target create $_TARGETNAME_0 riscv -chain-position $DEVICE.cpu | |
} | |
$_TARGETNAME_0 configure -event reset-init board_reset_init | |
$_TARGETNAME_0 configure -event reset-init init_regs | |
# | |
# Flash | |
# | |
# | |
# Flash may be defined via parameters: | |
# FLASH_DRIVER: cfi or microsemi-fusion-coreahbnvm (for Fusion/AFSXXX) or | |
# microsemi-smartfusion2-envm (for SmartFusion2/M2SXXX) or | |
# microsemi-smartfusion-envm (for SmartFusion/A2FXXX) or | |
# microsemi-polarfire-soc-envm (for PolarFire SoC/MPFSXXX) | |
# FLASH_BASE - e.g. 0x10000000 | |
# FLASH_SIZE - e.g. 0x8000 | |
# FLASH_WIDTH - e.g. 0, 1, 2 or 4 or not defined (defaults to 0) | |
# If FLASH_DRIVER is defined then the other parameters are assumed to be defined | |
# and to be valid | |
# | |
if {[exists FLASH_DRIVER]} { | |
flash bank $DEVICE.flash $FLASH_DRIVER $FLASH_BASE $FLASH_SIZE 0 0 $_TARGETNAME_0 | |
} | |
# | |
# Reset configuration | |
# | |
# Only TRSTn supported | |
reset_config trst_only | |
# | |
# Utility procedures | |
# | |
proc board_reset_init {} { | |
# call board level reset-init if defined | |
if {[exists -proc do_board_reset_init]} { | |
do_board_reset_init | |
} | |
} | |
proc init_regs {} { | |
reg pc 0 | |
} | |
# gdb-detach event handler | |
$_TARGETNAME_0 configure -event gdb-detach { | |
# resume execution on debugger detach | |
resume | |
} | |
# TODO: why does this eliminate the second (redundant?) probe/examine? | |
proc init_reset {mode} { | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment