diff --git a/.checkpatch.conf b/.checkpatch.conf new file mode 100644 index 0000000000..8cb9a3729a --- /dev/null +++ b/.checkpatch.conf @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +--max-line-length=120 +--tab-size=4 +--show-types +--strict + +--typedefsfile tools/scripts/typedefs.txt + +--ignore AVOID_EXTERNS +--ignore BLOCK_COMMENT_STYLE +--ignore COMPLEX_MACRO +--ignore CONST_STRUCT +--ignore ENOSYS +--ignore FILE_PATH_CHANGES +--ignore GERRIT_CHANGE_ID +--ignore LINE_SPACING +--ignore LOGICAL_CONTINUATIONS +--ignore MACRO_WITH_FLOW_CONTROL +--ignore NEW_TYPEDEFS +--ignore PARENTHESIS_ALIGNMENT +--ignore PREFER_DEFINED_ATTRIBUTE_MACRO +--ignore PREFER_FALLTHROUGH +--ignore PREFER_KERNEL_TYPES +--ignore SPLIT_STRING +--ignore SSCANF_TO_KSTRTO +--ignore SWITCH_CASE_INDENT_LEVEL +--ignore TRACING_LOGGING +--ignore VOLATILE diff --git a/.github/workflows/checkpatch.yml b/.github/workflows/checkpatch.yml index c9ec78d596..b7f3ebaf53 100644 --- a/.github/workflows/checkpatch.yml +++ b/.github/workflows/checkpatch.yml @@ -10,18 +10,23 @@ jobs: BUILD_DIR: ../build steps: - name: Checkout Code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: - fetch-depth: 50 + fetch-depth: 0 + - name: Checkout Base + run: | + git fetch origin ${{ github.event.pull_request.base.ref }} + echo "The current base for checkpatch is: $(git show FETCH_HEAD --oneline --raw)" - name: Install required packages (apt-get) run: | sudo apt-get update - sudo apt-get install patchutils + sudo apt-get install patchutils python3-ply python3-git - name: Run checkpatch run: | - git diff -U20 HEAD~40 \ + git diff --patch FETCH_HEAD \ | filterdiff \ -x "a/src/jtag/drivers/libjaylink/*" \ -x "a/tools/git2cl/*" \ -x "a/.github/*" \ + -x "a/HACKING" \ | ./tools/scripts/checkpatch.pl --no-signoff - diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index f566d8c903..01e230ce3f 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -5,7 +5,7 @@ name: Linux Build jobs: # 32-bit, clang build32: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 env: CFLAGS: -m32 CC: clang @@ -22,7 +22,6 @@ jobs: - run: file src/openocd | grep 32-bit - run: src/openocd --version - # 64-bit, gcc build64: runs-on: ubuntu-latest @@ -31,13 +30,32 @@ jobs: CC: gcc steps: - name: Checkout Code - uses: actions/checkout@v2 + uses: actions/checkout@v3 + - name: Configure environment + run: | + TAG=$(git rev-parse --short HEAD) + echo "TAG=$TAG" >> $GITHUB_OUTPUT + echo "NAME=openocd64-$TAG" >> $GITHUB_ENV - name: Install required packages (apt-get) run: | sudo apt-get update sudo apt-get install libusb-1.0-0 libusb-1.0-0-dev - run: ./bootstrap - - run: ./configure --enable-remote-bitbang --enable-jtag_vpi --enable-ftdi-cjtag + - run: ./configure --enable-remote-bitbang --enable-jtag_vpi --enable-ftdi-cjtag --prefix /tmp/${{ env.NAME }} - run: make -j`nproc` - - run: file src/openocd | grep 64-bit - - run: src/openocd --version + - name: Check that we built something + run: | + file src/openocd | grep 64-bit + src/openocd --version + - name: Package + # Package into tgz so that github stores a compressed artifact, even + # though it zips that artifact again before it sends it back to be + # downloaded. + run: | + make install + tar zcvf ${{ env.NAME }}.tgz -C /tmp ${{ env.NAME }} + - name: Upload Artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ env.NAME }} + path: ${{ env.NAME }}.tgz diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index d4749d6d30..f5cf56459c 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -2,13 +2,13 @@ # Copyright (C) 2020 by Tarek BOUCHKATI -on: pull_request +on: push name: OpenOCD Snapshot jobs: package: - runs-on: [ubuntu-18.04] + runs-on: [ubuntu-20.04] env: DL_DIR: ../downloads BUILD_DIR: ../build @@ -22,7 +22,7 @@ jobs: - run: ./bootstrap - name: Prepare libusb1 env: - LIBUSB1_VER: 1.0.24 + LIBUSB1_VER: 1.0.26 run: | mkdir -p $DL_DIR && cd $DL_DIR wget "https://github.com/libusb/libusb/releases/download/v${LIBUSB1_VER}/libusb-${LIBUSB1_VER}.tar.bz2" @@ -30,7 +30,7 @@ jobs: echo "LIBUSB1_SRC=$PWD/libusb-${LIBUSB1_VER}" >> $GITHUB_ENV - name: Prepare hidapi env: - HIDAPI_VER: 0.10.1 + HIDAPI_VER: 0.13.1 run: | mkdir -p $DL_DIR && cd $DL_DIR wget "https://github.com/libusb/hidapi/archive/hidapi-${HIDAPI_VER}.tar.gz" @@ -38,6 +38,14 @@ jobs: cd hidapi-hidapi-${HIDAPI_VER} ./bootstrap echo "HIDAPI_SRC=$PWD" >> $GITHUB_ENV + - name: Prepare libftdi + env: + LIBFTDI_VER: 1.5 + run: | + mkdir -p $DL_DIR && cd $DL_DIR + wget "http://www.intra2net.com/en/developer/libftdi/download/libftdi1-${LIBFTDI_VER}.tar.bz2" + tar -xjf libftdi1-${LIBFTDI_VER}.tar.bz2 + echo "LIBFTDI_SRC=$PWD/libftdi1-${LIBFTDI_VER}" >> $GITHUB_ENV - name: Prepare capstone env: CAPSTONE_VER: 4.0.2 @@ -48,14 +56,25 @@ jobs: wget "https://github.com/aquynh/capstone/archive/${CAPSTONE_VER}.tar.gz" tar -xzf ${CAPSTONE_VER}.tar.gz echo "CAPSTONE_SRC=$PWD/capstone-${CAPSTONE_VER}" >> $GITHUB_ENV + - name: Prepare libjaylink + env: + LIBJAYLINK_VER: 0.3.1 + run: | + mkdir -p $DL_DIR && cd $DL_DIR + wget https://gitlab.zapb.de/libjaylink/libjaylink/-/archive/${LIBJAYLINK_VER}/libjaylink-${LIBJAYLINK_VER}.tar.gz + tar -xzf libjaylink-${LIBJAYLINK_VER}.tar.gz + cd libjaylink-${LIBJAYLINK_VER} + ./autogen.sh + echo "LIBJAYLINK_SRC=$PWD" >> $GITHUB_ENV - name: Package OpenOCD for windows env: MAKE_JOBS: 2 HOST: i686-w64-mingw32 LIBUSB1_CONFIG: --enable-shared --disable-static HIDAPI_CONFIG: --enable-shared --disable-static --disable-testgui + LIBFTDI_CONFIG: -DSTATICLIBS=OFF -DEXAMPLES=OFF -DFTDI_EEPROM=OFF CAPSTONE_CONFIG: "CAPSTONE_BUILD_CORE_ONLY=yes CAPSTONE_STATIC=yes CAPSTONE_SHARED=no" - CAPSTONE_CFLAGS: -I$(CAPSTONE_SRC)/include/capstone + LIBJAYLINK_CONFIG: --enable-shared --disable-static run: | # check if there is tag pointing at HEAD, otherwise take the HEAD SHA-1 as OPENOCD_TAG OPENOCD_TAG="`git tag --points-at HEAD`" @@ -74,6 +93,7 @@ jobs: # add missing dlls cd $HOST-root/usr cp `$HOST-gcc --print-file-name=libwinpthread-1.dll` ./bin/ + # required by libftdi1.dll. For the gcc-mingw-10.3.x or later "libgcc_s_dw2-1.dll" will need to be copied. cp `$HOST-gcc --print-file-name=libgcc_s_sjlj-1.dll` ./bin/ # prepare the artifact ARTIFACT="openocd-${OPENOCD_TAG}-${HOST}.tar.gz" @@ -81,3 +101,23 @@ jobs: echo "RELEASE_NAME=$RELEASE_NAME" >> $GITHUB_ENV echo "IS_PRE_RELEASE=$IS_PRE_RELEASE" >> $GITHUB_ENV echo "ARTIFACT_PATH=$PWD/$ARTIFACT" >> $GITHUB_ENV + - name: Publish OpenOCD packaged for windows + uses: actions/upload-artifact@v3 + with: + path: ${{ env.ARTIFACT_PATH }} + - name: Delete 'latest' Release + uses: dev-drprasad/delete-tag-and-release@v0.2.1 + with: + delete_release: true + tag_name: ${{ env.RELEASE_NAME }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Create Release + uses: ncipollo/release-action@v1 + with: + tag: ${{ env.RELEASE_NAME }} + commit: ${{ github.sha }} + draft: false + artifacts: ${{ env.ARTIFACT_PATH }} + prerelease: ${{ env.IS_PRE_RELEASE }} + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/spike-openocd-tests.yml b/.github/workflows/spike-openocd-tests.yml new file mode 100644 index 0000000000..880ca575d9 --- /dev/null +++ b/.github/workflows/spike-openocd-tests.yml @@ -0,0 +1,136 @@ +# Build Spike and run a couple of debug tests. + +name: Test OpenOCD against 2 spike configurations + +env: + SPIKE_REPO: https://github.com/riscv-software-src/riscv-isa-sim.git + SPIKE_REV: master + RISCV_TESTS_REPO: https://github.com/riscv-software-src/riscv-tests.git + RISCV_TESTS_REV: master + TOOLCHAIN_URL: https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v12.2.0-1/xpack-riscv-none-elf-gcc-12.2.0-1-linux-x64.tar.gz + +on: + # Run on merges to master to populate the cache with entities that are + # accessible by every pull request. + push: + branches: + - riscv + pull_request: + types: [synchronize, opened, reopened] + +# There is some commented out code below that would be useful in adding this +# workflow to other repos. Ideally we can come up with something that would +# leave this file almost identical between repos, so they can all easily run +# this test suite. + +jobs: + test: + name: Test debug (Ubuntu) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install packages + run: | + sudo apt-get update + sudo apt-get install -y device-tree-compiler build-essential + + - name: Get revisions of dependencies + run: | + SPIKE_COMMIT=$( git ls-remote "$SPIKE_REPO" master | awk '{ print $1; }' ) + RISC_V_TESTS_COMMIT=$( git ls-remote "$RISCV_TESTS_REPO" master | awk '{ print $1; }' ) + echo "Revison of Spike: $SPIKE_COMMIT" + echo "Revision of RISC-V tests: $RISC_V_TESTS_COMMIT" + # Save for later use + echo "SPIKE_COMMIT=$SPIKE_COMMIT" >> $GITHUB_ENV + echo "RISC_V_TESTS_COMMIT=$RISC_V_TESTS_COMMIT" >> $GITHUB_ENV + + - name: Get the toolchain from cache (if available) + id: cache-toolchain + uses: actions/cache@v3 + with: + path: /opt/riscv/toolchain + key: "toolchain-${{env.TOOLCHAIN_URL}}" + + - name: Get spike from cache (if available) + id: cache-spike + uses: actions/cache@v3 + with: + path: /opt/riscv/spike + key: "spike-${{env.SPIKE_COMMIT}}" + + - if: ${{ steps.cache-toolchain.outputs.cache-hit != 'true' }} + name: Download Toolchain (if not cached) + run: | + mkdir -p /opt/riscv/toolchain + wget --progress=dot:giga $TOOLCHAIN_URL -O /tmp/toolchain.tar.gz + + - if: ${{ steps.cache-toolchain.outputs.cache-hit != 'true' }} + name: Install Toolchain (if not cached) + run: tar zxf /tmp/toolchain.tar.gz --strip-components=1 -C /opt/riscv/toolchain + + - if: ${{ steps.cache-spike.outputs.cache-hit != 'true' }} + name: Download Spike source (if not cached) + run: | + git clone "$SPIKE_REPO" + cd riscv-isa-sim + git checkout "$SPIKE_COMMIT" + git submodule update --init --recursive + + - if: ${{ steps.cache-spike.outputs.cache-hit != 'true' }} + name: Build Spike (if not cached) + run: | + cd riscv-isa-sim + mkdir build && cd build + ../configure --prefix=/opt/riscv/spike + make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" + make install + + - name: Build OpenOCD + run: | + #cd riscv-openocd + ./bootstrap + ./configure --prefix=/opt/riscv + make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" + ls -l src/openocd + +# - name: Download OpenOCD +# run: | +# git clone --recurse-submodules https://github.com/riscv/riscv-openocd.git +# cd riscv-openocd +# git checkout 43ea20dfbb6c815004a51106a3b2009d7f6c4940 + + - name: Download Tests + run: | + git clone "$RISCV_TESTS_REPO" + cd riscv-tests + git checkout "$RISCV_TESTS_REV" + git submodule update --init --recursive + + - name: Run Spike32 Tests + id: spike32-tests + run: | + cd riscv-tests/debug + ./gdbserver.py targets/RISC-V/spike32.py --print-failures \ + --gcc /opt/riscv/toolchain/bin/riscv-none-elf-gcc \ + --gdb /opt/riscv/toolchain/bin/riscv-none-elf-gdb \ + --sim_cmd /opt/riscv/spike/bin/spike \ + --server_cmd $GITHUB_WORKSPACE/src/openocd + + - name: Run Spike64-2 Tests + if: success() || steps.spike32-tests.conclusion == 'failure' + run: | + cd riscv-tests/debug + ./gdbserver.py targets/RISC-V/spike64-2.py --print-failures \ + --gcc /opt/riscv/toolchain/bin/riscv-none-elf-gcc \ + --gdb /opt/riscv/toolchain/bin/riscv-none-elf-gdb \ + --sim_cmd /opt/riscv/spike/bin/spike \ + --server_cmd $GITHUB_WORKSPACE/src/openocd + + - name: Archive test logs + # Proceed even if there was a failed test + if: ${{ success() || failure() }} + uses: actions/upload-artifact@v3 + with: + name: test-logs + path: riscv-tests/debug/logs diff --git a/.gitignore b/.gitignore index 955ca3c2e0..103dad2c75 100644 --- a/.gitignore +++ b/.gitignore @@ -100,3 +100,14 @@ tags GPATH GRTAGS GTAGS + +# checkpatch script files +.checkpatch-camelcase.* + +# clangd (e.g. for advanced code completion and linting) generates cache files +# into .cache +.cache + +# A compile_commands.json can be generated using bear and will help tools such +# as clangd to locate header files and use correct $CFLAGS +compile_commands.json diff --git a/.travis.yml b/.travis.yml index d0bc8f261c..28d5502c5c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,76 +1,91 @@ -language: c -dist: trusty +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright Marek Vasut -matrix: - include: - - os: linux - env: - - BUILD=x86_64-linux-gnu - - EXECUTABLE=openocd - addons: - apt: - packages: - - patchutils - compiler: gcc +# OpenOCD on Travis CI - https://travis-ci.org/ + +sudo: required +dist: bionic - - os: linux - env: - - BUILD=i686-linux-gnu - - CFLAGS=-m32 - - EXECUTABLE=openocd - addons: - apt: - packages: - - gcc-multilib patchutils - compiler: gcc +arch: + - amd64 + - arm64 + - ppc64le + - s390x - - os: linux - env: - - BUILD=x86_64-linux-gnu - - EXECUTABLE=openocd - addons: - apt: - packages: - - patchutils - compiler: clang +addons: + apt: + sources: + - sourceline: 'ppa:ubuntu-toolchain-r/test' + - sourceline: 'deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main' + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' + packages: + - libftdi-dev + - libhidapi-dev + - libjaylink-dev - - os: linux - env: - - BUILD=i686-linux-gnu - - CFLAGS=-m32 - - CONFIGURE_ARGS="--disable-target64" - - EXECUTABLE=openocd - compiler: clang - addons: - apt: - packages: - - gcc-multilib patchutils +env: + - CC=gcc-9 + - CC=clang-9 + +language: c - - os: linux - env: - - BUILD=i686-w64-mingw - - CONFIGURE_ARGS="--build=i686-unknown-linux-gnu --host=i686-w64-mingw32" - - EXECUTABLE=openocd.exe - compiler: i686-w64-mingw32-gcc - addons: - apt: - packages: - - binutils-mingw-w64-i686 gcc-mingw-w64-i686 g++-mingw-w64-i686 patchutils +git: + depth: 1 + autocrlf: input script: - # This is here for the signoff check. - # Disabled because when travis does the integration build the last change - # is an automated change, which won't have the Signed-off-by line. - #- ./tools/checkpatch.sh + - $mingw64 ${CC} --version + - $mingw64 env + - $mingw64 ./bootstrap + - $mingw64 ./configure + - $mingw64 make - # Ideally we'd diff back to where we either branched off OpenOCD or master, - # or riscv. But that's tricky, and the default git clone only gets the last - # 50 changes any case. Most merges won't consist of more than 40 changes, - # so this should work fine most of the time, and be a lot better than not - # checking at all. - - git diff -U20 HEAD~40 | - filterdiff -x "a/src/jtag/drivers/libjaylink/*" -x "a/tools/git2cl/*" - -x "b/src/gnulib/*" | - ./tools/scripts/checkpatch.pl --no-signoff - - - ./bootstrap && ./configure --enable-remote-bitbang --enable-jtag_vpi $CONFIGURE_ARGS && make - - file src/$EXECUTABLE +before_install: + - |- + case $TRAVIS_OS_NAME in + linux) + sudo apt install ${CC} libusb-1.0-0-dev + ;; + osx) + brew install libtool automake libusb libusb-compat hidapi libftdi + ;; + windows) + [[ ! -f C:/tools/msys64/msys2_shell.cmd ]] && rm -rf C:/tools/msys64 + choco uninstall -y mingw + choco upgrade --no-progress -y msys2 + export msys2='cmd //C RefreshEnv.cmd ' + export msys2+='& set MSYS=winsymlinks:nativestrict ' + export msys2+='& C:\\tools\\msys64\\msys2_shell.cmd -defterm -no-start' + export mingw64="$msys2 -mingw64 -full-path -here -c \$\* --" + export msys2+=" -msys2 -c \$\* --" + $msys2 pacman --sync --noconfirm --needed mingw-w64-x86_64-toolchain autoconf autoconf-archive automake automake-wrapper binutils gcc gettext git libtool m4 make pkg-config tcl texinfo mingw-w64-x86_64-libusb mingw-w64-x86_64-libusb-compat-git mingw-w64-x86_64-libjaylink-git mingw-w64-x86_64-libftdi mingw-w64-x86_64-hidapi mingw-w64-x86_64-clang + ## FIXME: Also build for i686? + ## Install more MSYS2 packages from https://packages.msys2.org/base here + taskkill //IM gpg-agent.exe //F # https://travis-ci.community/t/4967 + export PATH=/C/tools/msys64/mingw64/bin:$PATH + export MAKE=mingw32-make # so that Autotools can find it + ;; + esac + +before_cache: +- |- + case $TRAVIS_OS_NAME in + windows) + # https://unix.stackexchange.com/a/137322/107554 + $msys2 pacman --sync --clean --noconfirm + ;; + esac + +cache: + directories: + - $HOME/AppData/Local/Temp/chocolatey + - /C/tools/msys64 + +matrix: + include: + - os: osx + env: + - CC=clang + - os: windows + env: + - CC=gcc diff --git a/HACKING b/HACKING index 1eeb1a2849..46db3b8f6f 100644 --- a/HACKING +++ b/HACKING @@ -103,6 +103,21 @@ patch: Now every time OpenOCD is run, coverage info in your build directory is updated. Running `gcov src/path/file.c` will generate a report. +- Sparse Static Analyzer + + Using this tool allows identifying some bug in C code. + In the future, OpenOCD would use the sparse attribute 'bitwise' to + detect incorrect endianness assignments. + + Example usage: + @code + mkdir build-sparse; cd build-sparse + ../configure CC=cgcc CFLAGS="-Wsparse-all -Wno-declaration-after-statement \ + -Wno-unknown-attribute -Wno-transparent-union -Wno-tautological-compare \ + -Wno-vla -Wno-flexible-array-array -D__FLT_EVAL_METHOD__=0" + make + @endcode + Please consider performing these additional checks where appropriate (especially Clang Static Analyzer for big portions of new code) and mention the results (e.g. "Valgrind-clean, no new Clang analyzer @@ -166,10 +181,6 @@ topics. It is possible because @c for/master is not a traditional Git branch. -# You will need to install this hook, we will look into a better solution: @code -scp -p -P 29418 USERNAME@review.openocd.org:hooks/commit-msg .git/hooks/ -@endcode - Or with http only: -@code wget https://review.openocd.org/tools/hooks/commit-msg mv commit-msg .git/hooks chmod +x .git/hooks/commit-msg @@ -197,18 +208,48 @@ while(!done) { @endcode \note use "git add ." before commit to add new files. - Comment template, notice the short first line w/topic. The topic field - should identify the main part or subsystem the patch touches. Check - git log for examples. -@code -topic: Short comment + \note check @ref checkpatch for hint about checkpatch script + + Commit message template, notice the short first line. + The field 'specify touched area' + should identify the main part or subsystem the patch touches. +@code{.unparsed} +specify touched area: short comment Longer comments over several lines, explaining (where applicable) the reason for the patch and the general idea the solution is based on, -any major design decisions, etc... +any major design decisions, etc. Limit each comment line's length to 75 +characters; since 75 it's too short for a URL, you can put the URL in a +separate line preceded by 'Link: '. Signed-off-by: ... @endcode + Examples: +@code{.unparsed} +flash/nor/atsame5: add SAME59 support + +Add new device ID +@endcode +@code{.unparsed} +flash/nor: flash driver for XYZ123 + +Add new flash driver for internal flash of ... +@endcode +@code{.unparsed} +target/cortex_m: fix segmentation fault in cmd 'soft_reset_halt' + +soft_reset_halt command failed reproducibly under following conditions: ... +Test for NULL pointer and return error ... + +Reported-by: John Reporter +Fixes: 123456789abc ("target: the commit where the problem started") +BugLink: https://sourceforge.net/p/openocd/tickets/999/ +@endcode +@code{.unparsed} +doc: fix typos +@endcode + See "git log" for more examples. + -# Next you need to make sure that your patches are on top of the latest stuff on the server and that there are no conflicts: @@ -227,6 +268,65 @@ git push review Further reading: http://www.coreboot.org/Git +@section checkpatch About checkpatch script + +OpenOCD source code includes the script checkpatch to let developers to +verify their patches before submitting them for review (see @ref gerrit). + +Every patch for OpenOCD project that is submitted for review on Gerrit +is tested by Jenkins. Jenkins will run the checkpatch script to analyze +each patch. +If the script highlights either errors or warnings, Gerrit will add the +score "-1" to the patch and maintainers will probably ignore the patch, +waiting for the developer to send a fixed version. + +The script checkpatch verifies the SPDX tag for new files against a very +short list of license tags. +If the license of your contribution is not listed there, but compatible +with OpenOCD license, please alert the maintainers or add the missing +license in the first patch of your patch series. + +The script checkpatch has been originally developed for the Linux kernel +source code, thus includes specific tests and checks related to Linux +coding style and to Linux code structure. While the script has been +adapted for OpenOCD specificities, it still includes some Linux related +test. It is then possible that it triggers sometimes some false +positive! + +If you think that the error identified by checkpatch is a false +positive, please report it to the openocd-devel mailing list or prepare +a patch for fixing checkpatch and send it to Gerrit for review. + +\attention The procedure below is allowed only for exceptional +cases. Do not use it to submit normal patches. + +There are exceptional cases in which you need to skip some of +the tests from checkpatch in order to pass the approval from Gerrit. + +For example, a patch that modify one line inside a big comment block +will not show the beginning or the end of the comment block. This can +prevent checkpatch to detect the comment block. Checkpatch can wrongly +consider the modified comment line as a code line, triggering a set of +false errors. + +Only for exceptional cases, it is allowed to submit patches +to Gerrit with the special field 'Checkpatch-ignore:' in the commit +message. This field will cause checkpatch to ignore the error types +listed in the field, only for the patch itself. +The error type is printed by checkpatch on failure. +For example the names of Windows APIs mix lower and upper case chars, +in violation of OpenOCD coding style, triggering a 'CAMELCASE' error: +@code +CHECK:CAMELCASE: Avoid CamelCase: +#96105: FILE: src/helper/log.c:505: ++ error_code = WSAGetLastError(); +@endcode +Adding in the commit message of the patch the line: +@code +Checkpatch-ignore: CAMELCASE +@endcode +will force checkpatch to ignore the CAMELCASE error. + @section timeline When can I expect my contribution to be committed? The code review is intended to take as long as a week or two to allow diff --git a/LICENSES/exceptions/eCos-exception-2.0 b/LICENSES/exceptions/eCos-exception-2.0 new file mode 100644 index 0000000000..d21109f500 --- /dev/null +++ b/LICENSES/exceptions/eCos-exception-2.0 @@ -0,0 +1,20 @@ +SPDX-Exception-Identifier: eCos-exception-2.0 +SPDX-URL: https://spdx.org/licenses/eCos-exception-2.0.html +SPDX-Licenses: GPL-2.0-only, GPL-2.0-or-later +Usage-Guide: + This exception is used together with one of the above SPDX-Licenses. + To use this exception add it with the keyword WITH to one of the + identifiers in the SPDX-Licenses tag: + SPDX-License-Identifier: WITH eCos-exception-2.0 +License-Text: + +As a special exception, if other files instantiate templates or use +macros or inline functions from this file, or you compile this +file and link it with other works to produce a work based on this +file, this file does not by itself cause the resulting work to be +covered by the GNU General Public License. However the source code for +this file must still be made available in accordance with section (3) +of the GNU General Public License. + +This exception does not invalidate any other reasons why a work based on +this file might be covered by the GNU General Public License. diff --git a/LICENSES/license-rules.txt b/LICENSES/license-rules.txt index 8d0c0a0ee9..ecc8e4db16 100644 --- a/LICENSES/license-rules.txt +++ b/LICENSES/license-rules.txt @@ -173,7 +173,6 @@ OpenOCD, can be broken down into: File format examples:: - Valid-License-Identifier: GPL-2.0 Valid-License-Identifier: GPL-2.0-only Valid-License-Identifier: GPL-2.0-or-later SPDX-URL: https://spdx.org/licenses/GPL-2.0.html @@ -182,15 +181,70 @@ OpenOCD, can be broken down into: tag/value pairs into a comment according to the placement guidelines in the licensing rules documentation. For 'GNU General Public License (GPL) version 2 only' use: - SPDX-License-Identifier: GPL-2.0 - or SPDX-License-Identifier: GPL-2.0-only For 'GNU General Public License (GPL) version 2 or any later version' use: SPDX-License-Identifier: GPL-2.0-or-later License-Text: Full license text -2. Stand-alone licenses: +2. Exceptions: + + Some licenses can be amended with exceptions which grant certain rights + which the original license does not. These exceptions are available + from the directory:: + + LICENSES/exceptions/ + + in the OpenOCD source tree. The files in this directory contain the full + exception text and the required `Exception Metatags`_. + + Examples:: + + LICENSES/exceptions/eCos-exception-2.0 + + Exception Metatags: + + The following meta tags must be available in an exception file: + + - SPDX-Exception-Identifier: + + One exception identifier which can be used with SPDX license + identifiers. + + - SPDX-URL: + + The URL of the SPDX page which contains additional information related + to the exception. + + - SPDX-Licenses: + + A comma separated list of SPDX license identifiers for which the + exception can be used. + + - Usage-Guidance: + + Freeform text for usage advice. The text must be followed by correct + examples for the SPDX license identifiers as they should be put into + source files according to the `License identifier syntax`_ guidelines. + + - Exception-Text: + + All text after this tag is treated as the original exception text + + File format examples:: + + SPDX-Exception-Identifier: eCos-exception-2.0 + SPDX-URL: https://spdx.org/licenses/eCos-exception-2.0.html + SPDX-Licenses: GPL-2.0-only, GPL-2.0-or-later + Usage-Guide: + This exception is used together with one of the above SPDX-Licenses. + To use this exception add it with the keyword WITH to one of the + identifiers in the SPDX-Licenses tag: + SPDX-License-Identifier: WITH eCos-exception-2.0 + License-Text: + Full license text + +3. Stand-alone licenses: These licenses should only be used for stand-alone applications that are distributed with OpenOCD but are not included in the OpenOCD binary. diff --git a/LICENSES/preferred/BSD-2-Clause-Views b/LICENSES/preferred/BSD-2-Clause-Views new file mode 100644 index 0000000000..abfb0ffbba --- /dev/null +++ b/LICENSES/preferred/BSD-2-Clause-Views @@ -0,0 +1,37 @@ +Valid-License-Identifier: BSD-2-Clause-Views +SPDX-URL: https://spdx.org/licenses/BSD-2-Clause-Views.html +Usage-Guide: + To use the BSD 2-clause with views sentence License put the following SPDX + tag/value pair into a comment according to the placement guidelines in + the licensing rules documentation: + SPDX-License-Identifier: BSD-2-Clause-Views +License-Text: + +Copyright (c) . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation +are those of the authors and should not be interpreted as representing +official policies, either expressed or implied, of the copyright holders +or contributors. diff --git a/LICENSES/preferred/BSD-Source-Code b/LICENSES/preferred/BSD-Source-Code new file mode 100644 index 0000000000..622cd3a940 --- /dev/null +++ b/LICENSES/preferred/BSD-Source-Code @@ -0,0 +1,32 @@ +Valid-License-Identifier: BSD-Source-Code +SPDX-URL: https://spdx.org/licenses/BSD-Source-Code.html +Usage-Guide: + To use the BSD Source Code Attribution License put the following SPDX + tag/value pair into a comment according to the placement guidelines in + the licensing rules documentation: + SPDX-License-Identifier: BSD-Source-Code +License-Text: + +Copyright (c) . All rights reserved. + +Redistribution and use of this software in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSES/preferred/CC0-1.0 b/LICENSES/preferred/CC0-1.0 new file mode 100644 index 0000000000..ba3c8c7955 --- /dev/null +++ b/LICENSES/preferred/CC0-1.0 @@ -0,0 +1,130 @@ +Valid-License-Identifier: CC0-1.0 +SPDX-URL: https://spdx.org/licenses/CC0-1.0.html +Usage-Guide: + To use the Creative Commons Zero v1.0 Universal License put the following + SPDX tag/value pair into a comment according to the placement guidelines in + the licensing rules documentation: + SPDX-License-Identifier: CC0-1.0 +License-Text: + +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/LICENSES/preferred/GPL-2.0 b/LICENSES/preferred/GPL-2.0 index 2ca4651c35..687bdddb11 100644 --- a/LICENSES/preferred/GPL-2.0 +++ b/LICENSES/preferred/GPL-2.0 @@ -1,4 +1,3 @@ -Valid-License-Identifier: GPL-2.0 Valid-License-Identifier: GPL-2.0-only Valid-License-Identifier: GPL-2.0-or-later SPDX-URL: https://spdx.org/licenses/GPL-2.0.html @@ -7,8 +6,6 @@ Usage-Guide: tag/value pairs into a comment according to the placement guidelines in the licensing rules documentation. For 'GNU General Public License (GPL) version 2 only' use: - SPDX-License-Identifier: GPL-2.0 - or SPDX-License-Identifier: GPL-2.0-only For 'GNU General Public License (GPL) version 2 or any later version' use: SPDX-License-Identifier: GPL-2.0-or-later diff --git a/LICENSES/preferred/LGPL-2.1 b/LICENSES/preferred/LGPL-2.1 new file mode 100644 index 0000000000..8738a8d578 --- /dev/null +++ b/LICENSES/preferred/LGPL-2.1 @@ -0,0 +1,503 @@ +Valid-License-Identifier: LGPL-2.1-only +Valid-License-Identifier: LGPL-2.1-or-later +SPDX-URL: https://spdx.org/licenses/LGPL-2.1.html +Usage-Guide: + To use this license in source code, put one of the following SPDX + tag/value pairs into a comment according to the placement + guidelines in the licensing rules documentation. + For 'GNU Lesser General Public License (LGPL) version 2.1 only' use: + SPDX-License-Identifier: LGPL-2.1-only + For 'GNU Lesser General Public License (LGPL) version 2.1 or any later + version' use: + SPDX-License-Identifier: LGPL-2.1-or-later +License-Text: + +GNU LESSER GENERAL PUBLIC LICENSE +Version 2.1, February 1999 + +Copyright (C) 1991, 1999 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts as +the successor of the GNU Library Public License, version 2, hence the +version number 2.1.] + +Preamble + +The licenses for most software are designed to take away your freedom to +share and change it. By contrast, the GNU General Public Licenses are +intended to guarantee your freedom to share and change free software--to +make sure the software is free for all its users. + +This license, the Lesser General Public License, applies to some specially +designated software packages--typically libraries--of the Free Software +Foundation and other authors who decide to use it. You can use it too, but +we suggest you first think carefully about whether this license or the +ordinary General Public License is the better strategy to use in any +particular case, based on the explanations below. + +When we speak of free software, we are referring to freedom of use, not +price. Our General Public Licenses are designed to make sure that you have +the freedom to distribute copies of free software (and charge for this +service if you wish); that you receive source code or can get it if you +want it; that you can change the software and use pieces of it in new free +programs; and that you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for you if +you distribute copies of the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for +a fee, you must give the recipients all the rights that we gave you. You +must make sure that they, too, receive or can get the source code. If you +link other code with the library, you must provide complete object files to +the recipients, so that they can relink them with the library after making +changes to the library and recompiling it. And you must show them these +terms so they know their rights. + +We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no +warranty for the free library. Also, if the library is modified by someone +else and passed on, the recipients should know that what they have is not +the original version, so that the original author's reputation will not be +affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any +free program. We wish to make sure that a company cannot effectively +restrict the users of a free program by obtaining a restrictive license +from a patent holder. Therefore, we insist that any patent license obtained +for a version of the library must be consistent with the full freedom of +use specified in this license. + +Most GNU software, including some libraries, is covered by the ordinary GNU +General Public License. This license, the GNU Lesser General Public +License, applies to certain designated libraries, and is quite different +from the ordinary General Public License. We use this license for certain +libraries in order to permit linking those libraries into non-free +programs. + +When a program is linked with a library, whether statically or using a +shared library, the combination of the two is legally speaking a combined +work, a derivative of the original library. The ordinary General Public +License therefore permits such linking only if the entire combination fits +its criteria of freedom. The Lesser General Public License permits more lax +criteria for linking other code with the library. + +We call this license the "Lesser" General Public License because it does +Less to protect the user's freedom than the ordinary General Public +License. It also provides other free software developers Less of an +advantage over competing non-free programs. These disadvantages are the +reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + +For example, on rare occasions, there may be a special need to encourage +the widest possible use of a certain library, so that it becomes a de-facto +standard. To achieve this, non-free programs must be allowed to use the +library. A more frequent case is that a free library does the same job as +widely used non-free libraries. In this case, there is little to gain by +limiting the free library to free software only, so we use the Lesser +General Public License. + +In other cases, permission to use a particular library in non-free programs +enables a greater number of people to use a large body of free +software. For example, permission to use the GNU C Library in non-free +programs enables many more people to use the whole GNU operating system, as +well as its variant, the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' +freedom, it does ensure that the user of a program that is linked with the +Library has the freedom and the wherewithal to run that program using a +modified version of the Library. + +The precise terms and conditions for copying, distribution and modification +follow. Pay close attention to the difference between a "work based on the +library" and a "work that uses the library". The former contains code +derived from the library, whereas the latter must be combined with the +library in order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other program + which contains a notice placed by the copyright holder or other + authorized party saying it may be distributed under the terms of this + Lesser General Public License (also called "this License"). Each + licensee is addressed as "you". + + A "library" means a collection of software functions and/or data + prepared so as to be conveniently linked with application programs + (which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work which + has been distributed under these terms. A "work based on the Library" + means either the Library or any derivative work under copyright law: + that is to say, a work containing the Library or a portion of it, either + verbatim or with modifications and/or translated straightforwardly into + another language. (Hereinafter, translation is included without + limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for making + modifications to it. For a library, complete source code means all the + source code for all modules it contains, plus any associated interface + definition files, plus the scripts used to control compilation and + installation of the library. + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of running + a program using the Library is not restricted, and output from such a + program is covered only if its contents constitute a work based on the + Library (independent of the use of the Library in a tool for writing + it). Whether that is true depends on what the Library does and what the + program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the notices + that refer to this License and to the absence of any warranty; and + distribute a copy of this License along with the Library. + + You may charge a fee for the physical act of transferring a copy, and + you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, + thus forming a work based on the Library, and copy and distribute such + modifications or work under the terms of Section 1 above, provided that + you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices stating + that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no charge to + all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a table + of data to be supplied by an application program that uses the + facility, other than as an argument passed when the facility is + invoked, then you must make a good faith effort to ensure that, in + the event an application does not supply such function or table, the + facility still operates, and performs whatever part of its purpose + remains meaningful. + + (For example, a function in a library to compute square roots has a + purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must be + optional: if the application does not supply it, the square root + function must still compute square roots.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Library, and + can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based on + the Library, the distribution of the whole must be on the terms of this + License, whose permissions for other licensees extend to the entire + whole, and thus to each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Library. + + In addition, mere aggregation of another work not based on the Library + with the Library (or with a work based on the Library) on a volume of a + storage or distribution medium does not bring the other work under the + scope of this License. + +3. You may opt to apply the terms of the ordinary GNU General Public + License instead of this License to a given copy of the Library. To do + this, you must alter all the notices that refer to this License, so that + they refer to the ordinary GNU General Public License, version 2, + instead of to this License. (If a newer version than version 2 of the + ordinary GNU General Public License has appeared, then you can specify + that version instead if you wish.) Do not make any other change in these + notices. + + Once this change is made in a given copy, it is irreversible for that + copy, so the ordinary GNU General Public License applies to all + subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of the + Library into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of + it, under Section 2) in object code or executable form under the terms + of Sections 1 and 2 above provided that you accompany it with the + complete corresponding machine-readable source code, which must be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange. + + If distribution of object code is made by offering access to copy from a + designated place, then offering equivalent access to copy the source + code from the same place satisfies the requirement to distribute the + source code, even though third parties are not compelled to copy the + source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but + is designed to work with the Library by being compiled or linked with + it, is called a "work that uses the Library". Such a work, in isolation, + is not a derivative work of the Library, and therefore falls outside the + scope of this License. + + However, linking a "work that uses the Library" with the Library creates + an executable that is a derivative of the Library (because it contains + portions of the Library), rather than a "work that uses the + library". The executable is therefore covered by this License. Section 6 + states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file + that is part of the Library, the object code for the work may be a + derivative work of the Library even though the source code is + not. Whether this is true is especially significant if the work can be + linked without the Library, or if the work is itself a library. The + threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data structure + layouts and accessors, and small macros and small inline functions (ten + lines or less in length), then the use of the object file is + unrestricted, regardless of whether it is legally a derivative + work. (Executables containing this object code plus portions of the + Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may + distribute the object code for the work under the terms of Section + 6. Any executables containing that work also fall under Section 6, + whether or not they are linked directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a + "work that uses the Library" with the Library to produce a work + containing portions of the Library, and distribute that work under terms + of your choice, provided that the terms permit modification of the work + for the customer's own use and reverse engineering for debugging such + modifications. + + You must give prominent notice with each copy of the work that the + Library is used in it and that the Library and its use are covered by + this License. You must supply a copy of this License. If the work during + execution displays copyright notices, you must include the copyright + notice for the Library among them, as well as a reference directing the + user to the copy of this License. Also, you must do one of these things: + + a) Accompany the work with the complete corresponding machine-readable + source code for the Library including whatever changes were used in + the work (which must be distributed under Sections 1 and 2 above); + and, if the work is an executable linked with the Library, with the + complete machine-readable "work that uses the Library", as object + code and/or source code, so that the user can modify the Library and + then relink to produce a modified executable containing the modified + Library. (It is understood that the user who changes the contents of + definitions files in the Library will not necessarily be able to + recompile the application to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a copy + of the library already present on the user's computer system, rather + than copying library functions into the executable, and (2) will + operate properly with a modified version of the library, if the user + installs one, as long as the modified version is interface-compatible + with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least three + years, to give the same user the materials specified in Subsection + 6a, above, for a charge no more than the cost of performing this + distribution. + + d) If distribution of the work is made by offering access to copy from a + designated place, offer equivalent access to copy the above specified + materials from the same place. + + e) Verify that the user has already received a copy of these materials + or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the Library" + must include any data and utility programs needed for reproducing the + executable from it. However, as a special exception, the materials to be + distributed need not include anything that is normally distributed (in + either source or binary form) with the major components (compiler, + kernel, and so on) of the operating system on which the executable runs, + unless that component itself accompanies the executable. + + It may happen that this requirement contradicts the license restrictions + of other proprietary libraries that do not normally accompany the + operating system. Such a contradiction means you cannot use both them + and the Library together in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library + side-by-side in a single library together with other library facilities + not covered by this License, and distribute such a combined library, + provided that the separate distribution of the work based on the Library + and of the other library facilities is otherwise permitted, and provided + that you do these two things: + + a) Accompany the combined library with a copy of the same work based on + the Library, uncombined with any other library facilities. This must + be distributed under the terms of the Sections above. + + b) Give prominent notice with the combined library of the fact that part + of it is a work based on the Library, and explaining where to find + the accompanying uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the + Library except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense, link with, or distribute the + Library is void, and will automatically terminate your rights under this + License. However, parties who have received copies, or rights, from you + under this License will not have their licenses terminated so long as + such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed + it. However, nothing else grants you permission to modify or distribute + the Library or its derivative works. These actions are prohibited by law + if you do not accept this License. Therefore, by modifying or + distributing the Library (or any work based on the Library), you + indicate your acceptance of this License to do so, and all its terms and + conditions for copying, distributing or modifying the Library or works + based on it. + +10. Each time you redistribute the Library (or any work based on the + Library), the recipient automatically receives a license from the + original licensor to copy, distribute, link with or modify the Library + subject to these terms and conditions. You may not impose any further + restrictions on the recipients' exercise of the rights granted + herein. You are not responsible for enforcing compliance by third + parties with this License. + +11. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you + may not distribute the Library at all. For example, if a patent license + would not permit royalty-free redistribution of the Library by all + those who receive copies directly or indirectly through you, then the + only way you could satisfy both it and this License would be to refrain + entirely from distribution of the Library. + + If any portion of this section is held invalid or unenforceable under + any particular circumstance, the balance of the section is intended to + apply, and the section as a whole is intended to apply in other + circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system which is implemented + by public license practices. Many people have made generous + contributions to the wide range of software distributed through that + system in reliance on consistent application of that system; it is up + to the author/donor to decide if he or she is willing to distribute + software through any other system and a licensee cannot impose that + choice. + + This section is intended to make thoroughly clear what is believed to + be a consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain + countries either by patents or by copyrighted interfaces, the original + copyright holder who places the Library under this License may add an + explicit geographical distribution limitation excluding those + countries, so that distribution is permitted only in or among countries + not thus excluded. In such case, this License incorporates the + limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of + the Lesser General Public License from time to time. Such new versions + will be similar in spirit to the present version, but may differ in + detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the Library + specifies a version number of this License which applies to it and "any + later version", you have the option of following the terms and + conditions either of that version or of any later version published by + the Free Software Foundation. If the Library does not specify a license + version number, you may choose any version ever published by the Free + Software Foundation. + +14. If you wish to incorporate parts of the Library into other free + programs whose distribution conditions are incompatible with these, + write to the author to ask for permission. For software which is + copyrighted by the Free Software Foundation, write to the Free Software + Foundation; we sometimes make exceptions for this. Our decision will be + guided by the two goals of preserving the free status of all + derivatives of our free software and of promoting the sharing and reuse + of software generally. + +NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER + EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH + YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL + NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR + REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR + DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL + DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY + (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED + INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF + THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR + OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Libraries + +If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + +To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + +one line to give the library's name and an idea of what it does. +Copyright (C) year name of author + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at +your option) any later version. + +This library 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 Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add +information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in +the library `Frob' (a library for tweaking knobs) written +by James Random Hacker. + +signature of Ty Coon, 1 April 1990 +Ty Coon, President of Vice +That's all there is to it! diff --git a/LICENSES/stand-alone/Apache-2.0 b/LICENSES/stand-alone/Apache-2.0 new file mode 100644 index 0000000000..ae8128b7e6 --- /dev/null +++ b/LICENSES/stand-alone/Apache-2.0 @@ -0,0 +1,189 @@ +Valid-License-Identifier: Apache-2.0 +SPDX-URL: https://spdx.org/licenses/Apache-2.0.html +Usage-Guide: + Do NOT use on OpenOCD code. The Apache-2.0 is not GPL2 compatible. It may only + be used for dual-licensed files where the other license is GPL2 compatible. + If you end up using this it MUST be used together with a GPL2 compatible + license using "OR". + It may also be used for stand-alone code NOT linked within the OpenOCD binary + but distributed with OpenOCD. + To use the Apache License version 2.0 put the following SPDX tag/value + pair into a comment according to the placement guidelines in the + licensing rules documentation: + SPDX-License-Identifier: Apache-2.0 +License-Text: + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the +copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other +entities that control, are controlled by, or are under common control with +that entity. For the purposes of this definition, "control" means (i) the +power, direct or indirect, to cause the direction or management of such +entity, whether by contract or otherwise, or (ii) ownership of fifty +percent (50%) or more of the outstanding shares, or (iii) beneficial +ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation source, +and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation +or translation of a Source form, including but not limited to compiled +object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice that +is included in or attached to the work (an example is provided in the +Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, +that is based on (or derived from) the Work and for which the editorial +revisions, annotations, elaborations, or other modifications represent, as +a whole, an original work of authorship. For the purposes of this License, +Derivative Works shall not include works that remain separable from, or +merely link (or bind by name) to the interfaces of, the Work and Derivative +Works thereof. + +"Contribution" shall mean any work of authorship, including the original +version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor for +inclusion in the Work by the copyright owner or by an individual or Legal +Entity authorized to submit on behalf of the copyright owner. For the +purposes of this definition, "submitted" means any form of electronic, +verbal, or written communication sent to the Licensor or its +representatives, including but not limited to communication on electronic +mailing lists, source code control systems, and issue tracking systems that +are managed by, or on behalf of, the Licensor for the purpose of discussing +and improving the Work, but excluding communication that is conspicuously +marked or otherwise designated in writing by the copyright owner as "Not a +Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on +behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this + License, each Contributor hereby grants to You a perpetual, worldwide, + non-exclusive, no-charge, royalty-free, irrevocable copyright license to + reproduce, prepare Derivative Works of, publicly display, publicly + perform, sublicense, and distribute the Work and such Derivative Works + in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this + License, each Contributor hereby grants to You a perpetual, worldwide, + non-exclusive, no-charge, royalty-free, irrevocable (except as stated in + this section) patent license to make, have made, use, offer to sell, + sell, import, and otherwise transfer the Work, where such license + applies only to those patent claims licensable by such Contributor that + are necessarily infringed by their Contribution(s) alone or by + combination of their Contribution(s) with the Work to which such + Contribution(s) was submitted. If You institute patent litigation + against any entity (including a cross-claim or counterclaim in a + lawsuit) alleging that the Work or a Contribution incorporated within + the Work constitutes direct or contributory patent infringement, then + any patent licenses granted to You under this License for that Work + shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or + Derivative Works thereof in any medium, with or without modifications, + and in Source or Object form, provided that You meet the following + conditions: + + a. You must give any other recipients of the Work or Derivative Works a + copy of this License; and + + b. You must cause any modified files to carry prominent notices stating + that You changed the files; and + + c. You must retain, in the Source form of any Derivative Works that You + distribute, all copyright, patent, trademark, and attribution notices + from the Source form of the Work, excluding those notices that do not + pertain to any part of the Derivative Works; and + + d. If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained within + such NOTICE file, excluding those notices that do not pertain to any + part of the Derivative Works, in at least one of the following + places: within a NOTICE text file distributed as part of the + Derivative Works; within the Source form or documentation, if + provided along with the Derivative Works; or, within a display + generated by the Derivative Works, if and wherever such third-party + notices normally appear. The contents of the NOTICE file are for + informational purposes only and do not modify the License. You may + add Your own attribution notices within Derivative Works that You + distribute, alongside or as an addendum to the NOTICE text from the + Work, provided that such additional attribution notices cannot be + construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may + provide additional or different license terms and conditions for use, + reproduction, or distribution of Your modifications, or for any such + Derivative Works as a whole, provided Your use, reproduction, and + distribution of the Work otherwise complies with the conditions stated + in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any + Contribution intentionally submitted for inclusion in the Work by You to + the Licensor shall be under the terms and conditions of this License, + without any additional terms or conditions. Notwithstanding the above, + nothing herein shall supersede or modify the terms of any separate + license agreement you may have executed with Licensor regarding such + Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to + in writing, Licensor provides the Work (and each Contributor provides + its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + OF ANY KIND, either express or implied, including, without limitation, + any warranties or conditions of TITLE, NON-INFRINGEMENT, + MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely + responsible for determining the appropriateness of using or + redistributing the Work and assume any risks associated with Your + exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether + in tort (including negligence), contract, or otherwise, unless required + by applicable law (such as deliberate and grossly negligent acts) or + agreed to in writing, shall any Contributor be liable to You for + damages, including any direct, indirect, special, incidental, or + consequential damages of any character arising as a result of this + License or out of the use or inability to use the Work (including but + not limited to damages for loss of goodwill, work stoppage, computer + failure or malfunction, or any and all other commercial damages or + losses), even if such Contributor has been advised of the possibility of + such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the + Work or Derivative Works thereof, You may choose to offer, and charge a + fee for, acceptance of support, warranty, indemnity, or other liability + obligations and/or rights consistent with this License. However, in + accepting such obligations, You may act only on Your own behalf and on + Your sole responsibility, not on behalf of any other Contributor, and + only if You agree to indemnify, defend, and hold each Contributor + harmless for any liability incurred by, or claims asserted against, such + Contributor by reason of your accepting any such warranty or additional + liability. + +END OF TERMS AND CONDITIONS diff --git a/Makefile.am b/Makefile.am index 55d79e6e4e..1e3e0976a0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # not a GNU package. You can remove this line, if # have all needed files, that a GNU package needs AUTOMAKE_OPTIONS = gnu 1.6 @@ -24,10 +26,14 @@ noinst_LTLIBRARIES = info_TEXINFOS = dist_man_MANS = EXTRA_DIST = +DISTCLEANFILES = if INTERNAL_JIMTCL SUBDIRS += jimtcl DIST_SUBDIRS += jimtcl +EXTRA_DIST += jimtcl/configure.gnu +# jimtcl from 0.79 to 0.82 miss cleaning jsmn.o +DISTCLEANFILES += jimtcl/jsmn/jsmn.o endif # common flags used in openocd build @@ -54,13 +60,19 @@ EXTRA_DIST += \ $(EXTRA_DIST_NEWS) \ Doxyfile.in \ LICENSES/license-rules.txt \ + LICENSES/exceptions/eCos-exception-2.0 \ LICENSES/preferred/BSD-1-Clause \ LICENSES/preferred/BSD-2-Clause \ + LICENSES/preferred/BSD-2-Clause-Views \ LICENSES/preferred/BSD-3-Clause \ + LICENSES/preferred/BSD-Source-Code \ + LICENSES/preferred/CC0-1.0 \ LICENSES/preferred/GFDL-1.2 \ LICENSES/preferred/gfdl-1.2.texi.readme \ LICENSES/preferred/GPL-2.0 \ + LICENSES/preferred/LGPL-2.1 \ LICENSES/preferred/MIT \ + LICENSES/stand-alone/Apache-2.0 \ LICENSES/stand-alone/GPL-3.0 \ tools/logger.pl \ tools/rlink_make_speed_table \ @@ -126,18 +138,9 @@ uninstall-hook: distclean-local: rm -rf Doxyfile doxygen - rm -f $(srcdir)/jimtcl/configure.gnu - -# We want every change to have Signed-off-by. This is tricky to enforce in -# Travis, because it automatically makes temporary commits when merging. So -# instead we have a hook that enforces this in each workspace. To make sure -# that users actually use those hooks, we point git at them here. -# If git fails for some reason, that's OK. It's probably because somebody is -# building the source completely outside a git repo. -all-local: - cd $(srcdir) && git config core.hooksPath ./git-hooks || true - -DISTCLEANFILES = doxygen.log + -rm -f $(srcdir)/jimtcl/configure.gnu + +DISTCLEANFILES += doxygen.log METASOURCES = AUTO diff --git a/NEWS-0.12.0 b/NEWS-0.12.0 new file mode 100644 index 0000000000..208146a460 --- /dev/null +++ b/NEWS-0.12.0 @@ -0,0 +1,132 @@ +This file includes highlights of the changes made in the OpenOCD +source archive release. + +JTAG Layer: + * add default to adapter speed when unspecified (100 kHz) + * AM335X gpio (BeagleBones) adapter driver + * BCM2835 support for SWD + * Cadence Virtual Debug (vdebug) adapter driver + * CMSIS-DAP support for SWO and SWD multidrop + * Espressif USB JTAG Programmer adapter driver + * Remote bitbang support for Windows host + * ST-LINK add TCP server support to adapter driver + * SWD multidrop support + +Boundary Scan: + +Target Layer: + * aarch64: support watchpoints + * arm: support independent TPIU and SWO for trace + * arm adi v5: support Large Physical Address Extension + * arm adi v6: support added, for jtag and swd transport + * cortex_a: support watchpoints + * elf 64bit load support + * Espressif: support ESP32, ESP32-S2 and ESP32-S3 cores + * semihosting: support user defined operations + * Xtensa: support Xtensa LX architecture via JTAG and ADIv5 DAP + +Flash Layer: + * Atmel/Microchip SAM E51G18A, E51G19A, R35J18B, LAN9255 support + * GigaDevice GD32E23x, GD32F1x0/3x0, GD32VF103 support + * Nuvoton NPCX series support + * onsemi RSL10 support + * Raspberry Pi Pico RP2040 support + * ST BlueNRG-LPS support + * ST STM32 G05x, G06x, G0Bx, G0Cx, U57x, U58x, WB1x, WL5x support + * ST STM32 G0, G4, L4, L4+, L5, WB, WL OTP support + +Board, Target, and Interface Configuration Scripts: + * Ampere Computing eMAG8180, Altra ("Quicksilver") and Altra Max ("Mystique") board config + * Cadence KC705 FPGA (Xtensa Development Platform) via JTAG and ADIv5 DAP board config + * Digilent Nexys Video board config + * Espressif ESP32 ETHERNET-KIT and WROVER-KIT board config + * Espressif ESP32 via ESP USB Bridge generic board config + * Espressif ESP32-S2 Kaluga 1 board config + * Espressif ESP32-S2 with ESP USB Bridge board config + * Espressif ESP32-S3 example board config + * Kontron SMARC-sAL28 board config + * LambdaConcept ECPIX-5 board config + * Microchip ATSAMA5D27-SOM1-EK1 board config + * Microchip EVB-LAN9255 board config + * Microchip SAME51 Curiosity Nano board config + * NXP FRDM-K64F, LS1046ARDB and LS1088ARDB board config + * NXP RT6XX board config + * Olimex H405 board config + * Radiona ULX3S board config + * Raspberry Pi 3 and Raspberry Pi 4 model B board config + * Raspberry Pi Pico-Debug board config + * Renesas R-Car V3U Falcon board config + * ST BlueNRG-LPS steval-idb012v1 board config + * ST NUCLEO-8S208RB board config + * ST NUCLEO-G031K8, NUCLEO-G070RB, NUCLEO-G071RB board config + * ST NUCLEO-G431KB, NUCLEO-G431RB, NUCLEO-G474RE board config + * ST STM32MP13x-DK board config + * TI AM625 EVM, AM642 EVM and AM654 EVM board config + * TI J721E EVM, J721S2 EVM and J7200 EVM board config + * Ampere Computing eMAG, Altra ("Quicksilver") and Altra Max ("Mystique") target config + * Cadence Xtensa generic and Xtensa VDebug target config + * Broadcom BCM2711, BCM2835, BCM2836 and BCM2837 target config + * Espressif ESP32, ESP32-S2 and ESP32-S3 target config + * Microchip ATSAMA5D2 series target config + * NanoXplore NG-Ultra SoC target config + * NXP IMX8QM target config + * NXP LS1028A, LS1046A and LS1088A target config + * NXP RT600 (Xtensa HiFi DSP) target config + * onsemi RSL10 target config + * Raspberry Pi Pico RP2040 target config + * Renesas R8A779A0 V3U target config + * Renesas RZ/Five target config + * Renesas RZ/G2 MPU family target config + * Rockchip RK3399 target config + * ST BlueNRG-LPS target config + * ST STM32MP13x target config + * TI AM625, AM654, J721E and J721S2 target config + * Ashling Opella-LD interface config + * Aspeed AST2600 linuxgpiod based interface config + * Blinkinlabs JTAG_Hat interface config + * Cadence Virtual Debug (vdebug) interface config + * Espressif ESP32-S2 Kaluga 1 board's interface config + * Espressif USB Bridge jtag interface config + * Infineon DAP miniWiggler V3 interface config + * PLS SPC5 interface config + * Tigard interface config + * Lattice MachXO3 family FPGA config + +Server Layer: + * GDB: add per-target remote protocol extensions + * GDB: more 'Z' packets support + * IPDBG JtagHost server functionality + * semihosting: I/O redirection to TCP server + * telnet: support for command's autocomplete + +RTOS: + * 'none' rtos support + * Zephyr rtos support + +Documentation: + +Build and Release: + * Add json extension to jimtcl build + * Drop dependency from libusb0 + * Drop repository repo.or.cz for submodules + * Move gerrit to https://review.openocd.org/ + * Require autoconf 2.69 or newer + * Update jep106 to revision JEP106BF.01 + * Update jimtcl to version 0.81 + * Update libjaylink to version 0.3.1 + * New configure flag '--enable-jimtcl-maintainer' for jimtcl build + + +This release also contains a number of other important functional and +cosmetic bugfixes. For more details about what has changed since the +last release, see the git repository history: + +http://sourceforge.net/p/openocd/code/ci/v0.12.0/log/?path= + + +For older NEWS, see the NEWS files associated with each release +(i.e. NEWS-). + +For more information about contributing test reports, bug fixes, or new +features and device support, please read the new Developer Manual (or +the BUGS and PATCHES.txt files in the source archive). diff --git a/README b/README index 258dbe5350..52d6c3be86 100644 --- a/README +++ b/README @@ -144,17 +144,18 @@ Supported hardware JTAG adapters ------------- -AICE, ARM-JTAG-EW, ARM-USB-OCD, ARM-USB-TINY, AT91RM9200, axm0432, BCM2835, -Bus Blaster, Buspirate, Cadence DPI, Chameleon, CMSIS-DAP, Cortino, -Cypress KitProg, DENX, Digilent JTAG-SMT2, DLC 5, DLP-USB1232H, -embedded projects, eStick, FlashLINK, FlossJTAG, Flyswatter, Flyswatter2, +AM335x, ARM-JTAG-EW, ARM-USB-OCD, ARM-USB-TINY, AT91RM9200, axm0432, BCM2835, +Bus Blaster, Buspirate, Cadence DPI, Cadence vdebug, Chameleon, CMSIS-DAP, +Cortino, Cypress KitProg, DENX, Digilent JTAG-SMT2, DLC 5, DLP-USB1232H, +embedded projects, Espressif USB JTAG Programmer, +eStick, FlashLINK, FlossJTAG, Flyswatter, Flyswatter2, FTDI FT232R, Gateworks, Hoegl, ICDI, ICEBear, J-Link, JTAG VPI, JTAGkey, JTAGkey2, JTAG-lock-pick, KT-Link, Linux GPIOD, Lisa/L, LPC1768-Stick, Mellanox rshim, MiniModule, NGX, Nuvoton Nu-Link, Nu-Link2, NXHX, NXP IMX GPIO, OOCDLink, Opendous, OpenJTAG, Openmoko, OpenRD, OSBDM, Presto, Redbee, Remote Bitbang, RLink, SheevaPlug devkit, Stellaris evkits, ST-LINK (SWO tracing supported), STM32-PerformanceStick, STR9-comStick, -sysfsgpio, TI XDS110, TUMPA, Turtelizer, ULINK, USB-A9260, USB-Blaster, +sysfsgpio, Tigard, TI XDS110, TUMPA, Turtelizer, ULINK, USB-A9260, USB-Blaster, USB-JTAG, USBprog, VPACLink, VSLLink, Wiggler, XDS100v2, Xilinx XVC/PCIe, Xverve. @@ -164,16 +165,18 @@ Debug targets ARM: AArch64, ARM11, ARM7, ARM9, Cortex-A/R (v7-A/R), Cortex-M (ARMv{6/7/8}-M), FA526, Feroceon/Dragonite, XScale. ARCv2, AVR32, DSP563xx, DSP5680xx, EnSilica eSi-RISC, EJTAG (MIPS32, MIPS64), -Intel Quark, LS102x-SAP, NDS32, RISC-V, ST STM8. +ESP32, ESP32-S2, ESP32-S3, Intel Quark, LS102x-SAP, RISC-V, ST STM8, +Xtensa. Flash drivers ------------- ADUC702x, AT91SAM, AT91SAM9 (NAND), ATH79, ATmega128RFA1, Atmel SAM, AVR, CFI, DSP5680xx, EFM32, EM357, eSi-RISC, eSi-TSMC, EZR32HG, FM3, FM4, Freedom E SPI, -i.MX31, Kinetis, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPC3180, LPC32xx, +GD32, i.MX31, Kinetis, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPC3180, LPC32xx, LPCSPIFI, Marvell QSPI, MAX32, Milandr, MXC, NIIET, nRF51, nRF52 , NuMicro, -NUC910, Orion/Kirkwood, PIC32mx, PSoC4/5LP/6, Renesas RPC HF and SH QSPI, +NUC910, Nuvoton NPCX, onsemi RSL10, Orion/Kirkwood, PIC32mx, PSoC4/5LP/6, +Raspberry RP2040, Renesas RPC HF and SH QSPI, S3C24xx, S3C6400, SiM3x, SiFive Freedom E, Stellaris, ST BlueNRG, STM32, STM32 QUAD/OCTO-SPI for Flash/FRAM/EEPROM, STMSMI, STR7x, STR9x, SWM050, TI CC13xx, TI CC26xx, TI CC32xx, TI MSP432, Winner Micro w600, Xilinx XCF, @@ -259,7 +262,10 @@ You'll also need: - make - libtool -- pkg-config >= 0.23 (or compatible) +- pkg-config >= 0.23 or pkgconf + +OpenOCD uses jimtcl library; build from git can retrieve jimtcl as git +submodule. Additionally, for building from git: @@ -267,14 +273,25 @@ Additionally, for building from git: - automake >= 1.14 - texinfo >= 5.0 -USB-based adapters depend on libusb-1.0. A compatible implementation, such as -FreeBSD's, additionally needs the corresponding .pc files. +Optional USB-based adapter drivers need libusb-1.0. -USB-Blaster, ASIX Presto and OpenJTAG interface adapter +Optional USB-Blaster, ASIX Presto and OpenJTAG interface adapter drivers need: - libftdi: http://www.intra2net.com/en/developer/libftdi/index.php -CMSIS-DAP support needs HIDAPI library. +Optional CMSIS-DAP adapter driver needs HIDAPI library. + +Optional linuxgpiod adapter driver needs libgpiod library. + +Optional J-Link adapter driver needs libjaylink library. + +Optional ARM disassembly needs capstone library. + +Optional development script checkpatch needs: + +- perl +- python +- python-ply Permissions delegation ---------------------- diff --git a/README.Windows b/README.Windows index 7326a356ca..64bf5c0c6f 100644 --- a/README.Windows +++ b/README.Windows @@ -52,5 +52,5 @@ port depending on which application to use. For more information, see: - http://msdn.microsoft.com/en-us/library/windows/hardware/jj649944(v=vs.85).aspx + https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-device-specific-registry-settings http://www.ftdichip.com/Support/Knowledgebase/index.html?ignorehardwareserialnumber.htm diff --git a/TODO b/TODO index ebb6c99808..e4dded0ce6 100644 --- a/TODO +++ b/TODO @@ -202,8 +202,6 @@ https://lists.berlios.de/pipermail/openocd-development/2009-October/011506.html - MC1322x support (JW/DE?) - integrate and test support from JW (and DE?) - get working with a known good interface (i.e. not today's jlink) -- AT91SAM92xx: - - improvements for unknown-board-atmel-at91sam9260.cfg (RD) - STR9x: (ZW) - improvements to str912.cfg to be more general purpose - AVR: (SQ) diff --git a/bootstrap b/bootstrap index e81ba4d02d..cf6167fff6 100755 --- a/bootstrap +++ b/bootstrap @@ -1,4 +1,6 @@ #!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later + # Run the autotools bootstrap sequence to create the configure script # Abort execution on error diff --git a/configure.ac b/configure.ac index 081e7744d9..274be15c30 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + AC_PREREQ([2.69]) -AC_INIT([openocd], [0.11.0+dev], +AC_INIT([openocd], [0.12.0+dev], [OpenOCD Mailing List ]) AC_CONFIG_SRCDIR([src/openocd.c]) AC_CONFIG_AUX_DIR([build-aux]) @@ -24,6 +26,12 @@ AC_PROG_CC m4_version_prereq([2.70],[],[AC_PROG_CC_C99]) AM_PROG_CC_C_O AC_PROG_RANLIB + +# If macro PKG_PROG_PKG_CONFIG is not available, Autoconf generates a misleading error message, +# so check for existence first, and otherwise provide helpful advice. +m4_ifndef([PKG_PROG_PKG_CONFIG], [m4_fatal(m4_normalize([ + Macro PKG_PROG_PKG_CONFIG is not available. + It is usually defined in file pkg.m4 provided by package pkg-config.]))]) PKG_PROG_PKG_CONFIG([0.23]) dnl disable checks for C++, Fortran and GNU Java Compiler @@ -47,12 +55,10 @@ AC_CHECK_HEADERS([elf.h]) AC_EGREP_HEADER(Elf64_Ehdr, [elf.h], [ AC_DEFINE([HAVE_ELF64], [1], [Define to 1 if the system has the type `Elf64_Ehdr'.]) ]) -AC_CHECK_HEADERS([dirent.h]) AC_CHECK_HEADERS([fcntl.h]) AC_CHECK_HEADERS([malloc.h]) AC_CHECK_HEADERS([netdb.h]) AC_CHECK_HEADERS([poll.h]) -AC_CHECK_HEADERS([pthread.h]) AC_CHECK_HEADERS([strings.h]) AC_CHECK_HEADERS([sys/ioctl.h]) AC_CHECK_HEADERS([sys/param.h]) @@ -62,7 +68,7 @@ AC_CHECK_HEADERS([sys/sysctl.h]) AC_CHECK_HEADERS([sys/time.h]) AC_CHECK_HEADERS([sys/types.h]) AC_CHECK_HEADERS([unistd.h]) -AC_CHECK_HEADERS([arpa/inet.h ifaddrs.h netinet/in.h netinet/tcp.h net/if.h], [], [], [dnl +AC_CHECK_HEADERS([arpa/inet.h netinet/in.h netinet/tcp.h], [], [], [dnl #include #ifdef STDC_HEADERS # include @@ -86,7 +92,6 @@ AC_CHECK_FUNCS([strndup]) AC_CHECK_FUNCS([strnlen]) AC_CHECK_FUNCS([gettimeofday]) AC_CHECK_FUNCS([usleep]) -AC_CHECK_FUNCS([vasprintf]) AC_CHECK_FUNCS([realpath]) # guess-rev.sh only exists in the repository, not in the released archives @@ -114,6 +119,7 @@ m4_define([USB1_ADAPTERS], [[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]], [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]], [[ulink], [Keil ULINK JTAG Programmer], [ULINK]], + [[angie], [ANGIE Adapter], [ANGIE]], [[usb_blaster_2], [Altera USB-Blaster II Compatible], [USB_BLASTER_2]], [[ft232r], [Bitbang mode of FT232R based devices], [FT232R]], [[vsllink], [Versaloon-Link JTAG Programmer], [VSLLINK]], @@ -123,10 +129,8 @@ m4_define([USB1_ADAPTERS], [[opendous], [eStick/opendous JTAG Programmer], [OPENDOUS]], [[armjtagew], [Olimex ARM-JTAG-EW Programmer], [ARMJTAGEW]], [[rlink], [Raisonance RLink JTAG Programmer], [RLINK]], - [[usbprog], [USBProg JTAG Programmer], [USBPROG]]]) - -m4_define([DEPRECATED_USB1_ADAPTERS], - [[[aice], [Andes JTAG Programmer (deprecated)], [AICE]]]) + [[usbprog], [USBProg JTAG Programmer], [USBPROG]], + [[esp_usb_jtag], [Espressif JTAG Programmer], [ESP_USB_JTAG]]]) m4_define([HIDAPI_ADAPTERS], [[[cmsis_dap], [CMSIS-DAP Compliant Debugger], [CMSIS_DAP_HID]], @@ -239,6 +243,10 @@ AC_ARG_ENABLE([rshim], AS_HELP_STRING([--enable-rshim], [Enable building the rshim driver]), [build_rshim=$enableval], [build_rshim=no]) +AC_ARG_ENABLE([dmem], + AS_HELP_STRING([--enable-dmem], [Enable building the dmem driver]), + [build_dmem=$enableval], [build_dmem=no]) + m4_define([AC_ARG_ADAPTERS], [ m4_foreach([adapter], [$1], [AC_ARG_ENABLE(ADAPTER_OPT([adapter]), @@ -259,8 +267,6 @@ AC_ARG_ADAPTERS([ LIBJAYLINK_ADAPTERS ],[auto]) -AC_ARG_ADAPTERS([DEPRECATED_USB1_ADAPTERS],[no]) - AC_ARG_ENABLE([parport], AS_HELP_STRING([--enable-parport], [Enable building the pc parallel port driver]), [build_parport=$enableval], [build_parport=no]) @@ -299,10 +305,14 @@ AS_CASE(["${host_cpu}"], AC_ARG_ENABLE([imx_gpio], AS_HELP_STRING([--enable-imx_gpio], [Enable building support for bitbanging on NXP IMX processors]), [build_imx_gpio=$enableval], [build_imx_gpio=no]) + AC_ARG_ENABLE([am335xgpio], + AS_HELP_STRING([--enable-am335xgpio], [Enable building support for bitbanging on AM335x (as found in Beaglebones)]), + [build_am335xgpio=$enableval], [build_am335xgpio=no]) ], [ build_bcm2835gpio=no build_imx_gpio=no + build_am335xgpio=no ]) AS_CASE(["${host_cpu}"], @@ -353,6 +363,10 @@ AS_CASE([$host_os], AC_MSG_ERROR([build_rshim is only available on linux or freebsd]) ]) ]) + + AS_IF([test "x$build_dmem" = "xyes"], [ + AC_MSG_ERROR([dmem is only available on linux]) + ]) ]) AC_ARG_ENABLE([internal-jimtcl], @@ -364,12 +378,12 @@ AC_ARG_ENABLE([jimtcl-maintainer], [use_internal_jimtcl_maintainer=$enableval], [use_internal_jimtcl_maintainer=no]) AC_ARG_ENABLE([internal-libjaylink], - AS_HELP_STRING([--disable-internal-libjaylink], - [Disable building internal libjaylink]), - [use_internal_libjaylink=$enableval], [use_internal_libjaylink=yes]) + AS_HELP_STRING([--enable-internal-libjaylink], + [Enable building internal libjaylink]), + [use_internal_libjaylink=$enableval], [use_internal_libjaylink=no]) AC_ARG_ENABLE([remote-bitbang], - AS_HELP_STRING([--enable-remote-bitbang], [Enable building support for the Remote Bitbang jtag driver]), + AS_HELP_STRING([--enable-remote-bitbang], [Enable building support for the Remote Bitbang driver]), [build_remote_bitbang=$enableval], [build_remote_bitbang=yes]) AS_CASE(["${host_cpu}"], @@ -473,6 +487,12 @@ AS_IF([test "x$build_rshim" = "xyes"], [ AC_DEFINE([BUILD_RSHIM], [0], [0 if you don't want to debug BlueField SoC via rshim.]) ]) +AS_IF([test "x$build_dmem" = "xyes"], [ + AC_DEFINE([BUILD_DMEM], [1], [1 if you want to debug via Direct Mem.]) +], [ + AC_DEFINE([BUILD_DMEM], [0], [0 if you don't want to debug via Direct Mem.]) +]) + AS_IF([test "x$build_dummy" = "xyes"], [ build_bitbang=yes AC_DEFINE([BUILD_DUMMY], [1], [1 if you want dummy driver.]) @@ -508,6 +528,13 @@ AS_IF([test "x$build_imx_gpio" = "xyes"], [ AC_DEFINE([BUILD_IMX_GPIO], [0], [0 if you don't want imx_gpio.]) ]) +AS_IF([test "x$build_am335xgpio" = "xyes"], [ + build_bitbang=yes + AC_DEFINE([BUILD_AM335XGPIO], [1], [1 if you want am335xgpio.]) +], [ + AC_DEFINE([BUILD_AM335XGPIO], [0], [0 if you don't want am335xgpio.]) +]) + AS_IF([test "x$parport_use_ppdev" = "xyes"], [ AC_DEFINE([PARPORT_USE_PPDEV], [1], [1 if you want parport to use ppdev.]) ], [ @@ -558,11 +585,11 @@ AS_IF([test "x$enable_buspirate" != "xno"], [ ]) AS_IF([test "x$use_internal_jimtcl" = "xyes"], [ - AS_IF([test -f "$srcdir/jimtcl/configure.ac"], [ + AS_IF([test -f "$srcdir/jimtcl/configure"], [ AS_IF([test "x$use_internal_jimtcl_maintainer" = "xyes"], [ - jimtcl_config_options="--disable-install-jim --maintainer" + jimtcl_config_options="--disable-install-jim --with-ext=json --minimal --disable-ssl --maintainer" ], [ - jimtcl_config_options="--disable-install-jim" + jimtcl_config_options="--disable-install-jim --with-ext=json --minimal --disable-ssl" ]) AX_CONFIG_SUBDIR_OPTION([jimtcl], [$jimtcl_config_options]) ], [ @@ -572,9 +599,9 @@ AS_IF([test "x$use_internal_jimtcl" = "xyes"], [ AS_IF([test "x$build_remote_bitbang" = "xyes"], [ build_bitbang=yes - AC_DEFINE([BUILD_REMOTE_BITBANG], [1], [1 if you want the Remote Bitbang JTAG driver.]) + AC_DEFINE([BUILD_REMOTE_BITBANG], [1], [1 if you want the Remote Bitbang driver.]) ], [ - AC_DEFINE([BUILD_REMOTE_BITBANG], [0], [0 if you don't want the Remote Bitbang JTAG driver.]) + AC_DEFINE([BUILD_REMOTE_BITBANG], [0], [0 if you don't want the Remote Bitbang driver.]) ]) AS_IF([test "x$build_sysfsgpio" = "xyes"], [ @@ -615,7 +642,6 @@ AS_IF([test "x$enable_capstone" != xno], [ PKG_CHECK_MODULES([CAPSTONE], [capstone], [ AC_DEFINE([HAVE_CAPSTONE], [1], [1 if you have Capstone disassembly framework.]) ], [ - AC_DEFINE([HAVE_CAPSTONE], [0], [0 if you don't have Capstone disassembly framework.]) if test "x$enable_capstone" != xauto; then AC_MSG_ERROR([--with-capstone was given, but test for Capstone failed]) fi @@ -623,6 +649,10 @@ AS_IF([test "x$enable_capstone" != xno], [ ]) ]) +AS_IF([test "x$enable_capstone" == xno], [ + AC_DEFINE([HAVE_CAPSTONE], [0], [0 if you don't have Capstone disassembly framework.]) +]) + for hidapi_lib in hidapi hidapi-hidraw hidapi-libusb; do PKG_CHECK_MODULES([HIDAPI],[$hidapi_lib],[ use_hidapi=yes @@ -665,7 +695,6 @@ m4_define([PROCESS_ADAPTERS], [ ]) PROCESS_ADAPTERS([USB1_ADAPTERS], ["x$use_libusb1" = "xyes"], [libusb-1.x]) -PROCESS_ADAPTERS([DEPRECATED_USB1_ADAPTERS], ["x$use_libusb1" = "xyes"], [libusb-1.x]) PROCESS_ADAPTERS([HIDAPI_ADAPTERS], ["x$use_hidapi" = "xyes"], [hidapi]) PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libusb1" = "xyes"], [hidapi and libusb-1.x]) PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi]) @@ -694,7 +723,7 @@ AS_IF([test "x$enable_jlink" != "xno"], [ AX_CONFIG_SUBDIR_OPTION([src/jtag/drivers/libjaylink], [--enable-subproject-build]) ], [ - AC_MSG_ERROR([Internal libjaylink not found, run either 'git submodule init' and 'git submodule update' or disable internal libjaylink with --disable-internal-libjaylink.]) + AC_MSG_ERROR([Internal libjaylink not found, run 'git submodule init' and 'git submodule update'.]) ]) ]) ]) @@ -704,6 +733,11 @@ AS_IF([test "x$enable_presto" != "xno"], [ build_bitq=yes ]) +# esp-usb-jtag also needs the bitq module +AS_IF([test "x$enable_esp_usb_jtag" != "xno"], [ + build_bitq=yes +]) + AM_CONDITIONAL([RELEASE], [test "x$build_release" = "xyes"]) AM_CONDITIONAL([PARPORT], [test "x$build_parport" = "xyes"]) AM_CONDITIONAL([DUMMY], [test "x$build_dummy" = "xyes"]) @@ -712,6 +746,7 @@ AM_CONDITIONAL([EP93XX], [test "x$build_ep93xx" = "xyes"]) AM_CONDITIONAL([AT91RM9200], [test "x$build_at91rm9200" = "xyes"]) AM_CONDITIONAL([BCM2835GPIO], [test "x$build_bcm2835gpio" = "xyes"]) AM_CONDITIONAL([IMX_GPIO], [test "x$build_imx_gpio" = "xyes"]) +AM_CONDITIONAL([AM335XGPIO], [test "x$build_am335xgpio" = "xyes"]) AM_CONDITIONAL([BITBANG], [test "x$build_bitbang" = "xyes"]) AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes"]) AM_CONDITIONAL([VDEBUG], [test "x$build_vdebug" = "xyes"]) @@ -734,6 +769,7 @@ AM_CONDITIONAL([USE_LIBGPIOD], [test "x$use_libgpiod" = "xyes"]) AM_CONDITIONAL([USE_HIDAPI], [test "x$use_hidapi" = "xyes"]) AM_CONDITIONAL([USE_LIBJAYLINK], [test "x$use_libjaylink" = "xyes"]) AM_CONDITIONAL([RSHIM], [test "x$build_rshim" = "xyes"]) +AM_CONDITIONAL([DMEM], [test "x$build_dmem" = "xyes"]) AM_CONDITIONAL([HAVE_CAPSTONE], [test "x$enable_capstone" != "xno"]) AM_CONDITIONAL([INTERNAL_JIMTCL], [test "x$use_internal_jimtcl" = "xyes"]) @@ -781,7 +817,6 @@ AS_IF([test "x${gcc_wextra}" = "xyes"], [ GCC_WARNINGS="${GCC_WARNINGS} -Wredundant-decls" GCC_WARNINGS="${GCC_WARNINGS} -Wpointer-arith" GCC_WARNINGS="${GCC_WARNINGS} -Wundef" - GCC_WARNINGS="${GCC_WARNINGS} -Wno-error=deprecated-declarations" ]) AS_IF([test "x${gcc_werror}" = "xyes"], [ GCC_WARNINGS="${GCC_WARNINGS} -Werror" @@ -799,12 +834,17 @@ AC_CONFIG_FILES([ ]) AC_OUTPUT +AS_IF([test "x$enable_jlink" != "xno"], [ + AS_IF([test "x$use_internal_libjaylink" = "xyes"], [ + AC_MSG_WARN([Using the internal libjaylink is deprecated and will not be possible in the future.]) + ]]) +) + echo echo echo OpenOCD configuration summary echo -------------------------------------------------- m4_foreach([adapter], [USB1_ADAPTERS, - DEPRECATED_USB1_ADAPTERS, HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, LIBFTDI_USB1_ADAPTERS, LIBGPIOD_ADAPTERS, diff --git a/contrib/60-openocd.rules b/contrib/60-openocd.rules index 34defada09..fe8b00cb7a 100644 --- a/contrib/60-openocd.rules +++ b/contrib/60-openocd.rules @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Copy this file to /etc/udev/rules.d/ # If rules fail to reload automatically, you can refresh udev rules # with the command "udevadm control --reload" @@ -97,6 +99,8 @@ ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374e", MODE="660", GROUP="plugdev", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374f", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3753", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3754", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3755", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3757", MODE="660", GROUP="plugdev", TAG+="uaccess" # Cypress SuperSpeed Explorer Kit ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="0007", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -216,6 +220,17 @@ ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6010", MODE="660", GROUP="plugdev", ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6011", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="1106", MODE="660", GROUP="plugdev", TAG+="uaccess" +# Espressif USB JTAG/serial debug units +ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1002", MODE="660", GROUP="plugdev", TAG+="uaccess" + +# ANGIE USB-JTAG Adapter +ATTRS{idVendor}=="584e", ATTRS{idProduct}=="414f", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="584e", ATTRS{idProduct}=="424e", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="584e", ATTRS{idProduct}=="4255", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="584e", ATTRS{idProduct}=="4355", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="584e", ATTRS{idProduct}=="4a55", MODE="660", GROUP="plugdev", TAG+="uaccess" + # Marvell Sheevaplug ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="660", GROUP="plugdev", TAG+="uaccess" diff --git a/contrib/buildroot/openocd_be_defconfig b/contrib/buildroot/openocd_be_defconfig new file mode 100644 index 0000000000..49a6ec2ac4 --- /dev/null +++ b/contrib/buildroot/openocd_be_defconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +BR2_armeb=y +BR2_cortex_a7=y +BR2_TOOLCHAIN_EXTERNAL=y +BR2_PACKAGE_OPENOCD=y +BR2_PACKAGE_OPENOCD_FTDI=y +BR2_PACKAGE_OPENOCD_STLINK=y +BR2_PACKAGE_OPENOCD_TI_ICDI=y +BR2_PACKAGE_OPENOCD_ULINK=y +BR2_PACKAGE_OPENOCD_UBLASTER2=y +BR2_PACKAGE_OPENOCD_JLINK=y +BR2_PACKAGE_OPENOCD_OSDBM=y +BR2_PACKAGE_OPENOCD_OPENDOUS=y +BR2_PACKAGE_OPENOCD_VSLLINK=y +BR2_PACKAGE_OPENOCD_USBPROG=y +BR2_PACKAGE_OPENOCD_RLINK=y +BR2_PACKAGE_OPENOCD_ARMEW=y +BR2_PACKAGE_OPENOCD_XDS110=y +BR2_PACKAGE_OPENOCD_PARPORT=y +BR2_PACKAGE_OPENOCD_VPI=y +BR2_PACKAGE_OPENOCD_UBLASTER=y +BR2_PACKAGE_OPENOCD_AMTJT=y +BR2_PACKAGE_OPENOCD_GW16012=y +BR2_PACKAGE_OPENOCD_PRESTO=y +BR2_PACKAGE_OPENOCD_OPENJTAG=y +BR2_PACKAGE_OPENOCD_BUSPIRATE=y +BR2_PACKAGE_OPENOCD_SYSFS=y diff --git a/contrib/cross-build.sh b/contrib/cross-build.sh index 610607e1ce..bb8c8c47db 100755 --- a/contrib/cross-build.sh +++ b/contrib/cross-build.sh @@ -1,4 +1,5 @@ #!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later # This is an example of how to do a cross-build of OpenOCD using pkg-config. # Cross-building with pkg-config is deceptively hard and most guides and @@ -23,7 +24,7 @@ # export HIDAPI_SRC=/path/to/hidapi # export OPENOCD_CONFIG="--enable-..." # cd /work/dir -# .../path/to/openocd/contrib/cross-build.sh +# /path/to/openocd/contrib/cross-build.sh # # For static linking, a workaround is to # export LIBUSB1_CONFIG="--enable-static --disable-shared" @@ -40,12 +41,14 @@ WORK_DIR=$PWD : ${HIDAPI_SRC:=/path/to/hidapi} : ${LIBFTDI_SRC:=/path/to/libftdi} : ${CAPSTONE_SRC:=/path/to/capstone} +: ${LIBJAYLINK_SRC:=/path/to/libjaylink} OPENOCD_SRC=`readlink -m $OPENOCD_SRC` LIBUSB1_SRC=`readlink -m $LIBUSB1_SRC` HIDAPI_SRC=`readlink -m $HIDAPI_SRC` LIBFTDI_SRC=`readlink -m $LIBFTDI_SRC` CAPSTONE_SRC=`readlink -m $CAPSTONE_SRC` +LIBJAYLINK_SRC=`readlink -m $LIBJAYLINK_SRC` HOST_TRIPLET=$1 BUILD_DIR=$WORK_DIR/$HOST_TRIPLET-build @@ -53,6 +56,7 @@ LIBUSB1_BUILD_DIR=$BUILD_DIR/libusb1 HIDAPI_BUILD_DIR=$BUILD_DIR/hidapi LIBFTDI_BUILD_DIR=$BUILD_DIR/libftdi CAPSTONE_BUILD_DIR=$BUILD_DIR/capstone +LIBJAYLINK_BUILD_DIR=$BUILD_DIR/libjaylink OPENOCD_BUILD_DIR=$BUILD_DIR/openocd ## Root of host file tree @@ -121,11 +125,17 @@ fi if [ -d $LIBFTDI_SRC ] ; then mkdir -p $LIBFTDI_BUILD_DIR cd $LIBFTDI_BUILD_DIR - # libftdi requires libusb1 static libraries, granted by: - # export LIBUSB1_CONFIG="--enable-static ..." + # note : libftdi versions < 1.5 requires libusb1 static + # hint use : # export LIBUSB1_CONFIG="--enable-static ..." + # not needed since libftdi-1.5 when LIBFTDI_CONFIG="-DSTATICLIBS=OFF ..." + + # fix .cmake file + ESCAPED_SYSROOT=$(printf '%s\n' "$SYSROOT" | sed -e 's/[\/&]/\\&/g') + sed -i -E "s/(SET\(CMAKE_FIND_ROOT_PATH\s+).+\)/\1${ESCAPED_SYSROOT})/" \ + ${LIBFTDI_SRC}/cmake/Toolchain-${HOST_TRIPLET}.cmake + cmake $LIBFTDI_CONFIG \ - -DLIBUSB_INCLUDE_DIR=${SYSROOT}${PREFIX}/include/libusb-1.0 \ - -DLIBUSB_LIBRARIES=${SYSROOT}${PREFIX}/lib/libusb-1.0.a \ + -DCMAKE_TOOLCHAIN_FILE=${LIBFTDI_SRC}/cmake/Toolchain-${HOST_TRIPLET}.cmake \ -DCMAKE_INSTALL_PREFIX=${PREFIX} \ -DPKG_CONFIG_EXECUTABLE=`which pkg-config` \ $LIBFTDI_SRC @@ -148,9 +158,19 @@ if [ -d $CAPSTONE_SRC ] ; then sed -i '1s;^;prefix=/usr \ exec_prefix=${prefix} \ libdir=${exec_prefix}/lib \ -includedir=${prefix}/include\n\n;' $CAPSTONE_PC_FILE +includedir=${prefix}/include/capstone\n\n;' $CAPSTONE_PC_FILE fi +# libjaylink build & install into sysroot +if [ -d $LIBJAYLINK_SRC ] ; then + mkdir -p $LIBJAYLINK_BUILD_DIR + cd $LIBJAYLINK_BUILD_DIR + $LIBJAYLINK_SRC/configure --build=`$LIBJAYLINK_SRC/config.guess` --host=$HOST_TRIPLET \ + --with-sysroot=$SYSROOT --prefix=$PREFIX \ + $LIBJAYLINK_CONFIG + make -j $MAKE_JOBS + make install DESTDIR=$SYSROOT +fi # OpenOCD build & install into sysroot mkdir -p $OPENOCD_BUILD_DIR diff --git a/contrib/firmware/angie/c/Makefile b/contrib/firmware/angie/c/Makefile new file mode 100644 index 0000000000..1bcc1f7d1e --- /dev/null +++ b/contrib/firmware/angie/c/Makefile @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +#**************************************************************************** +# File : Makefile * +# Contents : Code for NanoXplore USB-JTAG ANGIE adapter hardware. * +# Based on openULINK project by: Martin Schmoelzer. * +# Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * +# * +# * +# ***************************************************************************/ + +# Define the name of tools. +PREFIX = + +# Small Device C Compiler: http://sdcc.sourceforge.net/ +CC = $(PREFIX)sdcc + +# 8051 assembler, part of the SDCC software package. +AS = $(PREFIX)sdas8051 + +# SDCC produces quite messy Intel HEX files. This tool is be used to re-format +# those files. It is not required for the firmware download functionality in +# the OpenOCD driver, but the resulting file is smaller. +PACKIHX = $(PREFIX)packihx + +# GNU binutils size. Used to print the size of the IHX file generated by SDCC. +SIZE = size + +# Source and header directories. +SRC_DIR = src +INCLUDE_DIR = include + +CODE_SIZE = 0x3C00 +XRAM_LOC = 0x3C00 +XRAM_SIZE = 0x0400 + +CFLAGS = --std-sdcc99 --opt-code-size --model-small +LDFLAGS = --code-loc 0x0000 --code-size $(CODE_SIZE) --xram-loc $(XRAM_LOC) \ + --xram-size $(XRAM_SIZE) --iram-size 256 --model-small + +# list of base object files +OBJECTS = main.rel usb.rel protocol.rel jtag.rel delay.rel USBJmpTb.rel serial.rel gpif.rel i2c.rel +HEADERS = $(INCLUDE_DIR)/usb.h \ + $(INCLUDE_DIR)/protocol.h \ + $(INCLUDE_DIR)/jtag.h \ + $(INCLUDE_DIR)/delay.h \ + $(INCLUDE_DIR)/reg_ezusb.h \ + $(INCLUDE_DIR)/io.h \ + $(INCLUDE_DIR)/serial.h \ + $(INCLUDE_DIR)/fx2macros.h \ + $(INCLUDE_DIR)/msgtypes.h \ + $(INCLUDE_DIR)/i2c.h + +# Disable all built-in rules. +.SUFFIXES: + +# Targets which are executed even when identically named file is present. +.PHONY: all, clean + +all: angie_firmware.ihx + $(SIZE) angie_firmware.ihx + +angie_firmware.ihx: $(OBJECTS) + $(CC) -mmcs51 $(LDFLAGS) -o $@ $^ + +# Rebuild every C module (there are only 8 of them) if any header changes. +%.rel: $(SRC_DIR)/%.c $(HEADERS) + $(CC) -c $(CFLAGS) -mmcs51 -I$(INCLUDE_DIR) -o $@ $< + +%.rel: $(SRC_DIR)/%.a51 + $(AS) -lsgo $@ $< + +clean: + rm -f *.asm *.lst *.rel *.rst *.sym *.ihx *.lk *.map *.mem + +bin: angie_firmware.ihx + makebin -p angie_firmware.ihx angie_firmware.bin + +hex: angie_firmware.ihx + $(PACKIHX) angie_firmware.ihx > fx2.hex diff --git a/contrib/firmware/angie/c/README b/contrib/firmware/angie/c/README new file mode 100644 index 0000000000..2d41da7a40 --- /dev/null +++ b/contrib/firmware/angie/c/README @@ -0,0 +1,37 @@ +#SPDX-License-Identifier: GPL-2.0-or-later + +This is the ANGIE firmware for ANGIE USB-JTAG adapter. + +The main components of ANGIE adapter are: +- Cypress EZ-USB FX2 microcontroller +- Spartan-6 FPGA +- SRAM memory chip +- Pin headers for various JTAG pin assignments + +To compile the firmware, the SDCC compiler package is required. Most Linux +distributions include SDCC in their official package repositories. The SDCC +source code can be found at http://sdcc.sourceforge.net/ + +Simply type "make bin" in the ANGIE directory to compile the firmware. +"make clean" will remove all generated files except the BIN file +required for downloading the firmware to ANGIE. + +Note that the EZ-USB FX2 microcontroller does not have on-chip flash, +ANGIE include on-board EEPROM memory to store the firmware program of +the FX2, but we are not going to use this method. + +Instead, upon initial connection of the ANGIE adapter to the host PC +via USB, the EZ-USB FX2 core has enough intelligence to act as a +stand-alone USB device, responding to USB control requests and allowing +firmware download via a special VENDOR-type control request. Then, the +EZ-USB microcontroller simulates a disconnect and re-connect to the USB bus. +It may take up to two seconds for the host to recognize the newly connected +device before OpenOCD can proceed to execute JTAG commands. This delay is +only visible when OpenOCD first uses a blank (unconfigured) ANGIE device. + +Once the firmware downloaded, the FX2 microcontroller activate its GPIF mode, +download the Spartan-6 FPGA's bitstream, program the FPGA rapidly, and switch +back to default io mode. + +Once the user disconnects the ANGIE adapter, all its memory contents are lost +and the firmware & bitstream download process has to be executed again. diff --git a/contrib/firmware/angie/c/include/delay.h b/contrib/firmware/angie/c/include/delay.h new file mode 100644 index 0000000000..0397941fe8 --- /dev/null +++ b/contrib/firmware/angie/c/include/delay.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/**************************************************************** + File : delay.h * + Contents : Delays handling header file for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************/ + +#ifndef __DELAY_H +#define __DELAY_H + +#include + +void syncdelay(uint8_t count); +void delay_5us(void); +void delay_1ms(void); +void delay_us(uint16_t delay); +void delay_ms(uint16_t delay); + +#ifndef _IFREQ +#define _IFREQ 48000 /* IFCLK frequency in kHz */ +#endif + +/* CFREQ can be any one of: 48000, 24000, or 12000 */ +#ifndef _CFREQ +#define _CFREQ 48000 /* CLKOUT frequency in kHz */ +#endif + +#if (_IFREQ < 5000) +#error "_IFREQ too small! Valid Range: 5000 to 48000..." +#endif + +#if (_IFREQ > 48000) +#error "_IFREQ too large! Valid Range: 5000 to 48000..." +#endif + +#if (_CFREQ != 48000) +#if (_CFREQ != 24000) +#if (_CFREQ != 12000) +#error "_CFREQ invalid! Valid values: 48000, 24000, 12000..." +#endif +#endif +#endif + +/* Synchronization Delay formula: see TRM section 15-14 */ +#define _SCYCL (3 * (_CFREQ) + 5 * (_IFREQ) - 1) / (2 * (_IFREQ)) +#endif diff --git a/contrib/firmware/angie/c/include/fx2macros.h b/contrib/firmware/angie/c/include/fx2macros.h new file mode 100644 index 0000000000..9067b56193 --- /dev/null +++ b/contrib/firmware/angie/c/include/fx2macros.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +/* + * This code was taken from the fx2lib project from this link: + * https://github.com/djmuhlestein/fx2lib + * + * Copyright (C) 2009 Ubixum, Inc. +*/ + +/*! \file + * Macros for simple common tasks in fx2 firmware. + * */ + +#ifndef FX2MACROS_H +#define FX2MACROS_H + +#include "reg_ezusb.h" + +typedef enum {FALSE = 0, TRUE} BOOL_VALS; + +/** + * \brief Used for getting and setting the CPU clock speed. + **/ +typedef enum {CLK_12M = 0, CLK_24M, CLK_48M} CLK_SPD; + +/** + * \brief Evaluates to a CLK_SPD enum. + **/ +#define CPUFREQ (CLK_SPD)((CPUCS & bmclkspd) >> 3) + +#endif diff --git a/contrib/firmware/angie/c/include/i2c.h b/contrib/firmware/angie/c/include/i2c.h new file mode 100644 index 0000000000..d0404923b3 --- /dev/null +++ b/contrib/firmware/angie/c/include/i2c.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/**************************************************************************** + File : i2c.h * + Contents : i2c bit-bang library * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#ifndef __I2C_H +#define __I2C_H + +#include +#include +#include + +void start_cd(void); +void repeated_start(void); +void stop_cd(void); +void clock_cd(void); +void send_ack(void); +void send_nack(void); +bool get_ack(void); + +uint8_t get_address(uint8_t adr, uint8_t rdwr); + +void send_byte(uint8_t input); +uint8_t receive_byte(void); +#endif diff --git a/contrib/firmware/angie/c/include/io.h b/contrib/firmware/angie/c/include/io.h new file mode 100644 index 0000000000..19289d11d8 --- /dev/null +++ b/contrib/firmware/angie/c/include/io.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/**************************************************************************** + File : io.h * + Contents : input/output declaration header file for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#ifndef __IO_H +#define __IO_H + +#include "reg_ezusb.h" + +/*************************************************************************** + * JTAG Signals: * + *************************************************************************** + * TMS ....... Test Mode Select * + * TCK ....... Test Clock * + * TDI ....... Test Data Input (from device point of view, not JTAG * + * adapter point of view!) * + * TDO ....... Test Data Output (from device point of view, not JTAG * + * adapter point of view!) * + * TRST ...... Test Reset: Used to reset the TAP Finite State Machine * + * into the Test Logic Reset state * + * SRST ..... Chip Reset * + ***************************************************************************/ + +/* PORT A */ +/* PA0 Not Connected */ +/* PA1 Not Connected */ +#define PIN_RDWR_B IOA2 +#define PIN_CSI_B IOA3 +#define PIN_INIT_B IOA4 +#define PIN_PROGRAM_B IOA5 +/* PA6 Not Connected */ +/* PA7 Not Connected */ + +/* PORT B */ +#define PIN_TRST IOB0 +#define PIN_TMS IOB1 +#define PIN_TCK IOB2 +#define PIN_TDI IOB3 +#define PIN_TDO IOB4 +#define PIN_SRST IOB5 +/* PB6 Not Connected */ +/* PB7 Not Connected */ + +/* JTAG Signals with direction 'OUT' on port B */ +/* PIN_TDI - PIN_TCK - PIN_TMS - PIN_TRST - PIN_SRST */ +#define MASK_PORTB_DIRECTION_OUT (bmbit0 | bmbit1 | bmbit2 | bmbit3 | bmbit5) + +/* PORT C */ +#define PIN_T0 IOC0 +#define PIN_T1 IOC1 +#define PIN_T2 IOC2 +#define PIN_T3 IOC3 +#define PIN_T4 IOC4 +/* PC5 Not Connected */ +/* PC6 Not Connected */ +/* PC7 Not Connected */ + +/* PORT D */ +#define PIN_SDA IOD0 +#define PIN_SCL IOD1 +#define PIN_SDA_DIR IOD2 +#define PIN_SCL_DIR IOD3 +/* PD4 Not Connected */ +/* PD5 Not Connected */ +/* PD6 Not Connected */ +/* PD7 Not Connected */ + +#endif diff --git a/contrib/firmware/angie/c/include/jtag.h b/contrib/firmware/angie/c/include/jtag.h new file mode 100644 index 0000000000..6d5df64805 --- /dev/null +++ b/contrib/firmware/angie/c/include/jtag.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/**************************************************************************** + File : jtag.h * + Contents : Jtag handling functions header file for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#ifndef __JTAG_H +#define __JTAG_H + +#include + +uint16_t jtag_get_signals(void); +void jtag_configure_tck_delay(uint8_t scan_in, uint8_t scan_out, + uint8_t scan_io, uint8_t tck, uint8_t tms); +void jtag_clock_tms(uint8_t count, uint8_t sequence); +void jtag_slow_clock_tms(uint8_t count, uint8_t sequence); +void jtag_set_signals(uint8_t low, uint8_t high); +void jtag_clock_tck(uint16_t count); +void jtag_slow_clock_tck(uint16_t count); +void jtag_scan_in(uint8_t out_offset, uint8_t in_offset); +void jtag_scan_out(uint8_t out_offset); +void jtag_scan_io(uint8_t out_offset, uint8_t in_offset); +void jtag_slow_scan_in(uint8_t out_offset, uint8_t in_offset); +void jtag_slow_scan_out(uint8_t out_offset); +void jtag_slow_scan_io(uint8_t out_offset, uint8_t in_offset); +#endif diff --git a/contrib/firmware/angie/c/include/msgtypes.h b/contrib/firmware/angie/c/include/msgtypes.h new file mode 100644 index 0000000000..91116904ad --- /dev/null +++ b/contrib/firmware/angie/c/include/msgtypes.h @@ -0,0 +1,171 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/**************************************************************************** + File : msgtypes.h * + Contents : Definition of the commands supported by NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +/** + * @file + * Definition of the commands supported by the ANGIE firmware. + * + * Basically, two types of commands can be distinguished: + * - Commands with fixed payload size + * - Commands with variable payload size + * + * SCAN commands (in all variations) carry payloads of variable size, all + * other commands carry payloads of fixed size. + * + * In the case of SCAN commands, the payload size (n) is calculated by + * dividing the scan_size_bits variable by 8, rounding up the result. + * + * Offset zero always contains the command ID. + * + **************************************************************************** + * CMD_SCAN_IN, CMD_SLOW_SCAN_IN: * + * * + * OUT: * + * offset 1: scan_size_bytes * + * offset 2: bits_last_byte * + * offset 3: tms_count_start + tms_count_end * + * offset 4: tms_sequence_start * + * offset 5: tms_sequence_end * + * * + * IN: * + * offset 0..n: TDO data * + **************************************************************************** + * CMD_SCAN_OUT, CMD_SLOW_SCAN_OUT: * + * * + * OUT: * + * offset 1: scan_size_bytes * + * offset 2: bits_last_byte * + * offset 3: tms_count_start + tms_count_end * + * offset 4: tms_sequence_start * + * offset 5: tms_sequence_end * + * offset 6..x: TDI data * + **************************************************************************** + * CMD_SCAN_IO, CMD_SLOW_SCAN_IO: * + * * + * OUT: * + * offset 1: scan_size_bytes * + * offset 2: bits_last_byte * + * offset 3: tms_count_start + tms_count_end * + * offset 4: tms_sequence_start * + * offset 5: tms_sequence_end * + * offset 6..x: TDI data * + * * + * IN: * + * offset 0..n: TDO data * + **************************************************************************** + * CMD_CLOCK_TMS, CMD_SLOW_CLOCK_TMS: * + * * + * OUT: * + * offset 1: tms_count * + * offset 2: tms_sequence * + **************************************************************************** + * CMD_CLOCK_TCK, CMD_SLOW_CLOCK_TCK: * + * * + * OUT: * + * offset 1: low byte of tck_count * + * offset 2: high byte of tck_count * + **************************************************************************** + * CMD_CLOCK_SLEEP_US: * + * * + * OUT: * + * offset 1: low byte of sleep_us * + * offset 2: high byte of sleep_us * + **************************************************************************** + * CMD_CLOCK_SLEEP_MS: * + * * + * OUT: * + * offset 1: low byte of sleep_ms * + * offset 2: high byte of sleep_ms * + **************************************************************************** + * CMD_GET_SIGNALS: * + * * + * IN: * + * offset 0: current state of input signals * + * offset 1: current state of output signals * + **************************************************************************** + * CMD_SET_SIGNALS: * + * * + * OUT: * + * offset 1: signals that should be de-asserted * + * offset 2: signals that should be asserted * + **************************************************************************** + * CMD_CONFIGURE_TCK_FREQ: * + * * + * OUT: * + * offset 1: delay value for scan_in function * + * offset 2: delay value for scan_out function * + * offset 3: delay value for scan_io function * + * offset 4: delay value for clock_tck function * + * offset 5: delay value for clock_tms function * + **************************************************************************** + * CMD_SET_LEDS: * + * * + * OUT: * + * offset 1: LED states: * + * Bit 0: turn COM LED on * + * Bit 1: turn RUN LED on * + * Bit 2: turn COM LED off * + * Bit 3: turn RUN LED off * + * Bits 7..4: Reserved * + **************************************************************************** + * CMD_TEST: * + * * + * OUT: * + * offset 1: unused dummy value * + **************************************************************************** + */ + +#ifndef __MSGTYPES_H +#define __MSGTYPES_H + +/* + * Command IDs: + * + * Bits 7..6: Reserved, should always be zero + * Bits 5..0: Command ID. There are 62 usable IDs. Of this 63 available IDs, + * the IDs 0x00..0x1F are commands with variable payload size, + * the IDs 0x20..0x3F are commands with fixed payload size. + */ + +#define CMD_ID_MASK 0x3F + +/* Commands with variable payload size */ +#define CMD_SCAN_IN 0x00 +#define CMD_SLOW_SCAN_IN 0x01 +#define CMD_SCAN_OUT 0x02 +#define CMD_SLOW_SCAN_OUT 0x03 +#define CMD_SCAN_IO 0x04 +#define CMD_SLOW_SCAN_IO 0x05 + +/* Commands with fixed payload size */ +#define CMD_CLOCK_TMS 0x20 +#define CMD_SLOW_CLOCK_TMS 0x21 +#define CMD_CLOCK_TCK 0x22 +#define CMD_SLOW_CLOCK_TCK 0x23 +#define CMD_SLEEP_US 0x24 +#define CMD_SLEEP_MS 0x25 +#define CMD_GET_SIGNALS 0x26 +#define CMD_SET_SIGNALS 0x27 +#define CMD_CONFIGURE_TCK_FREQ 0x28 +#define CMD_SET_LEDS 0x29 +#define CMD_TEST 0x2A + +/* JTAG signal definition for jtag_get_signals() -- Input signals! */ +#define SIGNAL_TDO 1 + +/* JTAG signal definition for jtag_get_signals() -- Output signals! */ +#define SIGNAL_TDI 8 +#define SIGNAL_TMS 2 +#define SIGNAL_TCK 4 +#define SIGNAL_TRST 1 +#define SIGNAL_SRST 32 + +#endif diff --git a/contrib/firmware/angie/c/include/protocol.h b/contrib/firmware/angie/c/include/protocol.h new file mode 100644 index 0000000000..a12644b27d --- /dev/null +++ b/contrib/firmware/angie/c/include/protocol.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/**************************************************************************** + File : protocol.h * + Contents : Jtag commands handling protocol header file for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#ifndef __PROTOCOL_H +#define __PROTOCOL_H + +#include + +bool execute_command(void); +void command_loop(void); + +#endif diff --git a/contrib/firmware/angie/c/include/reg_ezusb.h b/contrib/firmware/angie/c/include/reg_ezusb.h new file mode 100644 index 0000000000..c22476a1a6 --- /dev/null +++ b/contrib/firmware/angie/c/include/reg_ezusb.h @@ -0,0 +1,656 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/**************************************************************************** + File : reg_ezusb.h * + Contents : FX2 microcontroller registers file for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#ifndef REG_EZUSB_H +#define REG_EZUSB_H + +/** + * @file + * All information in this file was taken from the EZ-USB FX2 Technical + * Reference Manual, Cypress Semiconductor, 3901 North First Street + * San Jose, CA 95134 (www.cypress.com). + * + * The EZ-USB Technical Reference Manual is called "EZ-USB FX2 TRM" hereafter. + */ + +/* Compiler-specific definitions of SBIT, SFR, SFRX, ... macros */ +#include + +/* Bit vectors */ +#define bmbit0 0x01 +#define bmbit1 0x02 +#define bmbit2 0x04 +#define bmbit3 0x08 +#define bmbit4 0x10 +#define bmbit5 0x20 +#define bmbit6 0x40 +#define bmbit7 0x80 + +/************************************************************************** + ************************ Special Function Registers ********************** + ***************************************************************************/ +SFR(IOA, 0x80); +SBIT(IOA0, 0x80, 0); +SBIT(IOA1, 0x80, 1); +SBIT(IOA2, 0x80, 2); +SBIT(IOA3, 0x80, 3); +SBIT(IOA4, 0x80, 4); +SBIT(IOA5, 0x80, 5); +SBIT(IOA6, 0x80, 6); +SBIT(IOA7, 0x80, 7); + +SFR(SP, 0x81); +SFR(DPL0, 0x82); +SFR(DPH0, 0x83); +SFR(DPL1, 0x84); +SFR(DPL2, 0x85); + +SFR(DPS, 0x86); +#define SEL bmbit0 +/* Bit 1 read-only, always reads '0' */ +/* Bit 2 read-only, always reads '0' */ +/* Bit 3 read-only, always reads '0' */ +/* Bit 4 read-only, always reads '0' */ +/* Bit 5 read-only, always reads '0' */ +/* Bit 6 read-only, always reads '0' */ +/* Bit 7 read-only, always reads '0' */ + +SFR(PCON, 0x87); +#define IDLE bmbit0 +#define STOP bmbit1 +#define GF0 bmbit2 +#define GF1 bmbit3 +/* Bit 4 read-only, always reads '1' */ +/* Bit 5 read-only, always reads '1' */ +/* Bit 6 unused */ +#define SMOD0 bmbit7 + +SFR(TCON, 0x88); +SBIT(IT0, 0x88, 0); +SBIT(IE0, 0x88, 1); +SBIT(IT1, 0x88, 2); +SBIT(IE1, 0x88, 3); +SBIT(TR0, 0x88, 4); +SBIT(TF0, 0x88, 5); +SBIT(TR1, 0x88, 6); +SBIT(TF1, 0x88, 7); + +SFR(TMOD, 0x89); +SFR(TL0, 0x8A); +SFR(TL1, 0x8B); +SFR(TH0, 0x8C); +SFR(TH1, 0x8D); + +SFR(CKCON, 0x8E); +#define MD0 bmbit0 +#define MD1 bmbit1 +#define MD2 bmbit2 +#define T0M bmbit3 +#define T1M bmbit4 +#define T2M bmbit5 +/* Bit 6 unused */ +/* Bit 7 unused */ + +SFR(SPC_FNC, 0x8F); +#define BMWRS bmbit0 +/* Bit 1 read-only, always reads '0' */ +/* Bit 2 read-only, always reads '0' */ +/* Bit 3 read-only, always reads '0' */ +/* Bit 4 read-only, always reads '0' */ +/* Bit 5 read-only, always reads '0' */ +/* Bit 6 read-only, always reads '0' */ +/* Bit 7 read-only, always reads '0' */ + +SFR(IOB, 0x90); +SBIT(IOB0, 0x90, 0); +SBIT(IOB1, 0x90, 1); +SBIT(IOB2, 0x90, 2); +SBIT(IOB3, 0x90, 3); +SBIT(IOB4, 0x90, 4); +SBIT(IOB5, 0x90, 5); +SBIT(IOB6, 0x90, 6); +SBIT(IOB7, 0x90, 7); + +SFR(EXIF, 0x91); +SBIT(USBINT, 0x91, 4); +SBIT(I2CINT, 0x91, 5); +SBIT(IE4, 0x91, 6); +SBIT(IE5, 0x91, 7); + +SFR(MPAGE, 0x92); +SFR(SCON0, 0x98); +SBIT(RI, 0x98, 0); +SBIT(TI, 0x98, 1); +SBIT(RB8, 0x98, 2); +SBIT(TB8, 0x98, 3); +SBIT(REN, 0x98, 4); +SBIT(SM2, 0x98, 5); +SBIT(SM1, 0x98, 6); +SBIT(SM0, 0x98, 7); + +SFR(SBUF0, 0x99); +SFR(AUTOPTRH1, 0x9A); +SFR(AUTOPTRL1, 0x9B); +SFR(AUTOPTRH2, 0x9D); +SFR(AUTOPTRL2, 0x9E); + +#define AUTOPTR1H AUTOPTRH1 /* for backwards compatibility with examples */ +#define AUTOPTR1L AUTOPTRL1 /* for backwards compatibility with examples */ +#define APTR1H AUTOPTRH1 /* for backwards compatibility with examples */ +#define APTR1L AUTOPTRL1 /* for backwards compatibility with examples */ + +SFR(IOC, 0xA0); +SBIT(IOC0, 0xA0, 0); +SBIT(IOC1, 0xA0, 1); +SBIT(IOC2, 0xA0, 2); +SBIT(IOC3, 0xA0, 3); +SBIT(IOC4, 0xA0, 4); +SBIT(IOC5, 0xA0, 5); +SBIT(IOC6, 0xA0, 6); +SBIT(IOC7, 0xA0, 7); + +SFR(INT2CLR, 0xA1); +SFR(INT4CLR, 0xA2); +SFR(IE, 0xA8); +SBIT(EX0, 0xA8, 0); +SBIT(ET0, 0xA8, 1); +SBIT(EX1, 0xA8, 2); +SBIT(ET1, 0xA8, 3); +SBIT(ES0, 0xA8, 4); +SBIT(ET2, 0xA8, 5); +SBIT(ES1, 0xA8, 6); +SBIT(EA, 0xA8, 7); + +SFR(EP2468STAT, 0xAA); +#define EP8F bmbit7 +#define EP8E bmbit6 +#define EP6F bmbit5 +#define EP6E bmbit4 +#define EP4F bmbit3 +#define EP4E bmbit2 +#define EP2F bmbit1 +#define EP2E bmbit0 + +SFR(EP24FIFOFLGS, 0xAB); +SFR(EP68FIFOFLGS, 0xAC); +SFR(AUTOPTRSETUP, 0xAF); +SFR(IOD, 0xB0); +SBIT(IOD0, 0xB0, 0); +SBIT(IOD1, 0xB0, 1); +SBIT(IOD2, 0xB0, 2); +SBIT(IOD3, 0xB0, 3); +SBIT(IOD4, 0xB0, 4); +SBIT(IOD5, 0xB0, 5); +SBIT(IOD6, 0xB0, 6); +SBIT(IOD7, 0xB0, 7); + +SFR(IOE, 0xB1); +SFR(OEA, 0xB2); +SFR(OEB, 0xB3); +SFR(OEC, 0xB4); +SFR(OED, 0xB5); +SFR(OEE, 0xB6); + +SFR(IP, 0xB8); +SBIT(PX0, 0xB8, 0); +SBIT(PT0, 0xB8, 1); +SBIT(PX1, 0xB8, 2); +SBIT(PT1, 0xB8, 3); +SBIT(PS0, 0xB8, 4); +SBIT(PT2, 0xB8, 5); +SBIT(PS1, 0xB8, 6); +/* Bit 7 read-only, always reads '1' */ + +SFR(EP01STAT, 0xBA); +SFR(GPIFTRIG, 0xBB); +#define BMGPIFDONE bmbit7 +#define BMGPIFREAD bmbit2 +#define GPIF_EP2 0 +#define GPIF_EP4 1 +#define GPIF_EP6 2 +#define GPIF_EP8 3 + +SFR(GPIFSGLDATH, 0xBD); +SFR(GPIFSGLDATLX, 0xBE); +SFR(GPIFSGLDATLNOX, 0xBF); + +SFR(SCON1, 0xC0); +SBIT(RI_1, 0xC0, 0); +SBIT(TI_1, 0xC0, 1); +SBIT(RB8_1, 0xC0, 2); +SBIT(TB8_1, 0xC0, 3); +SBIT(REN_1, 0xC0, 4); +SBIT(SM2_1, 0xC0, 5); +SBIT(SM1_1, 0xC0, 6); +SBIT(SM0_1, 0xC0, 7); + +SFR(SBUF1, 0xC1); +SFR(T2CON, 0xC8); +SBIT(CPRL2, 0xC8, 0); +SBIT(C_T2, 0xC8, 1); +SBIT(TR2, 0xC8, 2); +SBIT(EXEN2, 0xC8, 3); +SBIT(TCLK, 0xC8, 4); +SBIT(RCLK, 0xC8, 5); +SBIT(EXF2, 0xC8, 6); +SBIT(TF2, 0xC8, 7); + +SFR(RCAP2L, 0xCA); +SFR(RCAP2H, 0xCB); +SFR(TL2, 0xCC); +SFR(TH2, 0xCD); +SFR(PSW, 0xD0); +SBIT(P, 0xD0, 0); +SBIT(F1, 0xD0, 1); +SBIT(OV, 0xD0, 2); +SBIT(RS0, 0xD0, 3); +SBIT(RS1, 0xD0, 4); +SBIT(F0, 0xD0, 5); +SBIT(AC, 0xD0, 6); +SBIT(CY, 0xD0, 7); + +SFR(EICON, 0xD8); +/* Bit 0 read-only, always reads '0' */ +/* Bit 1 read-only, always reads '0' */ +/* Bit 2 read-only, always reads '0' */ +SBIT(INT6, 0xD8, 3); +SBIT(RESI, 0xD8, 4); +SBIT(ERESI, 0xD8, 5); +/* Bit 6 read-only, always reads '1' */ +SBIT(SMOD1, 0xD8, 7); + +SFR(ACC, 0xE0); +SFR(EIE, 0xE8); +SBIT(EUSB, 0xE8, 0); +SBIT(EI2C, 0xE8, 1); +SBIT(EX4, 0xE8, 2); +SBIT(EX5, 0xE8, 3); +SBIT(EWDI, 0xE8, 4); +/* Bit 5 read-only, always reads '1' */ +/* Bit 6 read-only, always reads '1' */ +/* Bit 7 read-only, always reads '1' */ + +SFR(B, 0xF0); +SFR(EIP, 0xF8); +SBIT(PUSB, 0xF8, 0); +SBIT(PI2C, 0xF8, 1); +SBIT(PX4, 0xF8, 2); +SBIT(PX5, 0xF8, 3); +SBIT(PX6, 0xF8, 4); +/* Bit 5 read-only, always reads '1' */ +/* Bit 6 read-only, always reads '1' */ +/* Bit 7 read-only, always reads '1' */ + +/************************************************************************** + ***************************** XDATA Registers **************************** + ***************************************************************************/ + +SFRX(GPIF_WAVE_DATA, 0xE400); +SFRX(RES_WAVEDATA_END, 0xE480); + +/* General Configuration */ +SFRX(CPUCS, 0xE600); +#define RES8051 bmbit0 +#define CLKOE bmbit1 +#define BMCLKINV bmbit2 +#define bmclkspd0 bmbit3 +#define bmclkspd1 bmbit4 +#define bmclkspd (bmbit4 | bmbit3) +#define BMPRTCSTB bmbit5 + +/* PCON register */ +#define BMSMOD0 bmbit7 + +SFRX(IFCONFIG, 0xE601); +#define BMIFCLKSRC bmbit7 +#define BM3048MHZ bmbit6 +#define BMIFCLKOE bmbit5 +#define BMIFCLKPOL bmbit4 +#define BMASYNC bmbit3 +#define BMGSTATE bmbit2 +#define BMIFCFG1 bmbit1 +#define BMIFCFG0 bmbit0 +#define BMIFCFGMASK (BMIFCFG0 | BMIFCFG1) +#define BMIFGPIF BMIFCFG1 + +SFRX(PINFLAGSAB, 0xE602); +SFRX(PINFLAGSCD, 0xE603); +SFRX(FIFORESET, 0xE604); +#define BMNAKALL bmbit7 + +SFRX(BREAKPT, 0xE605); +#define BMBREAK bmbit3 +#define BMBPPULSE bmbit2 +#define BMBPEN bmbit1 + +SFRX(BPADDRH, 0xE606); +SFRX(BPADDRL, 0xE607); +SFRX(UART230, 0xE608); +SFRX(FIFOPINPOLAR, 0xE609); +SFRX(REVID, 0xE60A); +SFRX(REVCTL, 0xE60B); +#define BMNOAUTOARM bmbit1 +#define BMSKIPCOMMIT bmbit0 + +/* Endpoint Configuration */ +SFRX(EP1OUTCFG, 0xE610); +SFRX(EP1INCFG, 0xE611); +SFRX(EP2CFG, 0xE612); +SFRX(EP4CFG, 0xE613); +SFRX(EP6CFG, 0xE614); +SFRX(EP8CFG, 0xE615); +SFRX(EP2FIFOCFG, 0xE618); +SFRX(EP4FIFOCFG, 0xE619); +SFRX(EP6FIFOCFG, 0xE61A); +SFRX(EP8FIFOCFG, 0xE61B); +#define BMINFM bmbit6 +#define BMOEP bmbit5 +#define BMAUTOOUT bmbit4 +#define BMAUTOIN bmbit3 +#define BMZEROLENIN bmbit2 +#define BMWORDWIDE bmbit0 + +SFRX(EP2AUTOINLENH, 0xE620); +SFRX(EP2AUTOINLENL, 0xE621); +SFRX(EP4AUTOINLENH, 0xE622); +SFRX(EP4AUTOINLENL, 0xE623); +SFRX(EP6AUTOINLENH, 0xE612); +SFRX(EP6AUTOINLENL, 0xE613); +SFRX(EP8AUTOINLENH, 0xE614); +SFRX(EP8AUTOINLENL, 0xE615); +SFRX(EP2FIFOPFH, 0xE630); +SFRX(EP2FIFOPFL, 0xE631); +SFRX(EP4FIFOPFH, 0xE632); +SFRX(EP4FIFOPFL, 0xE633); +SFRX(EP6FIFOPFH, 0xE634); +SFRX(EP6FIFOPFL, 0xE635); +SFRX(EP8FIFOPFH, 0xE636); +SFRX(EP8FIFOPFL, 0xE637); +SFRX(EP2ISOINPKTS, 0xE640); +SFRX(EP4ISOINPKTS, 0xE641); +SFRX(EP6ISOINPKTS, 0xE642); +SFRX(EP8ISOINPKTS, 0xE643); +SFRX(INPKTEND, 0xE648); +SFRX(OUTPKTEND, 0xE649); + +/* Interrupts */ +SFRX(EP2FIFOIE, 0xE650); +SFRX(EP2FIFOIRQ, 0xE651); +SFRX(EP4FIFOIE, 0xE652); +SFRX(EP4FIFOIRQ, 0xE653); +SFRX(EP6FIFOIE, 0xE654); +SFRX(EP6FIFOIRQ, 0xE655); +SFRX(EP8FIFOIE, 0xE656); +SFRX(EP8FIFOIRQ, 0xE657); +SFRX(IBNIE, 0xE658); +SFRX(IBNIRQ, 0xE659); +#define EP0IBN bmbit0 +#define EP1IBN bmbit1 +#define EP2IBN bmbit2 +#define EP4IBN bmbit3 +#define EP6IBN bmbit4 +#define EP8IBN bmbit5 + +SFRX(NAKIE, 0xE65A); +SFRX(NAKIRQ, 0xE65B); +#define EP8PING bmbit7 +#define EP6PING bmbit6 +#define EP4PING bmbit5 +#define EP2PING bmbit4 +#define EP1PING bmbit3 +#define EP0PING bmbit2 +#define IBN bmbit0 + +SFRX(USBIEN, 0xE65C); +SFRX(USBIRQ, 0xE65D); +#define SUDAVI bmbit0 +#define SOFI bmbit1 +#define SUTOKI bmbit2 +#define SUSPI bmbit3 +#define URESI bmbit4 +#define HSGRANT bmbit5 +#define EP0ACK bmbit6 + +SFRX(EPIE, 0xE65E); +SFRX(EPIRQ, 0xE65F); +SFRX(GPIFIE, 0xE660); +SFRX(GPIFIRQ, 0xE661); +SFRX(USBERRIE, 0xE662); +SFRX(USBERRIRQ, 0xE663); +SFRX(ERRCNTLIM, 0xE664); +SFRX(CLRERRCNT, 0xE665); +SFRX(INT2IVEC, 0xE666); +#define I2V0 bmbit2 +#define I2V1 bmbit3 +#define I2V2 bmbit4 +#define I2V3 bmbit5 +#define I2V4 bmbit6 + +SFRX(INT4IVEC, 0xE667); +SFRX(INTSETUP, 0xE668); +#define AV4EN bmbit0 +#define INT4IN bmbit1 +#define AV2EN bmbit3 + +/* Input/Output */ +SFRX(PORTACFG, 0xE670); +#define BMINT0 bmbit0 +#define BMINT1 bmbit1 +#define BMFLAGD bmbit7 + +SFRX(PORTCCFG, 0xE671); +#define BMGPIFA0 bmbit0 +#define BMGPIFA1 bmbit1 +#define BMGPIFA2 bmbit2 +#define BMGPIFA3 bmbit3 +#define BMGPIFA4 bmbit4 +#define BMGPIFA5 bmbit5 +#define BMGPIFA6 bmbit6 +#define BMGPIFA7 bmbit7 + +SFRX(PORTECFG, 0xE672); +#define BMT0OUT bmbit0 +#define BMT1OUT bmbit1 +#define BMT2OUT bmbit2 +#define BMRXD0OUT bmbit3 +#define BMRXD1OUT bmbit4 +#define BMINT6 bmbit5 +#define BMT2EX bmbit6 +#define BMGPIFA8 bmbit7 + +SFRX(I2CS, 0xE678); +#define BMDONE bmbit0 +#define BMACK bmbit1 +#define BMBERR bmbit2 +#define BMID (bmbit4 | bmbit3) +#define BMLASTRD bmbit5 +#define BMSTOP bmbit6 +#define BMSTART bmbit7 + +SFRX(I2DAT, 0xE679); +SFRX(I2CTL, 0xE67A); +#define BMSTOPIE bmbit1 +#define BM400KHZ bmbit0 + +SFRX(XAUTODAT1, 0xE67B); +SFRX(XAUTODAT2, 0xE67C); +#define EXTAUTODAT1 XAUTODAT1 +#define EXTAUTODAT2 XAUTODAT2 + +/* USB Control */ +SFRX(USBCS, 0xE680); +#define SIGRSUME bmbit0 +#define RENUM bmbit1 +#define NOSYNSOF bmbit2 +#define DISCON bmbit3 +#define HSM bmbit7 + +SFRX(SUSPEND, 0xE681); +SFRX(WAKEUPCS, 0xE682); +#define BMWU2 bmbit7 +#define BMWU bmbit6 +#define BMWU2POL bmbit5 +#define BMWUPOL bmbit4 +#define BMDPEN bmbit2 +#define BMWU2EN bmbit1 +#define BMWUEN bmbit0 + +SFRX(TOGCTL, 0xE683); +#define BMTOGCTLEPMASK bmbit3 | bmbit2 | bmbit1 | bmbit0 +#define BMRESETTOGGLE bmbit5 +#define BMSETTOGGLE bmbit6 +#define BMQUERYTOGGLE bmbit7 + +SFRX(USBFRAMEH, 0xE684); +SFRX(USBFRAMEL, 0xE685); +SFRX(MICROFRAME, 0xE686); +SFRX(FNADDR, 0xE687); + +/* Endpoints */ +SFRX(EP0BCH, 0xE68A); +SFRX(EP0BCL, 0xE68B); +SFRX(EP1OUTBC, 0xE68D); +SFRX(EP1INBC, 0xE68F); +SFRX(EP2BCH, 0xE690); +SFRX(EP2BCL, 0xE691); +SFRX(EP4BCH, 0xE694); +SFRX(EP4BCL, 0xE695); +SFRX(EP6BCH, 0xE698); +SFRX(EP6BCL, 0xE699); +SFRX(EP8BCH, 0xE69C); +SFRX(EP8BCL, 0xE69D); +SFRX(EP0CS, 0xE6A0); +#define HSNAK bmbit7 + +SFRX(EP1INCS, 0xE6A2); +SFRX(EP1OUTCS, 0xE6A1); +#define EPSTALL bmbit0 +#define EPBSY bmbit1 + +SFRX(EP2CS, 0xE6A3); +SFRX(EP4CS, 0xE6A4); +SFRX(EP6CS, 0xE6A5); +SFRX(EP8CS, 0xE6A6); +#define BMEPEMPTY bmbit2 +#define BMEPFULL bmbit3 +#define BMNPAK (bmbit6 | bmbit5 | bmbit4) + +SFRX(EP2FIFOFLGS, 0xE6A7); +SFRX(EP4FIFOFLGS, 0xE6A8); +SFRX(EP6FIFOFLGS, 0xE6A9); +SFRX(EP8FIFOFLGS, 0xE6AA); +SFRX(EP2FIFOBCH, 0xE6AB); +SFRX(EP2FIFOBCL, 0xE6AC); +SFRX(EP4FIFOBCH, 0xE6AD); +SFRX(EP4FIFOBCL, 0xE6AE); +SFRX(EP6FIFOBCH, 0xE6AF); +SFRX(EP6FIFOBCL, 0xE6B0); +SFRX(EP8FIFOBCH, 0xE6B1); +SFRX(EP8FIFOBCL, 0xE6B2); +SFRX(SUDPTRH, 0xE6B3); +SFRX(SUDPTRL, 0xE6B4); + +SFRX(SUDPTRCTL, 0xE6B5); +#define BMSDPAUTO bmbit0 + +SFRX(SETUPDAT[8], 0xE6B8); + +/* GPIF */ +SFRX(GPIFWFSELECT, 0xE6C0); +SFRX(GPIFIDLECS, 0xE6C1); +SFRX(GPIFIDLECTL, 0xE6C2); +SFRX(GPIFCTLCFG, 0xE6C3); +SFRX(GPIFADRH, 0xE6C4); +SFRX(GPIFADRL, 0xE6C5); +SFRX(GPIFTCB3, 0xE6CE); +SFRX(GPIFTCB2, 0xE6CF); +SFRX(GPIFTCB1, 0xE6D0); +SFRX(GPIFTCB0, 0xE6D1); + +#define EP2GPIFTCH GPIFTCB1 /* these are here for backwards compatibility */ +#define EP2GPIFTCL GPIFTCB0 +#define EP4GPIFTCH GPIFTCB1 /* these are here for backwards compatibility */ +#define EP4GPIFTCL GPIFTCB0 +#define EP6GPIFTCH GPIFTCB1 /* these are here for backwards compatibility */ +#define EP6GPIFTCL GPIFTCB0 +#define EP8GPIFTCH GPIFTCB1 /* these are here for backwards compatibility */ +#define EP8GPIFTCL GPIFTCB0 + +SFRX(EP2GPIFFLGSEL, 0xE6D2); +SFRX(EP2GPIFPFSTOP, 0xE6D3); +SFRX(EP2GPIFTRIG, 0xE6D4); +SFRX(EP4GPIFFLGSEL, 0xE6DA); +SFRX(EP4GPIFPFSTOP, 0xE6DB); +SFRX(EP4GPIFTRIG, 0xE6DC); +SFRX(EP6GPIFFLGSEL, 0xE6E2); +SFRX(EP6GPIFPFSTOP, 0xE6E3); +SFRX(EP6GPIFTRIG, 0xE6E4); +SFRX(EP8GPIFFLGSEL, 0xE6EA); +SFRX(EP8GPIFPFSTOP, 0xE6EB); +SFRX(EP8GPIFTRIG, 0xE6EC); +SFRX(XGPIFSGLDATH, 0xE6F0); +SFRX(XGPIFSGLDATLX, 0xE6F1); +SFRX(XGPIFSGLDATLNOX, 0xE6F2); +SFRX(GPIFREADYCFG, 0xE6F3); +SFRX(GPIFREADYSTAT, 0xE6F4); +SFRX(GPIFABORT, 0xE6F5); + +// UDMA +SFRX(FLOWSTATE, 0xE6C6); +SFRX(FLOWLOGIC, 0xE6C7); +SFRX(FLOWEQ0CTL, 0xE6C8); +SFRX(FLOWEQ1CTL, 0xE6C9); +SFRX(FLOWHOLDOFF, 0xE6CA); +SFRX(FLOWSTB, 0xE6CB); +SFRX(FLOWSTBEDGE, 0xE6CC); +SFRX(FLOWSTBHPERIOD, 0xE6CD); +SFRX(GPIFHOLDAMOUNT, 0xE60C); +SFRX(UDMACRCH, 0xE67D); +SFRX(UDMACRCL, 0xE67E); +SFRX(UDMACRCQUAL, 0xE67F); + +/* Debug/Test + * The following registers are for Cypress's internal testing purposes only. + * These registers are not documented in the datasheet or the Technical Reference + * Manual as they were not designed for end user application usage + */ +SFRX(DBUG, 0xE6F8); +SFRX(TESTCFG, 0xE6F9); +SFRX(USBTEST, 0xE6FA); +SFRX(CT1, 0xE6FB); +SFRX(CT2, 0xE6FC); +SFRX(CT3, 0xE6FD); +SFRX(CT4, 0xE6FE); + +/* Endpoint Buffers */ +SFRX(EP0BUF[64], 0xE740); +SFRX(EP1INBUF[64], 0xE7C0); +SFRX(EP1OUTBUF[64], 0xE780); +SFRX(EP2FIFOBUF[512], 0xF000); +SFRX(EP4FIFOBUF[512], 0xF400); +SFRX(EP6FIFOBUF[512], 0xF800); +SFRX(EP8FIFOBUF[512], 0xFC00); + +/* Error Correction Code (ECC) Registers (FX2LP/FX1 only) */ +SFRX(ECCCFG, 0xE628); +SFRX(ECCRESET, 0xE629); +SFRX(ECC1B0, 0xE62A); +SFRX(ECC1B1, 0xE62B); +SFRX(ECC1B2, 0xE62C); +SFRX(ECC2B0, 0xE62D); +SFRX(ECC2B1, 0xE62E); +SFRX(ECC2B2, 0xE62F); + +/* Feature Registers (FX2LP/FX1 only) */ +SFRX(GPCR2, 0xE50D); +#define BMFULLSPEEDONLY bmbit4 + +#endif diff --git a/contrib/firmware/angie/c/include/serial.h b/contrib/firmware/angie/c/include/serial.h new file mode 100644 index 0000000000..548c005603 --- /dev/null +++ b/contrib/firmware/angie/c/include/serial.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +/** + * This code was taken from the fx2lib project from this link: + * https://github.com/djmuhlestein/fx2lib + * + * Copyright (C) 2009 Ubixum, Inc. + **/ + +/** \file serial.h + * defines functions to print to a serial console with SIO0 + **/ + +#include "fx2macros.h" +#include +/** + * This function inits sio0 to use T2CON (timer 2) + * See TRM 14.3.4.1 (Table 14-16) + * Certain baud rates have too high an error rate to work. All baud rates are .16% + * except: + * + * 12MHZ 24MHZ + * \li 57600 -6.99% + * \li 38400 -2.34% -2.34% + * \li 19200 -2.34% + * + * Possible Baud rates: + * \li 2400 + * \li 4800 + * \li 9600 + * \li 19200 + * \li 28800 + * \li 38400 + * \li 57600 + * + * Any of these rates should work except 57600 at 12mhz. -2.34% is pushing + * most hardware specs for working. All rates at 48mhz work at .16% + **/ + +void sio0_init(uint32_t baud_rate) __critical; /* baud_rate max should be 57600 since int=2 bytes */ + +/** + * putchar('\\n') or putchar('\\r') both transmit \\r\\n + * Just use one or the other. (This makes terminal echo easy) + **/ +int putchar(char c); +int getchar(void); diff --git a/contrib/firmware/angie/c/include/usb.h b/contrib/firmware/angie/c/include/usb.h new file mode 100644 index 0000000000..ad8be787e4 --- /dev/null +++ b/contrib/firmware/angie/c/include/usb.h @@ -0,0 +1,289 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/**************************************************************************** + File : usb.h * + Contents : usb communication handling header file for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#ifndef __USB_H +#define __USB_H + +#include "reg_ezusb.h" +#include +#include + +/* High and Low byte of a word (uint16_t) */ +#define HI8(word) (uint8_t)(((uint16_t)(word) >> 8) & 0xff) +#define LO8(word) (uint8_t)((uint16_t)(word) & 0xff) + +/* Convenience functions */ +#define STALL_EP0() (EP0CS |= EPSTALL) +#define CLEAR_IRQ() (USBINT = 0) + +/*********** USB descriptors. See USB 2.0 Spec **********/ + +/* USB Descriptor Types. See USB 2.0 Spec */ +#define DESCRIPTOR_TYPE_DEVICE 0x01 +#define DESCRIPTOR_TYPE_CONFIGURATION 0x02 +#define DESCRIPTOR_TYPE_STRING 0x03 +#define DESCRIPTOR_TYPE_INTERFACE 0x04 +#define DESCRIPTOR_TYPE_ENDPOINT 0x05 + +#define STR_DESCR(len, ...) { (len) * 2 + 2, DESCRIPTOR_TYPE_STRING, { __VA_ARGS__ } } + +/** USB Device Descriptor. See USB 2.0 Spec */ +struct usb_device_descriptor { + uint8_t blength; /**< Size of this descriptor in bytes. */ + uint8_t bdescriptortype; /**< DEVICE Descriptor Type. */ + uint16_t bcdusb; /**< USB specification release number (BCD). */ + uint8_t bdeviceclass; /**< Class code. */ + uint8_t bdevicesubclass; /**< Subclass code. */ + uint8_t bdeviceprotocol; /**< Protocol code. */ + uint8_t bmaxpacketsize0; /**< Maximum packet size for EP0 (8, 16, 32, 64). */ + uint16_t idvendor; /**< USB Vendor ID. */ + uint16_t idproduct; /**< USB Product ID. */ + uint16_t bcddevice; /**< Device Release Number (BCD). */ + uint8_t imanufacturer; /**< Index of manufacturer string descriptor. */ + uint8_t iproduct; /**< Index of product string descriptor. */ + uint8_t iserialnumber; /**< Index of string descriptor containing serial #. */ + uint8_t bnumconfigurations; /**< Number of possible configurations. */ +}; + +/** USB Configuration Descriptor. See USB 2.0 Spec */ +struct usb_config_descriptor { + uint8_t blength; /**< Size of this descriptor in bytes. */ + uint8_t bdescriptortype; /**< CONFIGURATION descriptor type. */ + uint16_t wtotallength; /**< Combined total length of all descriptors. */ + uint8_t bnuminterfaces; /**< Number of interfaces in this configuration. */ + uint8_t bconfigurationvalue; /**< Value used to select this configuration. */ + uint8_t iconfiguration; /**< Index of configuration string descriptor. */ + uint8_t bmattributes; /**< Configuration characteristics. */ + uint8_t maxpower; /**< Maximum power consumption in 2 mA units. */ +}; + +/** USB Interface association Descriptor. See USB 2.0 Spec */ +struct usb_interface_association_descriptor { + uint8_t blength; + uint8_t bdescriptortype; + uint8_t bfirstinterface; + uint8_t binterfacecount; + uint8_t bfunctionclass; + uint8_t bfunctionsubclass; + uint8_t bfunctionprotocol; + uint8_t ifunction; +}; + +/** USB Interface Descriptor. See USB 2.0 Spec */ +struct usb_interface_descriptor { + uint8_t blength; /**< Size of this descriptor in bytes. */ + uint8_t bdescriptortype; /**< INTERFACE descriptor type. */ + uint8_t binterfacenumber; /**< Interface number. */ + uint8_t balternatesetting; /**< Value used to select alternate setting. */ + uint8_t bnumendpoints; /**< Number of endpoints used by this interface. */ + uint8_t binterfaceclass; /**< Class code. */ + uint8_t binterfacesubclass; /**< Subclass code. */ + uint8_t binterfaceprotocol; /**< Protocol code. */ + uint8_t iinterface; /**< Index of interface string descriptor. */ +}; + +/** USB Endpoint Descriptor. See USB 2.0 Spec */ +struct usb_endpoint_descriptor { + uint8_t blength; /**< Size of this descriptor in bytes. */ + uint8_t bdescriptortype; /**< ENDPOINT descriptor type. */ + uint8_t bendpointaddress; /**< Endpoint Address: IN/OUT + EP number. */ + uint8_t bmattributes; /**< Endpoint Attributes: BULK/INTR/ISO/CTRL. */ + uint16_t wmaxpacketsize; /**< Maximum packet size for this endpoint. */ + uint8_t binterval; /**< Polling interval (in ms) for this endpoint. */ +}; + +/** USB Language Descriptor. See USB 2.0 Spec */ +struct usb_language_descriptor { + uint8_t blength; /**< Size of this descriptor in bytes. */ + uint8_t bdescriptortype; /**< STRING descriptor type. */ + uint16_t wlangid[]; /**< LANGID codes. */ +}; + +/** USB String Descriptor. See USB 2.0 Spec */ +struct usb_string_descriptor { + uint8_t blength; /**< Size of this descriptor in bytes. */ + uint8_t bdescriptortype; /**< STRING descriptor type. */ + uint16_t bstring[]; /**< UNICODE encoded string. */ +}; + +/********************** USB Control Endpoint 0 related *********************/ + +/** USB Control Setup Data. See USB 2.0 Spec */ +struct setup_data { + uint8_t bmrequesttype; /**< Characteristics of a request. */ + uint8_t brequest; /**< Specific request. */ + uint16_t wvalue; /**< Field that varies according to request. */ + uint16_t windex; /**< Field that varies according to request. */ + uint16_t wlength; /**< Number of bytes to transfer in data stage. */ +}; + +/* External declarations for variables that need to be accessed outside of + * the USB module */ +extern volatile bool ep1_out; +extern volatile bool ep1_in; +extern volatile bool ep6_out; + +extern volatile __xdata __at 0xE6B8 struct setup_data setup_data; + +/* + * USB Request Types (bmRequestType): See USB 2.0 Spec + * + * Bit 7: Data transfer direction + * 0 = Host-to-device + * 1 = Device-to-host + * Bit 6...5: Type + * 0 = Standard + * 1 = Class + * 2 = Vendor + * 3 = Reserved + * Bit 4...0: Recipient + * 0 = Device + * 1 = Interface + * 2 = Endpoint + * 3 = Other + * 4...31 = Reserved + */ + +#define USB_DIR_OUT 0x00 +#define USB_DIR_IN 0x80 + +#define USB_REQ_TYPE_STANDARD (0x00 << 5) +#define USB_REQ_TYPE_CLASS (0x01 << 5) +#define USB_REQ_TYPE_VENDOR (0x02 << 5) +#define USB_REQ_TYPE_RESERVED (0x03 << 5) + +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 + +/* Clear Interface Request */ +#define CF_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) +#define CF_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) +#define CF_ENDPOINT (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) + +/* Get Configuration Request */ +#define GC_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) + +/* Get Descriptor Request */ +#define GD_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) + +/* Get Interface Request */ +#define GI_INTERFACE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) + +/* Get Status Request: See USB 1.1 spec, page 190 */ +#define GS_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) +#define GS_INTERFACE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) +#define GS_ENDPOINT (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) + +/* Set Address Request is handled by EZ-USB core */ + +/* Set Configuration Request */ +#define SC_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) + +/* Set Descriptor Request */ +#define SD_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) + +/* Set Feature Request */ +#define SF_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) +#define SF_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) +#define SF_ENDPOINT (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) + +/* Set Interface Request */ +#define SI_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) + +/* Synch Frame Request */ +#define SY_ENDPOINT (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) + +/* USB Requests (bRequest): See USB 2.0 Spec */ +#define GET_STATUS 0 +#define CLEAR_FEATURE 1 +/* Value '2' is reserved for future use */ +#define SET_FEATURE 3 +/* Value '4' is reserved for future use */ +#define SET_ADDRESS 5 +#define GET_DESCRIPTOR 6 +#define SET_DESCRIPTOR 7 +#define GET_CONFIGURATION 8 +#define SET_CONFIGURATION 9 +#define GET_INTERFACE 10 +#define SET_INTERFACE 11 +#define SYNCH_FRAME 12 + +/* Standard Feature Selectors: See USB 2.0 Spec */ +#define DEVICE_REMOTE_WAKEUP 1 +#define ENDPOINT_HALT 0 + +/************************** EZ-USB specific stuff **************************/ +/** USB Interrupts. See EZ-USB FX2-TRM, for details */ +enum usb_isr { + SUDAV_ISR = 13, + SOF_ISR, + SUTOK_ISR, + SUSPEND_ISR, + USBRESET_ISR, + HIGHSPEED_ISR, + EP0ACK_ISR, + STUB_ISR, + EP0IN_ISR, + EP0OUT_ISR, + EP1IN_ISR, + EP1OUT_ISR, + EP2_ISR, + EP4_ISR, + EP6_ISR, + EP8_ISR, + IBN_ISR, + EP0PINGNAK_ISR, + EP1PINGNAK_ISR, + EP2PINGNAK_ISR, + EP4PINGNAK_ISR, + EP6PINGNAK_ISR, + EP8PINGNAK_ISR, + ERRORLIMIT_ISR, + EP2PIDERROR_ISR, + EP4PIDERROR_ISR, + EP6PIDERROR_ISR, + EP8PIDERROR_ISR, + EP2PFLAG_ISR, + EP4PFLAG_ISR, + EP6PFLAG_ISR, + EP8PFLAG_ISR, + EP2EFLAG_ISR, + EP4EFLAG_ISR, + EP6EFLAG_ISR, + EP8EFLAG_ISR, + EP2FFLAG_ISR, + EP4FFLAG_ISR, + EP6FFLAG_ISR, + EP8FFLAG_ISR, + GPIFCOMPLETE_ISR, + GPIFWAVEFORM_ISR +}; + +/*************************** Function Prototypes ***************************/ +__xdata uint8_t *usb_get_endpoint_cs_reg(uint8_t ep); +void usb_reset_data_toggle(uint8_t ep); +bool usb_handle_get_status(void); +bool usb_handle_clear_feature(void); +bool usb_handle_set_feature(void); +bool usb_handle_get_descriptor(void); +void usb_handle_set_interface(void); +void usb_handle_setup_data(void); +void usb_handle_i2c_in(void); +void usb_handle_i2c_out(void); + +void i2c_recieve(void); +void ep_init(void); +void interrupt_init(void); +void io_init(void); + +#endif diff --git a/contrib/firmware/angie/c/src/USBJmpTb.a51 b/contrib/firmware/angie/c/src/USBJmpTb.a51 new file mode 100644 index 0000000000..13b5f7218b --- /dev/null +++ b/contrib/firmware/angie/c/src/USBJmpTb.a51 @@ -0,0 +1,125 @@ +; SPDX-License-Identifier: GPL-2.0-or-later +;**************************************************************************** +; File : USBJmpTb.a51 * +; Contents : Interruptions vector configuration. * +; Based on openULINK project code by: Martin Schmoelzer. * +; Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * +; * +; * +;**************************************************************************** +.module JUMPTABLE + +.globl USB_AutoVector +.globl USB_Jump_Table + +.globl _sudav_isr, _sof_isr, _sutok_isr, _suspend_isr, _usbreset_isr, _highspeed_isr, _ep0ack_isr, _stub_isr, _ep0in_isr, _ep0out_isr, _ep1in_isr, _ep1out_isr, _ep2_isr, _ep4_isr, _ep6_isr, _ep8_isr, _ibn_isr +.globl _ep0pingnak_isr, _ep1pingnak_isr, _ep2pingnak_isr, _ep4pingnak_isr, _ep6pingnak_isr, _ep8pingnak_isr, _errorlimit_isr, _stub_isr, _stub_isr, _stub_isr, _ep2piderror_isr, _ep4piderror_isr, _ep6piderror_isr, _ep8piderror_isr +.globl _ep2pflag_isr, _ep4pflag_isr, _ep6pflag_isr, _ep8pflag_isr, _ep2eflag_isr, _ep4eflag_isr, _ep6eflag_isr, _ep8eflag_isr, _ep2fflag_isr, _ep4fflag_isr, _ep6fflag_isr, _ep8fflag_isr, _gpifcomplete_isr, _gpifwaveform_isr + +;--------------------------------------------------------------------------; +; Interrupt Vectors ; +;--------------------------------------------------------------------------; +.area USB_JV (ABS,OVR) ; Absolute, Overlay +.org 0x43 ; USB interrupt (INT2) jumps here +USB_AutoVector = #. + 2 + ljmp USB_Jump_Table ; Autovector will replace byte 45 + +;--------------------------------------------------------------------------; +; USB Jump Table ; +;--------------------------------------------------------------------------; +.area USB_JT (ABS) ; Absolute placement +.org 0x0200 ; Place jump table at 0x0200 + +USB_Jump_Table: ; autovector jump table + ljmp _sudav_isr ; (00) Setup Data Available + .db 0 + ljmp _sof_isr ; (04) Start of Frame + .db 0 + ljmp _sutok_isr ; (08) Setup Data Loading + .db 0 + ljmp _suspend_isr ; (0C) Global Suspend + .db 0 + ljmp _usbreset_isr ; (10) USB Reset + .db 0 + ljmp _highspeed_isr ; (14) Entered High Speed + .db 0 + ljmp _ep0ack_isr ; (18) EP0ACK + .db 0 + ljmp _stub_isr ; (1C) Reserved + .db 0 + ljmp _ep0in_isr ; (20) EP0 In + .db 0 + ljmp _ep0out_isr ; (24) EP0 Out + .db 0 + ljmp _ep1in_isr ; (28) EP1 In + .db 0 + ljmp _ep1out_isr ; (2C) EP1 Out + .db 0 + ljmp _ep2_isr ; (30) EP2 In/Out + .db 0 + ljmp _ep4_isr ; (34) EP4 In/Out + .db 0 + ljmp _ep6_isr ; (38) EP6 In/Out + .db 0 + ljmp _ep8_isr ; (3C) EP8 In/Out + .db 0 + ljmp _ibn_isr ; (40) IBN + .db 0 + ljmp _stub_isr ; (44) Reserved + .db 0 + ljmp _ep0pingnak_isr ; (48) EP0 PING NAK + .db 0 + ljmp _ep1pingnak_isr ; (4C) EP1 PING NAK + .db 0 + ljmp _ep2pingnak_isr ; (50) EP2 PING NAK + .db 0 + ljmp _ep4pingnak_isr ; (54) EP4 PING NAK + .db 0 + ljmp _ep6pingnak_isr ; (58) EP6 PING NAK + .db 0 + ljmp _ep8pingnak_isr ; (5C) EP8 PING NAK + .db 0 + ljmp _errorlimit_isr ; (60) Error Limit + .db 0 + ljmp _stub_isr ; (64) Reserved + .db 0 + ljmp _stub_isr ; (68) Reserved + .db 0 + ljmp _stub_isr ; (6C) Reserved + .db 0 + ljmp _ep2piderror_isr ; (70) EP2 ISO Pid Sequence Error + .db 0 + ljmp _ep4piderror_isr ; (74) EP4 ISO Pid Sequence Error + .db 0 + ljmp _ep6piderror_isr ; (78) EP6 ISO Pid Sequence Error + .db 0 + ljmp _ep8piderror_isr ; (7C) EP8 ISO Pid Sequence Error + .db 0 + ljmp _ep2pflag_isr ; (80) EP2 Programmable Flag + .db 0 + ljmp _ep4pflag_isr ; (84) EP4 Programmable Flag + .db 0 + ljmp _ep6pflag_isr ; (88) EP6 Programmable Flag + .db 0 + ljmp _ep8pflag_isr ; (8C) EP8 Programmable Flag + .db 0 + ljmp _ep2eflag_isr ; (90) EP2 Empty Flag + .db 0 + ljmp _ep4eflag_isr ; (94) EP4 Empty Flag + .db 0 + ljmp _ep6eflag_isr ; (98) EP6 Empty Flag + .db 0 + ljmp _ep8eflag_isr ; (9C) EP8 Empty Flag + .db 0 + ljmp _ep2fflag_isr ; (A0) EP2 Full Flag + .db 0 + ljmp _ep4fflag_isr ; (A4) EP4 Full Flag + .db 0 + ljmp _ep6fflag_isr ; (A8) EP6 Full Flag + .db 0 + ljmp _ep8fflag_isr ; (AC) EP8 Full Flag + .db 0 + ljmp _gpifcomplete_isr ; (B0) GPIF Operation Complete + .db 0 + ljmp _gpifwaveform_isr ; (B4) GPIF Waveform + .db 0 diff --git a/contrib/firmware/angie/c/src/delay.c b/contrib/firmware/angie/c/src/delay.c new file mode 100644 index 0000000000..471e160dd4 --- /dev/null +++ b/contrib/firmware/angie/c/src/delay.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/**************************************************************************** + File : delay.c * + Contents : Delays handling fucntions code for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#include "delay.h" +#include + +void syncdelay(uint8_t count) +{ + for (uint8_t i = 0; i < count; i++) + NOP(); +} + +void delay_5us(void) +{ + NOP(); +} + +void delay_1ms(void) +{ + uint16_t i; + + for (i = 0; i < 598; i++) + ; +} + +void delay_us(uint16_t delay) +{ + uint16_t i; + uint16_t maxcount = (delay / 5); + + for (i = 0; i < maxcount; i++) + delay_5us(); +} + +void delay_ms(uint16_t delay) +{ + uint16_t i; + + for (i = 0; i < delay; i++) + delay_1ms(); +} diff --git a/contrib/firmware/angie/c/src/gpif.c b/contrib/firmware/angie/c/src/gpif.c new file mode 100644 index 0000000000..f4028be400 --- /dev/null +++ b/contrib/firmware/angie/c/src/gpif.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + This program configures the General Programmable Interface (GPIF) for FX2. + Please do not modify sections of text which are marked as "DO NOT EDIT ...". +*/ + +/* GPIF Program Code */ + +#include "reg_ezusb.h" +#include "delay.h" + +/****************************** GPIF PROGRAM CODE ********************************/ +/* DO NOT EDIT ... */ +const char wavedata[128] = { +// Wave 0 +/* LenBr */ 0x01, 0x3F, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x02, 0x07, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, +/* Output*/ 0x04, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, +/* LFun */ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +// Wave 1 +/* LenBr */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Output*/ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +/* LFun */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +// Wave 2 +/* LenBr */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Output*/ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +/* LFun */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +// Wave 3 +/* LenBr */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Output*/ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +/* LFun */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +}; +/* END DO NOT EDIT */ + +/* DO NOT EDIT ... */ +const char flowstates[36] = { +/* Wave 0 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Wave 1 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Wave 2 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Wave 3 flowstates */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +/* END DO NOT EDIT */ + +/* DO NOT EDIT ... */ +const char initdata[7] = { +/* Regs */ 0xE0, 0x00, 0x00, 0x07, 0xEE, 0xF2, 0x00 +}; +/* END DO NOT EDIT */ + +void gpif_init(void) +{ + uint8_t i; + + IFCONFIG = 0xEE; + + GPIFABORT = 0xFF; /* abort any waveforms pending */ + GPIFREADYCFG = initdata[0]; + GPIFCTLCFG = initdata[1]; + GPIFIDLECS = initdata[2]; + GPIFIDLECTL = initdata[3]; + GPIFWFSELECT = initdata[5]; + GPIFREADYSTAT = initdata[6]; + + /* use dual autopointer feature... */ + AUTOPTRSETUP = 0x07; + + /* source */ + AUTOPTRH1 = (uint8_t)(((uint16_t)(&wavedata) >> 8) & 0xff); + AUTOPTRL1 = (uint8_t)((uint16_t)(&wavedata) & 0xff); + + /* destination */ + AUTOPTRH2 = 0xE4; + AUTOPTRL2 = 0x00; + + /* transfer */ + for (i = 0x00; i < 128; i++) + EXTAUTODAT2 = EXTAUTODAT1; + + /* GPIF address pins update when GPIFADRH/L written */ + syncdelay(3); + GPIFADRH = 0x00; /* bits[7:1] always 0 */ + syncdelay(3); + GPIFADRL = 0x00; /* point to PERIPHERAL address 0x0000 */ + + /* Configure GPIF flowstates registers for Wave 0 of wavedata */ + FLOWSTATE = flowstates[0]; + FLOWLOGIC = flowstates[1]; + FLOWEQ0CTL = flowstates[2]; + FLOWEQ1CTL = flowstates[3]; + FLOWHOLDOFF = flowstates[4]; + FLOWSTB = flowstates[5]; + FLOWSTBEDGE = flowstates[6]; + FLOWSTBHPERIOD = flowstates[7]; +} diff --git a/contrib/firmware/angie/c/src/i2c.c b/contrib/firmware/angie/c/src/i2c.c new file mode 100644 index 0000000000..10a463bf7d --- /dev/null +++ b/contrib/firmware/angie/c/src/i2c.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/**************************************************************************** + File : i2c.cpp * + Contents : i2c bit-bang library * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#include "i2c.h" +#include "io.h" +#include "delay.h" +#include "reg_ezusb.h" + +void start_cd(void) +{ + PIN_SCL_DIR = 0; + PIN_SDA_DIR = 0; + delay_us(10); + PIN_SDA = 0; //SDA = 1; + delay_us(1); + PIN_SCL = 0; //SCL = 1; + delay_us(1); +} + +void repeated_start(void) +{ + PIN_SDA = 1; + delay_us(1); + PIN_SCL = 1; + delay_us(1); + PIN_SDA = 0; + delay_us(1); + PIN_SCL = 0; + delay_us(1); +} + +void stop_cd(void) +{ + PIN_SDA = 0; + delay_us(1); + PIN_SCL = 1; + delay_us(1); + PIN_SDA = 1; + delay_us(1); + PIN_SDA_DIR = 1; + delay_us(1); + PIN_SCL_DIR = 1; + delay_us(1); +} + +void clock_cd(void) +{ + PIN_SCL = 1; + delay_us(1); + PIN_SCL = 0; + delay_us(1); +} + +void send_ack(void) +{ + PIN_SDA = 0; + delay_us(1); + PIN_SCL = 1; + delay_us(1); + PIN_SCL = 0; + delay_us(1); +} + +void send_nack(void) +{ + PIN_SDA = 1; + delay_us(1); + PIN_SCL = 1; + delay_us(1); + PIN_SCL = 0; + delay_us(1); +} + +bool get_ack(void) +{ + PIN_SDA_DIR = 1; + delay_us(1); + OED = 0xFE; + PIN_SCL = 1; + delay_us(1); + bool ack = PIN_SDA; + PIN_SCL = 0; + delay_us(1); + OED = 0xFF; + PIN_SDA_DIR = 0; + delay_us(1); + return ack; +} + +/* here address(8 bits) = adr (7 bits) + type (1 bit) */ +uint8_t get_address(uint8_t adr, uint8_t rdwr) +{ + adr &= 0x7F; + adr = adr << 1; + adr |= (rdwr & 0x01); + return adr; +} + +/* here send bit after bit and clocking scl with each bit */ +void send_byte(uint8_t input) +{ + for (uint8_t i = 0; i < 8; i++) { + if ((input & 0x80)) { + PIN_SDA = 1; + delay_us(1); + clock_cd(); + } else { + PIN_SDA = 0; + delay_us(1); + clock_cd(); + } + input = input << 1; + } +} + +/* here receive bit after bit and clocking scl with each bit */ + +uint8_t receive_byte(void) +{ + PIN_SDA_DIR = 1; //FX2 <-- FPGA + OED = 0xFE; + uint8_t input = 0x00; + for (uint8_t i = 0; i < 8; i++) { + PIN_SCL = 1; + delay_us(1); + input = input << 1; + if (PIN_SDA == 1) + input |= 0x01; + else + input |= 0X00; + + PIN_SCL = 0; + delay_us(1); + } + OED = 0xFF; + PIN_SDA_DIR = 0; + return input; +} diff --git a/contrib/firmware/angie/c/src/jtag.c b/contrib/firmware/angie/c/src/jtag.c new file mode 100644 index 0000000000..9a44cd0bfc --- /dev/null +++ b/contrib/firmware/angie/c/src/jtag.c @@ -0,0 +1,674 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/**************************************************************************** + File : jtag.c * + Contents : Jtag handling functions code for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#include "jtag.h" +#include "io.h" +#include "msgtypes.h" +#include "reg_ezusb.h" +#include +#include +#include + +/** Delay value for SCAN_IN operations with less than maximum TCK frequency */ +uint8_t delay_scan_in; + +/** Delay value for SCAN_OUT operations with less than maximum TCK frequency */ +uint8_t delay_scan_out; + +/** Delay value for SCAN_IO operations with less than maximum TCK frequency */ +uint8_t delay_scan_io; + +/** Delay value for CLOCK_TCK operations with less than maximum frequency */ +uint8_t delay_tck; + +/** Delay value for CLOCK_TMS operations with less than maximum frequency */ +uint8_t delay_tms; + +/** + * Perform JTAG SCAN-IN operation at maximum TCK frequency. + * + * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and + * stored in the EP2 IN buffer. + * + * Maximum achievable TCK frequency is 182 kHz for ANGIE clocked at 24 MHz. + * + * @param out_offset offset in EP1OUTBUF where payload data starts + * @param in_offset + */ +void jtag_scan_in(uint8_t out_offset, uint8_t in_offset) +{ + uint8_t scan_size_bytes, bits_last_byte; + uint8_t tms_count_start, tms_count_end; + uint8_t tms_sequence_start, tms_sequence_end; + uint8_t tdo_data, i, j; + + uint8_t outb_buffer; + + /* Get parameters from EP1OUTBUF */ + scan_size_bytes = EP1OUTBUF[out_offset]; + bits_last_byte = EP1OUTBUF[out_offset + 1]; + tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; + tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; + tms_sequence_start = EP1OUTBUF[out_offset + 3]; + tms_sequence_end = EP1OUTBUF[out_offset + 4]; + + if (tms_count_start > 0) + jtag_clock_tms(tms_count_start, tms_sequence_start); + + outb_buffer = IOB & ~(bmbit1 | bmbit2 | bmbit3); + + /* Shift all bytes except the last byte */ + for (i = 0; i < scan_size_bytes - 1; i++) { + tdo_data = 0; + + for (j = 0; j < 8; j++) { + IOB = outb_buffer; /* TCK changes here */ + tdo_data = tdo_data >> 1; + IOB = (outb_buffer | bmbit2); + + if (PIN_TDO) + tdo_data |= 0x80; + } + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + } + tdo_data = 0; + + /* Shift the last byte */ + for (j = 0; j < bits_last_byte; j++) { + /* Assert TMS signal if requested and this is the last bit */ + if (j == (bits_last_byte - 1) && tms_count_end > 0) { + outb_buffer |= bmbit1; + tms_count_end--; + tms_sequence_end = tms_sequence_end >> 1; + } + + IOB = outb_buffer; /* TCK changes here */ + tdo_data = tdo_data >> 1; + IOB = (outb_buffer | bmbit2); + + if (PIN_TDO) + tdo_data |= 0x80; + } + tdo_data = tdo_data >> (8 - bits_last_byte); + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + + /* Move to correct end state */ + if (tms_count_end > 0) + jtag_clock_tms(tms_count_end, tms_sequence_end); +} + + +/** + * Perform JTAG SCAN-IN operation at variable TCK frequency. + * + * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and + * stored in the EP2 IN buffer. + * + * Maximum achievable TCK frequency is 113 kHz for ANGIE clocked at 24 MHz. + * + * @param out_offset offset in EP1OUTBUF where payload data starts + * @param in_offset + */ +void jtag_slow_scan_in(uint8_t out_offset, uint8_t in_offset) +{ + uint8_t scan_size_bytes, bits_last_byte; + uint8_t tms_count_start, tms_count_end; + uint8_t tms_sequence_start, tms_sequence_end; + uint8_t tdo_data, i, j, k; + uint8_t outb_buffer; + + /* Get parameters from EP1OUTBUF */ + scan_size_bytes = EP1OUTBUF[out_offset]; + bits_last_byte = EP1OUTBUF[out_offset + 1]; + tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; + tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; + tms_sequence_start = EP1OUTBUF[out_offset + 3]; + tms_sequence_end = EP1OUTBUF[out_offset + 4]; + + if (tms_count_start > 0) + jtag_slow_clock_tms(tms_count_start, tms_sequence_start); + + outb_buffer = IOB & ~(bmbit3 | bmbit2 | bmbit1); + + /* Shift all bytes except the last byte */ + for (i = 0; i < scan_size_bytes - 1; i++) { + tdo_data = 0; + + for (j = 0; j < 8; j++) { + IOB = outb_buffer; /* TCK changes here */ + for (k = 0; k < delay_scan_in; k++) + ; + tdo_data = tdo_data >> 1; + + IOB = (outb_buffer | bmbit2); + for (k = 0; k < delay_scan_in; k++) + ; + + if (PIN_TDO) + tdo_data |= 0x80; + } + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + } + + tdo_data = 0; + + /* Shift the last byte */ + for (j = 0; j < bits_last_byte; j++) { + /* Assert TMS signal if requested and this is the last bit */ + if (j == (bits_last_byte - 1) && tms_count_end > 0) { + outb_buffer |= bmbit1; + tms_count_end--; + tms_sequence_end = tms_sequence_end >> 1; + } + + IOB = outb_buffer; /* TCK changes here */ + for (k = 0; k < delay_scan_in; k++) + ; + tdo_data = tdo_data >> 1; + + IOB = (outb_buffer | bmbit2); + for (k = 0; k < delay_scan_in; k++) + ; + + if (PIN_TDO) + tdo_data |= 0x80; + } + tdo_data = tdo_data >> (8 - bits_last_byte); + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + + /* Move to correct end state */ + if (tms_count_end > 0) + jtag_slow_clock_tms(tms_count_end, tms_sequence_end); +} + + +/** + * Perform JTAG SCAN-OUT operation at maximum TCK frequency. + * + * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO + * data is not sampled. + * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. + * + * Maximum achievable TCK frequency is 142 kHz for ANGIE clocked at 24 MHz. + * + * @param out_offset offset in EP1OUTBUF where payload data starts + */ +void jtag_scan_out(uint8_t out_offset) +{ + uint8_t scan_size_bytes, bits_last_byte; + uint8_t tms_count_start, tms_count_end; + uint8_t tms_sequence_start, tms_sequence_end; + uint8_t tdi_data, i, j; + uint8_t outb_buffer; + + /* Get parameters from EP1OUTBUF */ + scan_size_bytes = EP1OUTBUF[out_offset]; + bits_last_byte = EP1OUTBUF[out_offset + 1]; + tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; + tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; + tms_sequence_start = EP1OUTBUF[out_offset + 3]; + tms_sequence_end = EP1OUTBUF[out_offset + 4]; + + if (tms_count_start > 0) + jtag_clock_tms(tms_count_start, tms_sequence_start); + outb_buffer = IOB & ~(bmbit2 | bmbit1); + + /* Shift all bytes except the last byte */ + for (i = 0; i < scan_size_bytes - 1; i++) { + tdi_data = EP1OUTBUF[i + out_offset + 5]; + + for (j = 0; j < 8; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + + IOB = outb_buffer; /* TDI and TCK change here */ + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + } + } + tdi_data = EP1OUTBUF[i + out_offset + 5]; + + /* Shift the last byte */ + for (j = 0; j < bits_last_byte; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + + /* Assert TMS signal if requested and this is the last bit */ + if (j == (bits_last_byte - 1) && tms_count_end > 0) { + outb_buffer |= bmbit1; + tms_count_end--; + tms_sequence_end = tms_sequence_end >> 1; + } + IOB = outb_buffer; /* TDI and TCK change here */ + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + } + + /* Move to correct end state */ + if (tms_count_end > 0) + jtag_clock_tms(tms_count_end, tms_sequence_end); +} + +/** + * Perform JTAG SCAN-OUT operation at maximum TCK frequency. + * + * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO + * data is not sampled. + * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. + * + * Maximum achievable TCK frequency is 97 kHz for ANGIE clocked at 24 MHz. + * + * @param out_offset offset in EP1OUTBUF where payload data starts + */ +void jtag_slow_scan_out(uint8_t out_offset) +{ + uint8_t scan_size_bytes, bits_last_byte; + uint8_t tms_count_start, tms_count_end; + uint8_t tms_sequence_start, tms_sequence_end; + uint8_t tdi_data, i, j, k; + uint8_t outb_buffer; + + /* Get parameters from EP1OUTBUF */ + scan_size_bytes = EP1OUTBUF[out_offset]; + bits_last_byte = EP1OUTBUF[out_offset + 1]; + tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; + tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; + tms_sequence_start = EP1OUTBUF[out_offset + 3]; + tms_sequence_end = EP1OUTBUF[out_offset + 4]; + + if (tms_count_start > 0) + jtag_slow_clock_tms(tms_count_start, tms_sequence_start); + outb_buffer = IOB & ~(bmbit2 | bmbit1); + + /* Shift all bytes except the last byte */ + for (i = 0; i < scan_size_bytes - 1; i++) { + tdi_data = EP1OUTBUF[i + out_offset + 5]; + + for (j = 0; j < 8; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + IOB = outb_buffer; /* TDI and TCK change here */ + for (k = 0; k < delay_scan_out; k++) + ; + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + for (k = 0; k < delay_scan_out; k++) + ; + } + } + tdi_data = EP1OUTBUF[i + out_offset + 5]; + + /* Shift the last byte */ + for (j = 0; j < bits_last_byte; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + + /* Assert TMS signal if requested and this is the last bit */ + if (j == (bits_last_byte - 1) && tms_count_end > 0) { + outb_buffer |= bmbit1; + tms_count_end--; + tms_sequence_end = tms_sequence_end >> 1; + } + IOB = outb_buffer; /* TDI and TCK change here */ + for (k = 0; k < delay_scan_out; k++) + ; + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + for (k = 0; k < delay_scan_out; k++) + ; + } + + /* Move to correct end state */ + if (tms_count_end > 0) + jtag_slow_clock_tms(tms_count_end, tms_sequence_end); +} + + +/** + * Perform bidirectional JTAG SCAN operation at maximum TCK frequency. + * + * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO + * data is sampled and stored in the EP2 IN buffer. + * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. + * + * Maximum achievable TCK frequency is 100 kHz for ANGIE clocked at 24 MHz. + * + * @param out_offset offset in EP1OUTBUF where payload data starts + * @param in_offset + */ +int it; +void jtag_scan_io(uint8_t out_offset, uint8_t in_offset) +{ + uint8_t scan_size_bytes, bits_last_byte; + uint8_t tms_count_start, tms_count_end; + uint8_t tms_sequence_start, tms_sequence_end; + uint8_t tdi_data, tdo_data, i, j; + uint8_t outb_buffer; + + it++; + /* Get parameters from EP1OUTBUF */ + scan_size_bytes = EP1OUTBUF[out_offset]; + bits_last_byte = EP1OUTBUF[out_offset + 1]; + tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; + tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; + tms_sequence_start = EP1OUTBUF[out_offset + 3]; + tms_sequence_end = EP1OUTBUF[out_offset + 4]; + + if (tms_count_start > 0) + jtag_clock_tms(tms_count_start, tms_sequence_start); + outb_buffer = IOB & ~(bmbit2 | bmbit1); + + /* Shift all bytes except the last byte */ + for (i = 0; i < scan_size_bytes - 1; i++) { + tdi_data = EP1OUTBUF[i + out_offset + 5]; + tdo_data = 0; + for (j = 0; j < 8; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + IOB = outb_buffer; /* TDI and TCK change here */ + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + tdo_data = tdo_data >> 1; + if (PIN_TDO) + tdo_data |= 0x80; + } + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + } + tdi_data = EP1OUTBUF[i + out_offset + 5]; + tdo_data = 0; + + /* Shift the last byte */ + for (j = 0; j < bits_last_byte; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + + /* Assert TMS signal if requested and this is the last bit */ + if (j == (bits_last_byte - 1) && tms_count_end > 0) { + outb_buffer |= bmbit1; + tms_count_end--; + tms_sequence_end = tms_sequence_end >> 1; + } + IOB = outb_buffer; /* TDI and TCK change here */ + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + tdo_data = tdo_data >> 1; + if (PIN_TDO) + tdo_data |= 0x80; + } + tdo_data = tdo_data >> (8 - bits_last_byte); + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + + /* Move to correct end state */ + if (tms_count_end > 0) + jtag_clock_tms(tms_count_end, tms_sequence_end); +} + +/** + * Perform bidirectional JTAG SCAN operation at maximum TCK frequency. + * + * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO + * data is sampled and stored in the EP2 IN buffer. + * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. + * + * Maximum achievable TCK frequency is 78 kHz for ANGIE clocked at 24 MHz. + * + * @param out_offset offset in EP1OUTBUF where payload data starts + * @param in_offset + */ +void jtag_slow_scan_io(uint8_t out_offset, uint8_t in_offset) +{ + uint8_t scan_size_bytes, bits_last_byte; + uint8_t tms_count_start, tms_count_end; + uint8_t tms_sequence_start, tms_sequence_end; + uint8_t tdi_data, tdo_data, i, j, k; + uint8_t outb_buffer; + + /* Get parameters from EP1OUTBUF */ + scan_size_bytes = EP1OUTBUF[out_offset]; + bits_last_byte = EP1OUTBUF[out_offset + 1]; + tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; + tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; + tms_sequence_start = EP1OUTBUF[out_offset + 3]; + tms_sequence_end = EP1OUTBUF[out_offset + 4]; + + if (tms_count_start > 0) + jtag_slow_clock_tms(tms_count_start, tms_sequence_start); + outb_buffer = IOB & ~(bmbit2 | bmbit1); + + /* Shift all bytes except the last byte */ + for (i = 0; i < scan_size_bytes - 1; i++) { + tdi_data = EP1OUTBUF[i + out_offset + 5]; + tdo_data = 0; + for (j = 0; j < 8; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + IOB = outb_buffer; /* TDI and TCK change here */ + for (k = 0; k < delay_scan_io; k++) + ; + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + for (k = 0; k < delay_scan_io; k++) + ; + tdo_data = tdo_data >> 1; + if (PIN_TDO) + tdo_data |= 0x80; + } + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + } + tdi_data = EP1OUTBUF[i + out_offset + 5]; + tdo_data = 0; + + /* Shift the last byte */ + for (j = 0; j < bits_last_byte; j++) { + if (tdi_data & 0x01) + outb_buffer |= bmbit3; + else + outb_buffer &= ~bmbit3; + + /* Assert TMS signal if requested and this is the last bit */ + if (j == (bits_last_byte - 1) && tms_count_end > 0) { + outb_buffer |= bmbit1; + tms_count_end--; + tms_sequence_end = tms_sequence_end >> 1; + } + IOB = outb_buffer; /* TDI and TCK change here */ + for (k = 0; k < delay_scan_io; k++) + ; + tdi_data = tdi_data >> 1; + IOB = (outb_buffer | bmbit2); + for (k = 0; k < delay_scan_io; k++) + ; + tdo_data = tdo_data >> 1; + if (PIN_TDO) + tdo_data |= 0x80; + } + tdo_data = tdo_data >> (8 - bits_last_byte); + + /* Copy TDO data to EP1INBUF */ + EP1INBUF[i + in_offset] = tdo_data; + + /* Move to correct end state */ + if (tms_count_end > 0) + jtag_slow_clock_tms(tms_count_end, tms_sequence_end); +} + +/** + * Generate TCK clock cycles. + * + * Maximum achievable TCK frequency is 375 kHz for ANGIE clocked at 24 MHz. + * + * @param count number of TCK clock cycles to generate. + */ +void jtag_clock_tck(uint16_t count) +{ + uint16_t i; + uint8_t outb_buffer = IOB & ~(bmbit2); + + for (i = 0; i < count; i++) { + IOB = outb_buffer; + IOB = outb_buffer | bmbit2; + } +} + +/** + * Generate TCK clock cycles at variable frequency. + * + * Maximum achievable TCK frequency is 166.6 kHz for ANGIE clocked at 24 MHz. + * + * @param count number of TCK clock cycles to generate. + */ +void jtag_slow_clock_tck(uint16_t count) +{ + uint16_t i; + uint8_t j; + uint8_t outb_buffer = IOB & ~(bmbit2); + + for (i = 0; i < count; i++) { + IOB = outb_buffer; + for (j = 0; j < delay_tck; j++) + ; + IOB = outb_buffer | bmbit2; + for (j = 0; j < delay_tck; j++) + ; + } +} + +/** + * Perform TAP FSM state transitions at maximum TCK frequency. + * + * Maximum achievable TCK frequency is 176 kHz for ANGIE clocked at 24 MHz. + * + * @param count the number of state transitions to perform. + * @param sequence the TMS pin levels for each state transition, starting with + * the least-significant bit. + */ +void jtag_clock_tms(uint8_t count, uint8_t sequence) +{ + uint8_t outb_buffer = IOB & ~(bmbit2); + uint8_t i; + + for (i = 0; i < count; i++) { + /* Set TMS pin according to sequence parameter */ + if (sequence & 0x1) + outb_buffer |= bmbit1; + else + outb_buffer &= ~bmbit1; + IOB = outb_buffer; + sequence = sequence >> 1; + IOB = outb_buffer | bmbit2; + } +} + +/** + * Perform TAP-FSM state transitions at less than maximum TCK frequency. + * + * Maximum achievable TCK frequency is 117 kHz for ANGIE clocked at 24 MHz. + * + * @param count the number of state transitions to perform. + * @param sequence the TMS pin levels for each state transition, starting with + * the least-significant bit. + */ +void jtag_slow_clock_tms(uint8_t count, uint8_t sequence) +{ + uint8_t outb_buffer = IOB & ~(bmbit2); + uint8_t i, j; + + for (i = 0; i < count; i++) { + /* Set TMS pin according to sequence parameter */ + if (sequence & 0x1) + outb_buffer |= bmbit1; + else + outb_buffer &= ~bmbit1; + IOB = outb_buffer; + for (j = 0; j < delay_tms; j++) + ; + sequence = sequence >> 1; + IOB = outb_buffer | bmbit2; + for (j = 0; j < delay_tms; j++) + ; + } +} + +uint16_t jtag_get_signals(void) +{ + uint8_t input_signal_state, output_signal_state; + input_signal_state = 0; + output_signal_state = 0; + + /* Get states of input pins */ + if (PIN_TDO) + input_signal_state |= SIGNAL_TDO; + + /* Get states of output pins */ + output_signal_state = IOB & MASK_PORTB_DIRECTION_OUT; + + return ((uint16_t)input_signal_state << 8) | ((uint16_t)output_signal_state); +} + +/** + * Set state of JTAG output signals. + * + * @param low signals which should be de-asserted. + * @param high signals which should be asserted. + */ +void jtag_set_signals(uint8_t low, uint8_t high) +{ + IOB &= ~(low & MASK_PORTB_DIRECTION_OUT); + IOB |= (high & MASK_PORTB_DIRECTION_OUT); +} + +/** + * Configure TCK delay parameters. + * + * @param scan_in number of delay cycles in scan_in operations. + * @param scan_out number of delay cycles in scan_out operations. + * @param scan_io number of delay cycles in scan_io operations. + * @param tck number of delay cycles in clock_tck operations. + * @param tms number of delay cycles in clock_tms operations. + */ +void jtag_configure_tck_delay(uint8_t scan_in, uint8_t scan_out, + uint8_t scan_io, uint8_t tck, uint8_t tms) +{ + delay_scan_in = scan_in; + delay_scan_out = scan_out; + delay_scan_io = scan_io; + delay_tck = tck; + delay_tms = tms; +} diff --git a/contrib/firmware/angie/c/src/main.c b/contrib/firmware/angie/c/src/main.c new file mode 100644 index 0000000000..9290af2ab5 --- /dev/null +++ b/contrib/firmware/angie/c/src/main.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/**************************************************************************** + File : main.c * + Contents : main code for NanoXplore USB-JTAG ANGIE adapter * + hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#include "usb.h" +#include "delay.h" +#include "protocol.h" +#include "reg_ezusb.h" +#include +#include + +extern void sudav_isr(void)__interrupt SUDAV_ISR; +extern void sof_isr(void)__interrupt; +extern void sutok_isr(void)__interrupt; +extern void suspend_isr(void)__interrupt; +extern void usbreset_isr(void)__interrupt; +extern void highspeed_isr(void)__interrupt; +extern void ep0ack_isr(void)__interrupt; +extern void stub_isr(void)__interrupt; +extern void ep0in_isr(void)__interrupt; +extern void ep0out_isr(void)__interrupt; +extern void ep1in_isr(void)__interrupt; +extern void ep1out_isr(void)__interrupt; +extern void ep2_isr(void)__interrupt; +extern void ep4_isr(void)__interrupt; +extern void ep6_isr(void)__interrupt; +extern void ep8_isr(void)__interrupt; +extern void ibn_isr(void)__interrupt; +extern void ep0pingnak_isr(void)__interrupt; +extern void ep1pingnak_isr(void)__interrupt; +extern void ep2pingnak_isr(void)__interrupt; +extern void ep4pingnak_isr(void)__interrupt; +extern void ep6pingnak_isr(void)__interrupt; +extern void ep8pingnak_isr(void)__interrupt; +extern void errorlimit_isr(void)__interrupt; +extern void ep2piderror_isr(void)__interrupt; +extern void ep4piderror_isr(void)__interrupt; +extern void ep6piderror_isr(void)__interrupt; +extern void ep8piderror_isr(void)__interrupt; +extern void ep2pflag_isr(void)__interrupt; +extern void ep4pflag_isr(void)__interrupt; +extern void ep6pflag_isr(void)__interrupt; +extern void ep8pflag_isr(void)__interrupt; +extern void ep2eflag_isr(void)__interrupt; +extern void ep4eflag_isr(void)__interrupt; +extern void ep6eflag_isr(void)__interrupt; +extern void ep8eflag_isr(void)__interrupt; +extern void ep2fflag_isr(void)__interrupt; +extern void ep4fflag_isr(void)__interrupt; +extern void ep6fflag_isr(void)__interrupt; +extern void ep8fflag_isr(void)__interrupt; +extern void gpifcomplete_isr(void)__interrupt; +extern void gpifwaveform_isr(void)__interrupt; + +void gpif_init(void); + +int main(void) +{ + CPUCS = ((CPUCS & ~bmclkspd) | (CLK_48M << 3) | CLKOE); /* required for sio0_init */ + sio0_init(57600); /* needed for printf */ + + ep_init(); + gpif_init(); + interrupt_init(); + io_init(); + + /* Perform ReNumeration */ + USBCS |= (DISCON | RENUM); + delay_ms(250); + USBCS &= ~DISCON; + + /* Begin executing command(s). This function never returns. */ + command_loop(); + + /* Never reached, but SDCC complains about missing return statement */ + return 0; +} diff --git a/contrib/firmware/angie/c/src/protocol.c b/contrib/firmware/angie/c/src/protocol.c new file mode 100644 index 0000000000..e32808db8f --- /dev/null +++ b/contrib/firmware/angie/c/src/protocol.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/**************************************************************************** + File : protocol.c * + Contents : Jtag commands handling protocol code for NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#include "usb.h" +#include "protocol.h" +#include "jtag.h" +#include "delay.h" +#include "io.h" +#include "msgtypes.h" +#include "reg_ezusb.h" +#include +#include + +/** Index in EP1 Bulk-OUT data buffer that contains the current command ID */ +volatile uint8_t cmd_id_index; + +/** Number of data bytes already in EP1 Bulk-IN buffer */ +volatile uint8_t payload_index_in; + +/** + * Executes one command and updates global command indexes. + * + * @return true if this command was the last command. + * @return false if there are more commands within the current contents of the + * Bulk EP1-OUT data buffer. + */ +bool execute_command(void) +{ + uint8_t usb_out_bytecount, usb_in_bytecount; + uint16_t signal_state = 0; + uint16_t count; + + /* Most commands do not transfer IN data. To save code space, we write 0 to + * usb_in_bytecount here, then modify it in the switch statement below where + * necessary */ + usb_in_bytecount = 0; + + switch (EP1OUTBUF[cmd_id_index] /* Command ID */) { + case CMD_SCAN_IN: + usb_out_bytecount = 5; + usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; + jtag_scan_in((cmd_id_index + 1), payload_index_in); + break; + case CMD_SCAN_OUT: + usb_out_bytecount = EP1OUTBUF[cmd_id_index + 1] + 5; + jtag_scan_out(cmd_id_index + 1); + break; + case CMD_SCAN_IO: + usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; + usb_out_bytecount = usb_in_bytecount + 5; + jtag_scan_io((cmd_id_index + 1), payload_index_in); + break; + case CMD_CLOCK_TMS: + usb_out_bytecount = 2; + jtag_clock_tms(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]); + break; + case CMD_CLOCK_TCK: + usb_out_bytecount = 2; + count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; + count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; + jtag_clock_tck(count); + break; + case CMD_SLOW_SCAN_IN: + usb_out_bytecount = 5; + usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; + jtag_slow_scan_in(cmd_id_index + 1, payload_index_in); + break; + case CMD_SLOW_SCAN_OUT: + usb_out_bytecount = EP1OUTBUF[cmd_id_index + 1] + 5; + jtag_slow_scan_out(cmd_id_index + 1); + break; + case CMD_SLOW_SCAN_IO: + usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; + usb_out_bytecount = usb_in_bytecount + 5; + jtag_slow_scan_io(cmd_id_index + 1, payload_index_in); + break; + case CMD_SLOW_CLOCK_TMS: + usb_out_bytecount = 2; + jtag_slow_clock_tms(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]); + break; + case CMD_SLOW_CLOCK_TCK: + usb_out_bytecount = 2; + count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; + count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; + jtag_slow_clock_tck(count); + break; + case CMD_SLEEP_US: + usb_out_bytecount = 2; + count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; + count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; + delay_us(count); + break; + case CMD_SLEEP_MS: + usb_out_bytecount = 2; + count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; + count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; + delay_ms(count); + break; + case CMD_GET_SIGNALS: + usb_out_bytecount = 0; + usb_in_bytecount = 2; + signal_state = jtag_get_signals(); + EP1INBUF[payload_index_in] = (signal_state >> 8); + EP1INBUF[payload_index_in + 1] = (signal_state & 0xFF); + break; + case CMD_SET_SIGNALS: + usb_out_bytecount = 2; + jtag_set_signals(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]); + break; + case CMD_CONFIGURE_TCK_FREQ: + usb_out_bytecount = 5; + jtag_configure_tck_delay(EP1OUTBUF[cmd_id_index + 1], /* scan_in */ + EP1OUTBUF[cmd_id_index + 2], /* scan_out */ + EP1OUTBUF[cmd_id_index + 3], /* scan_io */ + EP1OUTBUF[cmd_id_index + 4], /* clock_tck */ + EP1OUTBUF[cmd_id_index + 5]); /* clock_tms */ + break; + case CMD_TEST: + usb_out_bytecount = 1; + /* Do nothing... This command is only used to test if the device is ready + * to accept new commands */ + break; + default: + /* Should never be reached */ + usb_out_bytecount = 0; + break; + } + + /* Update EP1 Bulk-IN data byte count */ + payload_index_in += usb_in_bytecount; + + /* Determine if this was the last command */ + if ((cmd_id_index + usb_out_bytecount + 1) >= EP1OUTBC) + return true; + + /* Not the last command, update cmd_id_index */ + cmd_id_index += (usb_out_bytecount + 1); + return false; +} + +/** + * Forever wait for commands and execute them as they arrive. + */ +void command_loop(void) +{ + bool last_command; + while (1) { + cmd_id_index = 0; + payload_index_in = 0; + + /* Wait until host sends Bulk-OUT packet */ + while ((!ep1_out) && (!ep6_out)) + ; + if (ep6_out) { + /* Execute I2C command */ + i2c_recieve(); + ep6_out = false; + } + if (ep1_out) { + ep1_out = false; + /* Execute the commands */ + last_command = false; + while (!last_command) + last_command = execute_command(); + + /* Send back EP1 Bulk-IN packet if required */ + if (payload_index_in > 0) { + EP1INBC = payload_index_in; + syncdelay(3); + + while (!ep1_in) + ; + ep1_in = false; + } + + /* Re-arm EP1-OUT after command execution */ + EP1OUTBC = 0; + syncdelay(3); + EP1OUTBC = 0; + syncdelay(3); + } + } +} diff --git a/contrib/firmware/angie/c/src/serial.c b/contrib/firmware/angie/c/src/serial.c new file mode 100644 index 0000000000..0398cb23cf --- /dev/null +++ b/contrib/firmware/angie/c/src/serial.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/* + * This code was taken from the fx2lib project from this link: + * https://github.com/djmuhlestein/fx2lib + * + * Copyright (C) 2009 Ubixum, Inc. +*/ + +#include +#include +#include +#include +/** + * using the comp port implies that timer 2 will be used as + * a baud rate generator. (Don't use timer 2) + **/ +void sio0_init(uint32_t baud_rate) __critical +{ + uint16_t hl; /* hl value for reload */ + uint8_t mult; /* multiplier for clock speed */ + uint32_t tmp; /* scratch for mult/divide */ + + mult = (CPUFREQ == CLK_12M) ? 1 : ((CPUFREQ == CLK_24M) ? 2 : 4); + + /* set the clock rate */ + /* use clock 2 */ + RCLK = 1; TCLK = 1; + tmp = mult * 375000L * 2; + tmp /= baud_rate; + tmp += 1; + tmp /= 2; + hl = 0xFFFF - (uint16_t)tmp; + RCAP2H = (uint8_t)(((uint16_t)(hl) >> 8) & 0xff); + + /* seems that the 24/48mhz calculations are always one less than suggested values */ + /* trm table 14-16 */ + RCAP2L = ((uint8_t)((uint16_t)(hl) & 0xff)) + (mult > 0 ? 1 : 0); + + /* start the timer */ + TR2 = 1; + + /* set up the serial port */ + SM0 = 0; SM1 = 1; /* serial mode 1 (asyncronous) */ + SM2 = 0 ; /* has to do with receiving */ + REN = 1 ; /* to enable receiving */ + PCON |= 0x80; /* SET SMOD0, baud rate doubler */ + TI = 1; /* we send initial byte */ +} + +int getchar(void) +{ + char c; + while (!RI) + ; + c = SBUF0; + RI = 0; + return c; +} + +void _transchar(char c) +{ + while (!TI) + ; /* wait for TI=1 */ + TI = 0; + SBUF0 = c; +} + +int putchar (char c) +{ + if (c == '\n') + _transchar('\r'); /* transmit \r\n */ + _transchar(c); + if (c == '\r') + _transchar('\n'); /* transmit \r\n */ + return c; +} diff --git a/contrib/firmware/angie/c/src/usb.c b/contrib/firmware/angie/c/src/usb.c new file mode 100644 index 0000000000..ed23dcfa5a --- /dev/null +++ b/contrib/firmware/angie/c/src/usb.c @@ -0,0 +1,894 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/**************************************************************************** + File : usb.c * + Contents : usb communication handling code for NanoXplore USB-JTAG * + ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + * + * +*****************************************************************************/ + +#include "usb.h" +#include "stdint.h" +#include "delay.h" +#include "io.h" +#include "reg_ezusb.h" +#include +#include +#include +#include "i2c.h" + +/* Also update external declarations in "include/usb.h" if making changes to + * these variables! + */ +volatile bool ep1_out; +volatile bool ep1_in; +volatile bool ep6_out; + +volatile __xdata __at 0xE6B8 struct setup_data setup_data; + +/* Define number of endpoints (except Control Endpoint 0) in a central place. + * Be sure to include the necessary endpoint descriptors! + */ +#define NUM_ENDPOINTS 3 + +__code struct usb_device_descriptor device_descriptor = { + .blength = sizeof(struct usb_device_descriptor), + .bdescriptortype = DESCRIPTOR_TYPE_DEVICE, + .bcdusb = 0x0200, /* BCD: 02.00 (Version 2.0 USB spec) */ + .bdeviceclass = 0xEF, + .bdevicesubclass = 0x02, + .bdeviceprotocol = 0x01, + .bmaxpacketsize0 = 64, + .idvendor = 0x584e, + .idproduct = 0x414f, + .bcddevice = 0x0000, + .imanufacturer = 1, + .iproduct = 2, + .iserialnumber = 3, + .bnumconfigurations = 1 +}; + +/* WARNING: ALL config, interface and endpoint descriptors MUST be adjacent! */ + +__code struct usb_config_descriptor config_descriptor = { + .blength = sizeof(struct usb_config_descriptor), + .bdescriptortype = DESCRIPTOR_TYPE_CONFIGURATION, + .wtotallength = sizeof(struct usb_config_descriptor) + + 3 * sizeof(struct usb_interface_descriptor) + + ((NUM_ENDPOINTS + 2) * sizeof(struct usb_endpoint_descriptor)), + .bnuminterfaces = 2, + .bconfigurationvalue = 1, + .iconfiguration = 1, /* String describing this configuration */ + .bmattributes = 0x80, /* Only MSB set according to USB spec */ + .maxpower = 50 /* 100 mA */ +}; + +__code struct usb_interface_descriptor interface_descriptor00 = { + .blength = sizeof(struct usb_interface_descriptor), + .bdescriptortype = DESCRIPTOR_TYPE_INTERFACE, + .binterfacenumber = 0, + .balternatesetting = 0, + .bnumendpoints = NUM_ENDPOINTS, + .binterfaceclass = 0XFF, + .binterfacesubclass = 0x00, + .binterfaceprotocol = 0x00, + .iinterface = 4 +}; + +__code struct usb_endpoint_descriptor bulk_ep1_out_endpoint_descriptor = { + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (1 | USB_DIR_OUT), + .bmattributes = 0x02, + .wmaxpacketsize = 64, + .binterval = 0 +}; + +__code struct usb_endpoint_descriptor bulk_ep1_in_endpoint_descriptor = { + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (1 | USB_DIR_IN), + .bmattributes = 0x02, + .wmaxpacketsize = 64, + .binterval = 0 +}; + +__code struct usb_endpoint_descriptor bulk_ep2_endpoint_descriptor = { + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (2 | USB_DIR_OUT), + .bmattributes = 0x02, + .wmaxpacketsize = 512, + .binterval = 0 +}; + +__code struct usb_interface_descriptor interface_descriptor01 = { + .blength = sizeof(struct usb_interface_descriptor), + .bdescriptortype = DESCRIPTOR_TYPE_INTERFACE, + .binterfacenumber = 1, + .balternatesetting = 0, + .bnumendpoints = 2, + .binterfaceclass = 0x0A, + .binterfacesubclass = 0x00, + .binterfaceprotocol = 0x00, + .iinterface = 0x00 +}; + +__code struct usb_endpoint_descriptor bulk_ep6_out_endpoint_descriptor = { + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (6 | USB_DIR_OUT), + .bmattributes = 0x02, + .wmaxpacketsize = 512, + .binterval = 0 +}; + +__code struct usb_endpoint_descriptor bulk_ep8_in_endpoint_descriptor = { + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (8 | USB_DIR_IN), + .bmattributes = 0x02, + .wmaxpacketsize = 512, + .binterval = 0 +}; +__code struct usb_language_descriptor language_descriptor = { + .blength = 4, + .bdescriptortype = DESCRIPTOR_TYPE_STRING, + .wlangid = {0x0409} /* US English */ +}; + +__code struct usb_string_descriptor strmanufacturer = + STR_DESCR(16, 'N', 'a', 'n', 'o', 'X', 'p', 'l', 'o', 'r', 'e', ',', ' ', 'S', 'A', 'S', '.'); + +__code struct usb_string_descriptor strproduct = + STR_DESCR(13, 'A', 'N', 'G', 'I', 'E', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r'); + +__code struct usb_string_descriptor strserialnumber = + STR_DESCR(6, '0', '0', '0', '0', '0', '1'); + +__code struct usb_string_descriptor strconfigdescr = + STR_DESCR(12, 'J', 'T', 'A', 'G', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r'); + +/* Table containing pointers to string descriptors */ +__code struct usb_string_descriptor *__code en_string_descriptors[4] = { + &strmanufacturer, + &strproduct, + &strserialnumber, + &strconfigdescr +}; +void sudav_isr(void)__interrupt SUDAV_ISR +{ + EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ + USBIRQ = SUDAVI; + EP0CS |= HSNAK; + usb_handle_setup_data(); +} +void sof_isr(void)__interrupt SOF_ISR +{ +} +void sutok_isr(void)__interrupt SUTOK_ISR +{ +} +void suspend_isr(void)__interrupt SUSPEND_ISR +{ +} +void usbreset_isr(void)__interrupt USBRESET_ISR +{ +} +void highspeed_isr(void)__interrupt HIGHSPEED_ISR +{ +} +void ep0ack_isr(void)__interrupt EP0ACK_ISR +{ +} +void stub_isr(void)__interrupt STUB_ISR +{ +} +void ep0in_isr(void)__interrupt EP0IN_ISR +{ +} +void ep0out_isr(void)__interrupt EP0OUT_ISR +{ +} +void ep1in_isr(void)__interrupt EP1IN_ISR +{ + ep1_in = true; + EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ + EPIRQ = 0x04; /* Clear individual EP1IN IRQ */ +} +void ep1out_isr(void)__interrupt EP1OUT_ISR +{ + ep1_out = true; + EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ + EPIRQ = 0x08; /* Clear individual EP1OUT IRQ */ +} +void ep2_isr(void)__interrupt EP2_ISR +{ +} +void ep4_isr(void)__interrupt EP4_ISR +{ +} +void ep6_isr(void)__interrupt EP6_ISR +{ + ep6_out = true; + EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ + EPIRQ = 0x40; /* Clear individual EP6OUT IRQ */ + +} +void ep8_isr(void)__interrupt EP8_ISR +{ + EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ + EPIRQ = 0x80; /* Clear individual EP8IN IRQ */ +} +void ibn_isr(void)__interrupt IBN_ISR +{ +} +void ep0pingnak_isr(void)__interrupt EP0PINGNAK_ISR +{ +} +void ep1pingnak_isr(void)__interrupt EP1PINGNAK_ISR +{ +} +void ep2pingnak_isr(void)__interrupt EP2PINGNAK_ISR +{ +} +void ep4pingnak_isr(void)__interrupt EP4PINGNAK_ISR +{ +} +void ep6pingnak_isr(void)__interrupt EP6PINGNAK_ISR +{ +} +void ep8pingnak_isr(void)__interrupt EP8PINGNAK_ISR +{ +} +void errorlimit_isr(void)__interrupt ERRORLIMIT_ISR +{ +} +void ep2piderror_isr(void)__interrupt EP2PIDERROR_ISR +{ +} +void ep4piderror_isr(void)__interrupt EP4PIDERROR_ISR +{ +} +void ep6piderror_isr(void)__interrupt EP6PIDERROR_ISR +{ +} +void ep8piderror_isr(void)__interrupt EP8PIDERROR_ISR +{ +} +void ep2pflag_isr(void)__interrupt EP2PFLAG_ISR +{ +} +void ep4pflag_isr(void)__interrupt EP4PFLAG_ISR +{ +} +void ep6pflag_isr(void)__interrupt EP6PFLAG_ISR +{ +} +void ep8pflag_isr(void)__interrupt EP8PFLAG_ISR +{ +} +void ep2eflag_isr(void)__interrupt EP2EFLAG_ISR +{ +} +void ep4eflag_isr(void)__interrupt EP4EFLAG_ISR +{ +} +void ep6eflag_isr(void)__interrupt EP6EFLAG_ISR +{ +} +void ep8eflag_isr(void)__interrupt EP8EFLAG_ISR +{ +} +void ep2fflag_isr(void)__interrupt EP2FFLAG_ISR +{ +} +void ep4fflag_isr(void)__interrupt EP4FFLAG_ISR +{ +} +void ep6fflag_isr(void)__interrupt EP6FFLAG_ISR +{ +} +void ep8fflag_isr(void)__interrupt EP8FFLAG_ISR +{ +} +void gpifcomplete_isr(void)__interrupt GPIFCOMPLETE_ISR +{ +} +void gpifwaveform_isr(void)__interrupt GPIFWAVEFORM_ISR +{ +} + +/** + * Return the control/status register for an endpoint + * + * @param ep endpoint address + * @return on success: pointer to Control & Status register for endpoint + * specified in \a ep + * @return on failure: NULL + */ +__xdata uint8_t *usb_get_endpoint_cs_reg(uint8_t ep) +{ + /* Mask direction bit */ + uint8_t ep_num = ep & ~0x80; + + switch (ep_num) { + case 0: + return &EP0CS; + case 1: + return ep & 0x80 ? &EP1INCS : &EP1OUTCS; + case 2: + return &EP2CS; + case 4: + return &EP4CS; + case 6: + return &EP6CS; + case 8: + return &EP8CS; + default: + return NULL; + } +} + +void usb_reset_data_toggle(uint8_t ep) +{ + /* TOGCTL register: + +----+-----+-----+------+-----+-------+-------+-------+ + | Q | S | R | IO | EP3 | EP2 | EP1 | EP0 | + +----+-----+-----+------+-----+-------+-------+-------+ + + To reset data toggle bits, we have to write the endpoint direction (IN/OUT) + to the IO bit and the endpoint number to the EP2..EP0 bits. Then, in a + separate write cycle, the R bit needs to be set. + */ + TOGCTL = (((ep & 0x80) >> 3) + (ep & 0x0F)); + TOGCTL |= BMRESETTOGGLE; +} + +/** + * Handle GET_STATUS request. + * + * @return on success: true + * @return on failure: false + */ +bool usb_handle_get_status(void) +{ + uint8_t *ep_cs; + switch (setup_data.bmrequesttype) { + case GS_DEVICE: + /* Two byte response: Byte 0, Bit 0 = self-powered, Bit 1 = remote wakeup. + * Byte 1: reserved, reset to zero */ + EP0BUF[0] = 0; + EP0BUF[1] = 0; + + /* Send response */ + EP0BCH = 0; + syncdelay(3); + EP0BCL = 2; + syncdelay(3); + break; + case GS_INTERFACE: + /* Always return two zero bytes according to USB 1.1 spec, p. 191 */ + EP0BUF[0] = 0; + EP0BUF[1] = 0; + + /* Send response */ + EP0BCH = 0; + syncdelay(3); + EP0BCL = 2; + syncdelay(3); + break; + case GS_ENDPOINT: + /* Get stall bit for endpoint specified in low byte of wIndex */ + ep_cs = usb_get_endpoint_cs_reg(setup_data.windex & 0xff); + + if (*ep_cs & EPSTALL) + EP0BUF[0] = 0x01; + else + EP0BUF[0] = 0x00; + + /* Second byte sent has to be always zero */ + EP0BUF[1] = 0; + + /* Send response */ + EP0BCH = 0; + syncdelay(3); + EP0BCL = 2; + syncdelay(3); + break; + default: + return false; + } + return true; +} + +/** + * Handle CLEAR_FEATURE request. + * + * @return on success: true + * @return on failure: false + */ +bool usb_handle_clear_feature(void) +{ + __xdata uint8_t *ep_cs; + + switch (setup_data.bmrequesttype) { + case CF_DEVICE: + /* Clear remote wakeup not supported: stall EP0 */ + STALL_EP0(); + break; + case CF_ENDPOINT: + if (setup_data.wvalue == 0) { + /* Unstall the endpoint specified in wIndex */ + ep_cs = usb_get_endpoint_cs_reg(setup_data.windex); + if (!ep_cs) + return false; + *ep_cs &= ~EPSTALL; + } else { + /* Unsupported feature, stall EP0 */ + STALL_EP0(); + } + break; + default: + /* Vendor commands... */ + break; + } + return true; +} + +/** + * Handle SET_FEATURE request. + * + * @return on success: true + * @return on failure: false + */ +bool usb_handle_set_feature(void) +{ + __xdata uint8_t *ep_cs; + + switch (setup_data.bmrequesttype) { + case SF_DEVICE: + if (setup_data.wvalue == 2) + return true; + break; + case SF_ENDPOINT: + if (setup_data.wvalue == 0) { + /* Stall the endpoint specified in wIndex */ + ep_cs = usb_get_endpoint_cs_reg(setup_data.windex); + if (!ep_cs) + return false; + *ep_cs |= EPSTALL; + } else { + /* Unsupported endpoint feature */ + return false; + } + break; + default: + /* Vendor commands... */ + break; + } + + return true; +} + +/** + * Handle GET_DESCRIPTOR request. + * + * @return on success: true + * @return on failure: false + */ +bool usb_handle_get_descriptor(void) +{ + __xdata uint8_t descriptor_type; + __xdata uint8_t descriptor_index; + + descriptor_type = (setup_data.wvalue & 0xff00) >> 8; + descriptor_index = setup_data.wvalue & 0x00ff; + + switch (descriptor_type) { + case DESCRIPTOR_TYPE_DEVICE: + SUDPTRH = HI8(&device_descriptor); + SUDPTRL = LO8(&device_descriptor); + break; + case DESCRIPTOR_TYPE_CONFIGURATION: + SUDPTRH = HI8(&config_descriptor); + SUDPTRL = LO8(&config_descriptor); + break; + case DESCRIPTOR_TYPE_STRING: + if (setup_data.windex == 0) { + /* Supply language descriptor */ + SUDPTRH = HI8(&language_descriptor); + SUDPTRL = LO8(&language_descriptor); + } else if (setup_data.windex == 0x0409 /* US English */) { + /* Supply string descriptor */ + SUDPTRH = HI8(en_string_descriptors[descriptor_index - 1]); + SUDPTRL = LO8(en_string_descriptors[descriptor_index - 1]); + } else { + return false; + } + break; + default: + /* Unsupported descriptor type */ + return false; + } + return true; +} + +/** + * Handle SET_INTERFACE request. + */ +void usb_handle_set_interface(void) +{ + /* Reset Data Toggle */ + usb_reset_data_toggle(USB_DIR_IN | 4); + usb_reset_data_toggle(USB_DIR_OUT | 2); + + /* Unstall & clear busy flag of all valid IN endpoints */ + EP1INCS = 0 | EPBSY; + + /* Unstall all valid OUT endpoints, reset bytecounts */ + EP1OUTCS = 0; + EP1OUTBC = 0; + syncdelay(3); +} + +/* Initialize GPIF interface transfer count */ +void set_gpif_cnt(uint32_t count) +{ + GPIFTCB3 = (uint8_t)(((uint32_t)(count) >> 24) & 0x000000ff); + syncdelay(3); + GPIFTCB2 = (uint8_t)(((uint32_t)(count) >> 16) & 0x000000ff); + syncdelay(3); + GPIFTCB1 = (uint8_t)(((uint32_t)(count) >> 8) & 0x000000ff); + syncdelay(3); + GPIFTCB0 = (uint8_t)((uint32_t)(count) & 0x000000ff); +} + +/* + * Vendor commands handling: +*/ +#define VR_CFGOPEN 0xB0 +#define VR_CFGCLOSE 0xB1 + +uint8_t ix; +uint8_t bcnt; +uint8_t __xdata *eptr; +uint16_t wcnt; +uint32_t __xdata gcnt; +bool usb_handle_send_bitstream(void) +{ + eptr = EP0BUF; /* points to EP0BUF 64-byte register */ + wcnt = setup_data.wlength; /* total transfer count */ + + /* Clear EP0BUF for OUT requests */ + if (setup_data.bmrequesttype & 0x80) { + bcnt = ((wcnt > 64) ? 64 : wcnt); + for (ix = 0; ix < bcnt; ix++) + eptr[ix] = 0; + } + + switch (setup_data.brequest) { + case VR_CFGOPEN: + /* Clear bytecount / to allow new data in / to stops NAKing */ + EP0BCH = 0; + EP0BCL = 0; + while (EP0CS & EPBSY) + ; /* wait to finish transferring in EP0BUF, until not busy */ + gcnt = ((uint32_t)(eptr[0]) << 24) | ((uint32_t)(eptr[1]) << 16) + | ((uint32_t)(eptr[2]) << 8) | (uint32_t)(eptr[3]); + /* Angie board FPGA bitstream download */ + switch ((setup_data.wvalue) & 0x00C0) { + case 0x00: + PIN_PROGRAM_B = 0; /* Apply RPGM- pulse */ + GPIFWFSELECT = 0xF2; /* Restore Config mode waveforms select */ + syncdelay(3); + EP2FIFOCFG = BMAUTOOUT; /* and Automatic 8-bit GPIF OUT mode */ + syncdelay(3); + PIN_PROGRAM_B = 1; /* Negate RPGM- pulse */ + delay_ms(10); /* FPGA init time < 10mS */ + set_gpif_cnt(gcnt); /* Initialize GPIF interface transfer count */ + PIN_RDWR_B = 0; + PIN_CSI_B = 0; + GPIFTRIG = GPIF_EP2; /* Trigger GPIF OUT transfer on EP2 */ + syncdelay(3); + break; + default: + break; + } + break; + case VR_CFGCLOSE: + ix = 10; + /* wait until GPIF transaction has been completed */ + while ((GPIFTRIG & BMGPIFDONE) == 0) { + if (ix-- == 0) { + break; + } + delay_ms(1); + } + switch ((setup_data.wvalue) & 0x00C0) { + case 0x00: + PIN_CSI_B = 1; + PIN_RDWR_B = 1; + IFCONFIG &= 0xFC; /* Exit gpif mode */ + break; + default: + break; + } + EP0BCH = 0; + EP0BCL = (uint8_t)(setup_data.wlength); /* Signal buffer is filled */ + break; + default: + return true; /* Error: unknown VR command */ + } + return false; /* no error; command handled OK */ +} + +/** + * Handle the arrival of a USB Control Setup Packet. + */ +void usb_handle_setup_data(void) +{ + switch (setup_data.brequest) { + case GET_STATUS: + if (!usb_handle_get_status()) + STALL_EP0(); + break; + case CLEAR_FEATURE: + if (!usb_handle_clear_feature()) + STALL_EP0(); + break; + case 2: case 4: + /* Reserved values */ + STALL_EP0(); + break; + case SET_FEATURE: + if (!usb_handle_set_feature()) + STALL_EP0(); + break; + case SET_ADDRESS: + /* Handled by USB core */ + break; + case SET_DESCRIPTOR: + /* Set Descriptor not supported. */ + STALL_EP0(); + break; + case GET_DESCRIPTOR: + if (!usb_handle_get_descriptor()) + STALL_EP0(); + break; + case GET_CONFIGURATION: + /* ANGIE has only one configuration, return its index */ + EP0BUF[0] = config_descriptor.bconfigurationvalue; + EP0BCH = 0; + EP0BCL = 1; + syncdelay(3); + break; + case SET_CONFIGURATION: + /* ANGIE has only one configuration -> nothing to do */ + break; + case GET_INTERFACE: + /* ANGIE only has one interface, return its number */ + EP0BUF[0] = interface_descriptor00.binterfacenumber; + EP0BCH = 0; + EP0BCL = 1; + syncdelay(3); + break; + case SET_INTERFACE: + usb_handle_set_interface(); + break; + case SYNCH_FRAME: + /* Isochronous endpoints not used -> nothing to do */ + break; + default: + /* if not Vendor command, Stall EndPoint 0 */ + if (usb_handle_send_bitstream()) + STALL_EP0(); + break; + } +} + +/** + * Handle the initialization of endpoints. + */ +void ep_init(void) +{ + EP1INCFG = 0xA0; + syncdelay(3); + EP1OUTCFG = 0xA0; + syncdelay(3); + EP2CFG = 0xA0; + syncdelay(3); + EP4CFG = 0x00; + syncdelay(3); + EP6CFG = 0xA2; + syncdelay(3); + EP8CFG = 0xE2; + syncdelay(3); + + /* arm EP1-OUT */ + EP1OUTBC = 0; + syncdelay(3); + EP1OUTBC = 0; + syncdelay(3); + + /* arm EP1-IN */ + EP1INBC = 0; + syncdelay(3); + EP1INBC = 0; + syncdelay(3); + + /* arm EP6-OUT */ + EP6BCL = 0x80; + syncdelay(3); + EP6BCL = 0x80; + syncdelay(3); + + /* Standard procedure to reset FIFOs */ + FIFORESET = BMNAKALL; /* NAK all transfers during the reset */ + syncdelay(3); + FIFORESET = 0x02; /* reset EP2 FIFO */ + syncdelay(3); + FIFORESET = 0x00; /* deactivate the NAK all */ + syncdelay(3); + EP2FIFOCFG = 0x00; + syncdelay(3); + EP2FIFOCFG = BMAUTOOUT; /* Automatic 8-bit GPIF OUT mode */ + syncdelay(3); +} + +void i2c_recieve(void) +{ + PIN_SDA_DIR = 0; + if (EP6FIFOBUF[0] == 1) { + uint8_t rdwr = EP6FIFOBUF[0]; //read + uint8_t data_count = EP6FIFOBUF[1]; //data sent count + uint8_t count = EP6FIFOBUF[2]; //requested data count + uint8_t adr = EP6FIFOBUF[3]; //address + uint8_t address = get_address(adr, rdwr); //address byte (read command) + uint8_t address_2 = get_address(adr, 0); //address byte 2 (write command) + + printf("%d\n", address - 1); + + /* start: */ + start_cd(); + /* address: */ + send_byte(address_2); //write + /* ack: */ + uint8_t ack = get_ack(); + + /* send data */ + if (data_count) { //if there is a byte reg + for (uint8_t i = 0; i < data_count; i++) { + send_byte(EP6FIFOBUF[i + 4]); + /* ack(): */ + ack = get_ack(); + } + } + + /* repeated start: */ + repeated_start(); + /* address: */ + send_byte(address); + /* get ack: */ + ack = get_ack(); + + /* receive data */ + for (uint8_t i = 0; i < count - 1; i++) { + EP8FIFOBUF[i] = receive_byte(); + + /* send ack: */ + send_ack(); + } + + EP8FIFOBUF[count - 1] = receive_byte(); + + /* send Nack: */ + send_nack(); + + /* stop */ + stop_cd(); + + EP8BCH = 0; //EP8 + syncdelay(3); + EP8BCL = count; //EP8 + + EP6BCL = 0x80; //EP6 + syncdelay(3); + EP6BCL = 0x80; //EP6 + } else { + uint8_t rdwr = EP6FIFOBUF[0]; //write + uint8_t count = EP6FIFOBUF[1]; //data count + uint8_t adr = EP6FIFOBUF[2]; //address + uint8_t address = get_address(adr, rdwr); //address byte (read command) + uint8_t ack_cnt = 0; + +/* start(): */ + start_cd(); +/* address: */ + send_byte(address); //write +/* ack(): */ + if (!get_ack()) + ack_cnt++; +/* send data */ + for (uint8_t i = 0; i < count; i++) { + send_byte(EP6FIFOBUF[i + 3]); + + /* get ack: */ + if (!get_ack()) + ack_cnt++; + } + +/* stop */ + stop_cd(); + + EP8FIFOBUF[0] = ack_cnt; + + EP8BCH = 0; //EP8 + syncdelay(3); + EP8BCL = 1; //EP8 + + EP6BCL = 0x80; //EP6 + syncdelay(3); + EP6BCL = 0x80; //EP6 + } +} + +/** + * Interrupt initialization. Configures USB interrupts. + **/ +void interrupt_init(void) +{ + /* Enable Interrupts */ + EA = 1; + + /* Enable USB interrupt (EIE register) */ + EUSB = 1; + EICON |= 0x20; + + /* Enable INT 2 & 4 Autovectoring */ + INTSETUP |= (AV2EN | AV4EN); + + /* Enable individual EP1OUT&IN & EP6&8 interrupts */ + EPIE |= 0xCC; + + /* Clear individual USB interrupt IRQ */ + EPIRQ = 0xCC; + + /* Enable SUDAV interrupt */ + USBIEN |= SUDAVI; + + /* Clear SUDAV interrupt */ + USBIRQ = SUDAVI; +} + +/** + * Handle the initialization of io ports. + */ +void io_init(void) +{ + /* PORT A */ + PORTACFG = 0x01; /* 0: normal ou 1: alternate function (each bit) */ + OEA = 0xEF; /* all OUT exept INIT_B IN */ + IOA = 0xFF; + + /* PORT B */ + OEB = 0xEF; /* all OUT exept TDO */ + IOB = 0xFF; + PIN_TRST = 1; + PIN_TMS = 0; + PIN_TCK = 0; + PIN_TDI = 0; + PIN_SRST = 1; + + /* PORT C */ + PORTCCFG = 0x00; /* 0: normal ou 1: alternate function (each bit) */ + OEC = 0xFF; + IOC = 0xFF; + + /* PORT D */ + OED = 0xFF; + IOD = 0xFF; +} diff --git a/contrib/firmware/angie/hdl/Makefile b/contrib/firmware/angie/hdl/Makefile new file mode 100644 index 0000000000..b28b650892 --- /dev/null +++ b/contrib/firmware/angie/hdl/Makefile @@ -0,0 +1,109 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (C) 2023 by NanoXplore, France - all rights reserved + +# Needed by timing test +export PROJECT := angie_bitstream +TARGET_PART := xc6slx9-2tqg144 +export TOPLEVEL := S609 + +# Detects the ROOT dir from the .git marker +sp := +sp += +_walk = $(if $1,$(wildcard /$(subst $(sp),/,$1)/$2) $(call _walk,$(wordlist 2,$(words $1),x $1),$2)) +_find = $(firstword $(call _walk,$(strip $(subst /, ,$1)),$2)) +_ROOT := $(patsubst %/.git,%,$(call _find,$(CURDIR),.git)) + +SHELL := /bin/bash +TOP_DIR := $(realpath $(_ROOT)) +HDL_DIR := $(CURDIR) +SRC_DIR := $(HDL_DIR)/src +TOOLS_DIR := $(TOP_DIR)/tools/build +COMMON_DIR := $(TOP_DIR)/common/hdl +COMMON_HDL_DIR := $(COMMON_DIR)/src +COMMON_LIBS := $(COMMON_DIR)/libs +HDL_BUILD_DIR := $(HDL_DIR)/build +OUTPUT_DIR ?= $(HDL_BUILD_DIR)/output +FINAL_OUTPUT_DIR := $(OUTPUT_DIR)/$(PROJECT) + +# Tools +MKDIR := mkdir -p +CP := cp -f + +HDL_SRC_PATH := $(addprefix $(COMMON_DIR)/ips/, $(HDL_IPS)) $(HDL_DIR) +VHDSOURCE += $(foreach ip,$(HDL_SRC_PATH),$(wildcard $(ip)/src/*.vhd)) +VSOURCE += $(foreach ip,$(HDL_SRC_PATH),$(wildcard $(ip)/src/*.v)) +VSOURCE += $(foreach ip,$(HDL_SRC_PATH),$(wildcard $(ip)/src/*.vh)) + +CONSTRAINTS ?= $(SRC_DIR)/$(PROJECT).ucf + +COMMON_OPTS := -intstyle xflow +XST_OPTS := +NGDBUILD_OPTS := +MAP_OPTS := -mt 2 +PAR_OPTS := -mt 4 +BITGEN_OPTS := -g Binary:Yes + +XILINX_PLATFORM := lin64 +PATH := $(PATH):$(XILINX_HOME)/bin/$(XILINX_PLATFORM) + +RUN = @echo -ne "\n\n\e[1;33m======== $(1) ========\e[m\n\n"; \ + cd $(HDL_BUILD_DIR) && $(XILINX_HOME)/bin/$(XILINX_PLATFORM)/$(1) + +compile: $(HDL_BUILD_DIR)/$(PROJECT).bin + +install: $(HDL_BUILD_DIR)/$(PROJECT).bin + $(MKDIR) $(FINAL_OUTPUT_DIR) + $(CP) $(HDL_BUILD_DIR)/$(PROJECT).bin $(FINAL_OUTPUT_DIR) + +clean: + rm -rf $(HDL_BUILD_DIR) + +$(HDL_BUILD_DIR)/$(PROJECT).bin: $(HDL_BUILD_DIR)/$(PROJECT).ncd + $(call RUN,bitgen) $(COMMON_OPTS) $(BITGEN_OPTS) \ + -w $(PROJECT).ncd $(PROJECT).bit + +$(HDL_BUILD_DIR)/$(PROJECT).ncd: $(HDL_BUILD_DIR)/$(PROJECT).map.ncd + $(call RUN,par) $(COMMON_OPTS) $(PAR_OPTS) \ + -w $(PROJECT).map.ncd $(PROJECT).ncd $(PROJECT).pcf + +$(HDL_BUILD_DIR)/$(PROJECT).map.ncd: $(HDL_BUILD_DIR)/$(PROJECT).ngd + $(call RUN,map) $(COMMON_OPTS) $(MAP_OPTS) \ + -p $(TARGET_PART) \ + -w $(PROJECT).ngd -o $(PROJECT).map.ncd $(PROJECT).pcf + +$(HDL_BUILD_DIR)/$(PROJECT).ngd: $(HDL_BUILD_DIR)/$(PROJECT).ngc + $(call RUN,ngdbuild) $(COMMON_OPTS) $(NGDBUILD_OPTS) \ + -p $(TARGET_PART) -uc $(CONSTRAINTS) \ + $(PROJECT).ngc $(PROJECT).ngd + +$(HDL_BUILD_DIR)/$(PROJECT).ngc: $(HDL_BUILD_DIR)/$(PROJECT).prj $(HDL_BUILD_DIR)/$(PROJECT).scr + $(call RUN,xst) $(COMMON_OPTS) -ifn $(PROJECT).scr + +$(HDL_BUILD_DIR)/$(PROJECT).scr: | $(HDL_BUILD_DIR) + @echo "Updating $@" + @mkdir -p $(HDL_BUILD_DIR) + @rm -f $@ + @echo "run" \ + "-ifn $(PROJECT).prj" \ + "-ofn $(PROJECT).ngc" \ + "-ifmt mixed" \ + "$(XST_OPTS)" \ + "-top $(TOPLEVEL)" \ + "-ofmt NGC" \ + "-p $(TARGET_PART)" \ + > $(HDL_BUILD_DIR)/$(PROJECT).scr + +$(HDL_BUILD_DIR)/$(PROJECT).prj: | $(HDL_BUILD_DIR) + @echo "Updating $@" + @rm -f $@ + @$(foreach file,$(VSOURCE),echo "verilog work \"$(file)\"" >> $@;) + @$(foreach file,$(VHDSOURCE),echo "vhdl work \"$(file)\"" >> $@;) + @$(foreach lib,$(HDL_LIBS),$(foreach file,$(wildcard $(COMMON_LIBS)/$(lib)/src/*.vhd),echo "vhdl $(lib) \"$(file)\"" >> $@;)) + @$(foreach lib,$(HDL_LIBS),$(foreach file,$(wildcard $(COMMON_LIBS)/$(lib)/src/*.v),echo "verilog $(lib) \"$(file)\"" >> $@;)) + @$(foreach lib,$(HDL_LIBS),$(foreach file,$(wildcard $(COMMON_LIBS)/$(lib)/src/*.vh),echo "verilog $(lib) \"$(file)\"" >> $@;)) + +$(HDL_BUILD_DIR): + $(MKDIR) $(HDL_BUILD_DIR) + +.PHONY: clean compile install + diff --git a/contrib/firmware/angie/hdl/README b/contrib/firmware/angie/hdl/README new file mode 100644 index 0000000000..00578ff729 --- /dev/null +++ b/contrib/firmware/angie/hdl/README @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (C) 2023 by NanoXplore, France - all rights reserved + +This is the source code of Nanoxplore USB-JTAG Adapter Angie's bitstream. +This bitstream is for the "xc6slx9-2tqg144" Spartan-6 Xilinx FPGA. + +To generate this bitstream, you need to install Xilinx ISE Webpack 14.7 +You will need to give the ISE software path : export XILINX_HOME=path/to/ise/sw +Please set the enviromnent first by executing the ". ./set_env.sh" + +All you have to do now is to write your vhd and constrains codes. + +One all is setup, you can use the make commands: + make compile : to compile your (.vhd & .ucf) files in the "src" directory + A directory named "build" will be created, which contains all the generated + files including the bitstream file. + + make clean : to delete the build directory. diff --git a/contrib/firmware/angie/hdl/set_env.sh b/contrib/firmware/angie/hdl/set_env.sh new file mode 100644 index 0000000000..60e97375b9 --- /dev/null +++ b/contrib/firmware/angie/hdl/set_env.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (C) 2023 by NanoXplore, France - all rights reserved + +[ -z "${XILINX_HOME}" ] && export XILINX_HOME=/home/software/Xilinx/ISE/14.7/ISE_DS/ISE +export PATH="$XILINX_HOME:$PATH" +echo "SET XILINX_HOME to ${XILINX_HOME}" +# This is needed for isim +XILINX_HOME_BASE=${XILINX_HOME}/.. +for part in common EDK PlanAhead ISE +do + el=${XILINX_HOME_BASE}/${part} + . ${el}/.settings64.sh ${el} +done diff --git a/contrib/firmware/angie/hdl/src/angie_bitstream.ucf b/contrib/firmware/angie/hdl/src/angie_bitstream.ucf new file mode 100644 index 0000000000..9eb0c85c39 --- /dev/null +++ b/contrib/firmware/angie/hdl/src/angie_bitstream.ucf @@ -0,0 +1,50 @@ +## SPDX-License-Identifier: BSD-3-Clause +##-------------------------------------------------------------------------- +## Project Context: nanoXplore USB-JTAG Adapter Board, Spartan6 +## Design Name: NJTAG USB-JTAG Adapter FPGA source code +## Module Name: _angie_openocd.ucf +## Target Device: XC6SLX9-2 TQ144 +## Tool versions: ISE Webpack 13.2 -> 14.2 +## Author: Ahmed BOUDJELIDA nanoXplore SAS +##-------------------------------------------------------------------------- +# WARNING: PullUps on JTAG inputs should be enabled after configuration +# (bitgen option) since the pins are not connected. + +net TRST LOC = 'P48' ; +net TMS LOC = 'P43' ; +net TCK LOC = 'P44' ; +net TDI LOC = 'P45' ; +net TDO LOC = 'P46' ; +net SRST LOC = 'P61' ; + +net SDA LOC = 'P50' ; +net SCL LOC = 'P51' ; +net SDA_DIR LOC = 'P56' ; +net SCL_DIR LOC = 'P57' ; + +net SI_TDO LOC = 'P16' ; +net SO_TRST LOC = 'P32' ; +net SO_TMS LOC = 'P27' ; +net SO_TCK LOC = 'P30' ; +net SO_TDI LOC = 'P26' ; +net SO_SRST LOC = 'P12' ; + +net SO_SDA_OUT LOC = 'P140' ; +net SO_SDA_IN LOC = 'P1' ; +net SO_SCL LOC = 'P137'; + +net ST_0 LOC = 'P29' ; +net ST_1 LOC = 'P21' ; +net ST_2 LOC = 'P11' ; + +net ST_4 LOC = 'P134' ; +net ST_5 LOC = 'P139' ; + +net FTP<0> LOC = 'P121' ; +net FTP<1> LOC = 'P120' ; +net FTP<2> LOC = 'P119' ; +net FTP<3> LOC = 'P116' ; +net FTP<4> LOC = 'P111' ; +net FTP<5> LOC = 'P112' ; +net FTP<6> LOC = 'P115' ; +net FTP<7> LOC = 'P114' ; diff --git a/contrib/firmware/angie/hdl/src/angie_bitstream.vhd b/contrib/firmware/angie/hdl/src/angie_bitstream.vhd new file mode 100644 index 0000000000..6004bf2ff5 --- /dev/null +++ b/contrib/firmware/angie/hdl/src/angie_bitstream.vhd @@ -0,0 +1,103 @@ +-- SPDX-License-Identifier: BSD-3-Clause +---------------------------------------------------------------------------- +-- Project Context: nanoXplore USB-JTAG Adapter Board, Spartan6 +-- Design Name: NJTAG USB-JTAG Adapter FPGA source code +-- Module Name: _angie_openocd.vhd +-- Target Device: XC6SLX9-2 TQ144 +-- Tool versions: ISE Webpack 13.2 -> 14.2 +-- Author: Ahmed BOUDJELIDA nanoXplore SAS +---------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; +library UNISIM; +use UNISIM.VComponents.all; + +entity S609 is port( + TRST : in std_logic; + TMS : in std_logic; + TCK : in std_logic; + TDI : in std_logic; + TDO : out std_logic; + SRST : in std_logic; + + SDA : inout std_logic; + SDA_DIR : in std_logic; + SCL : in std_logic; + SCL_DIR : in std_logic; + + FTP : out std_logic_vector(7 downto 0); -- Test points + SI_TDO : in std_logic; + ST_0 : out std_logic; + ST_1 : out std_logic; + ST_2 : out std_logic; + + ST_4 : out std_logic; + ST_5 : out std_logic; + + SO_SDA_OUT : out std_logic; + SO_SDA_IN : in std_logic; + SO_SCL : out std_logic; + + SO_TRST : out std_logic; + SO_TMS : out std_logic; + SO_TCK : out std_logic; + SO_TDI : out std_logic; + SO_SRST : out std_logic +); +end S609; + +architecture A_S609 of S609 is +begin + +--Directions: +ST_0 <= '0'; +ST_1 <= '1'; + +--TDO: +TDO <= not SI_TDO; + +--TRST - TCK - TMS - TDI: +SO_TRST <= TRST; +SO_TMS <= TMS; +SO_TCK <= TCK; +SO_TDI <= TDI; +ST_2 <= SRST; +SO_SRST <= '0'; + +SO_SCL <= SCL; + +SDA <= not(SO_SDA_IN) when (SDA_DIR = '1') else 'Z'; +SO_SDA_OUT <= SDA; + +process(SDA_DIR) +begin + if(SDA_DIR = '0') then + ST_5 <= '0'; + else + ST_5 <= '1'; + end if; +end process; + +process(SCL_DIR) +begin + if(SCL_DIR = '0') then + ST_4 <= '0'; + else + ST_4 <= '1'; + end if; +end process; + +--Points de test: +FTP(0) <= SDA; +FTP(1) <= SCL; +FTP(2) <= not(SO_SDA_IN); +FTP(3) <= SDA_DIR; +FTP(5) <= SRST; +FTP(4) <= SI_TDO; +FTP(6) <= '1'; +FTP(7) <= '1'; + +end A_S609; diff --git a/contrib/gen-stellaris-part-header.pl b/contrib/gen-stellaris-part-header.pl index 68f2889b31..3f982f4ab0 100755 --- a/contrib/gen-stellaris-part-header.pl +++ b/contrib/gen-stellaris-part-header.pl @@ -1,4 +1,6 @@ #!/usr/bin/perl +# SPDX-License-Identifier: GPL-2.0-or-later + # Automatically generates the StellarisParts struct in src/flash/nor/stellaris.c # Uses the header files from TI/Luminary's StellarisWare complete Firmware Development Package # available from: http://www.luminarymicro.com/products/software_updates.html diff --git a/contrib/itmdump.c b/contrib/itmdump.c index 88099040a6..e7523d9bc2 100644 --- a/contrib/itmdump.c +++ b/contrib/itmdump.c @@ -1,19 +1,6 @@ -/* - * Copyright (C) 2010 by David Brownell - * - * 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 3 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 . - */ +// SPDX-License-Identifier: GPL-3.0-or-later + +/* Copyright (C) 2010 by David Brownell */ /* * Simple utility to parse and dump ARM Cortex-M3 SWO trace output. Once the diff --git a/contrib/libdcc/dcc_stdio.c b/contrib/libdcc/dcc_stdio.c index 7da78c6471..9ad633b61c 100644 --- a/contrib/libdcc/dcc_stdio.c +++ b/contrib/libdcc/dcc_stdio.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2008 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -5,19 +7,6 @@ * spen@spen-soft.co.uk * * Copyright (C) 2008 by Frederik Kriewtz * * frederik@kriewitz.eu * - * * - * 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 . * ***************************************************************************/ #include "dcc_stdio.h" diff --git a/contrib/libdcc/dcc_stdio.h b/contrib/libdcc/dcc_stdio.h index f4a5d7e32e..3447b8c6bd 100644 --- a/contrib/libdcc/dcc_stdio.h +++ b/contrib/libdcc/dcc_stdio.h @@ -1,21 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2008 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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 . * ***************************************************************************/ #ifndef DCC_STDIO_H diff --git a/contrib/libdcc/example.c b/contrib/libdcc/example.c index 99b7bf6024..7c7d93670e 100644 --- a/contrib/libdcc/example.c +++ b/contrib/libdcc/example.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * Copyright (C) 2008 by Frederik Kriewtz * * frederik@kriewitz.eu * - * * - * 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 . * ***************************************************************************/ #include "dcc_stdio.h" diff --git a/contrib/list_example.c b/contrib/list_example.c index 0f62b864b5..4fcfcdf348 100644 --- a/contrib/list_example.c +++ b/contrib/list_example.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later /* Copyright (C) 2021 by Andreas Fritiofson */ /* diff --git a/contrib/loaders/Makefile b/contrib/loaders/Makefile index 0a637aff59..ae6a5ebad7 100644 --- a/contrib/loaders/Makefile +++ b/contrib/loaders/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + .PHONY: arm clean-arm all: arm stm8 diff --git a/contrib/loaders/checksum/Makefile b/contrib/loaders/checksum/Makefile index 623e42576e..5789a0824e 100644 --- a/contrib/loaders/checksum/Makefile +++ b/contrib/loaders/checksum/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../src/helper/bin2char.sh ARM_CROSS_COMPILE ?= arm-none-eabi- diff --git a/contrib/loaders/checksum/armv4_5_crc.s b/contrib/loaders/checksum/armv4_5_crc.s index 8f62dc89f9..b3ecb58472 100644 --- a/contrib/loaders/checksum/armv4_5_crc.s +++ b/contrib/loaders/checksum/armv4_5_crc.s @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ /* diff --git a/contrib/loaders/checksum/armv7m_crc.s b/contrib/loaders/checksum/armv7m_crc.s index 923875a089..8cb7f2dc17 100644 --- a/contrib/loaders/checksum/armv7m_crc.s +++ b/contrib/loaders/checksum/armv7m_crc.s @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ /* diff --git a/contrib/loaders/checksum/mips32.s b/contrib/loaders/checksum/mips32.s index 3073d87a34..52de547b45 100644 --- a/contrib/loaders/checksum/mips32.s +++ b/contrib/loaders/checksum/mips32.s @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .global main diff --git a/contrib/loaders/checksum/riscv_crc.c b/contrib/loaders/checksum/riscv_crc.c index e437b66168..9931af5ff6 100644 --- a/contrib/loaders/checksum/riscv_crc.c +++ b/contrib/loaders/checksum/riscv_crc.c @@ -1,7 +1,6 @@ -/* - * SPDX-License-Identifier: GPL-2.0-or-later - * Copyright (C) 2009-2021 Free Software Foundation, Inc. - */ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* Copyright (C) 2009-2021 Free Software Foundation, Inc. */ /* Copied from https://github.com/gcc-mirror/gcc/blob/master/libiberty/crc32.c * and then tweaked a little. */ diff --git a/contrib/loaders/debug/xscale/Makefile b/contrib/loaders/debug/xscale/Makefile index a0455c7331..cdecd144bd 100644 --- a/contrib/loaders/debug/xscale/Makefile +++ b/contrib/loaders/debug/xscale/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../../src/helper/bin2char.sh CROSS_COMPILE ?= arm-none-eabi- diff --git a/contrib/loaders/debug/xscale/debug_handler.S b/contrib/loaders/debug/xscale/debug_handler.S index 0f62d9c14d..9e1d65f93c 100644 --- a/contrib/loaders/debug/xscale/debug_handler.S +++ b/contrib/loaders/debug/xscale/debug_handler.S @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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 . * ***************************************************************************/ #include "protocol.h" diff --git a/contrib/loaders/debug/xscale/debug_handler.ld b/contrib/loaders/debug/xscale/debug_handler.ld index d943b13b3e..0e46cb13fb 100644 --- a/contrib/loaders/debug/xscale/debug_handler.ld +++ b/contrib/loaders/debug/xscale/debug_handler.ld @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* identify the Entry Point */ ENTRY(reset_handler) diff --git a/contrib/loaders/debug/xscale/protocol.h b/contrib/loaders/debug/xscale/protocol.h index cb01655ee1..bd29cf12fb 100644 --- a/contrib/loaders/debug/xscale/protocol.h +++ b/contrib/loaders/debug/xscale/protocol.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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 . * ***************************************************************************/ #define REG_R0 0 diff --git a/contrib/loaders/erase_check/Makefile b/contrib/loaders/erase_check/Makefile index 1a0fd9e3f5..d49c049c4d 100644 --- a/contrib/loaders/erase_check/Makefile +++ b/contrib/loaders/erase_check/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../src/helper/bin2char.sh ARM_CROSS_COMPILE ?= arm-none-eabi- diff --git a/contrib/loaders/erase_check/armv4_5_erase_check.s b/contrib/loaders/erase_check/armv4_5_erase_check.s index 6c7d27f058..dedadaa5d3 100644 --- a/contrib/loaders/erase_check/armv4_5_erase_check.s +++ b/contrib/loaders/erase_check/armv4_5_erase_check.s @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ /* diff --git a/contrib/loaders/erase_check/armv7m_erase_check.s b/contrib/loaders/erase_check/armv7m_erase_check.s index 3303c8778b..429b6939f0 100644 --- a/contrib/loaders/erase_check/armv7m_erase_check.s +++ b/contrib/loaders/erase_check/armv7m_erase_check.s @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ /* diff --git a/contrib/loaders/erase_check/stm8_erase_check.s b/contrib/loaders/erase_check/stm8_erase_check.s index 04cde5b1bf..116ac59f10 100644 --- a/contrib/loaders/erase_check/stm8_erase_check.s +++ b/contrib/loaders/erase_check/stm8_erase_check.s @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* -* Copyright (C) 2017 Ake Rehnman -* ake.rehnman(at)gmail.com -* -* 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 . -*/ + * Copyright (C) 2017 Ake Rehnman + * ake.rehnman(at)gmail.com + */ ;; ;; erase check memory code ;; diff --git a/contrib/loaders/flash/armv4_5_cfi_intel_16.s b/contrib/loaders/flash/armv4_5_cfi_intel_16.s index c35b6515f8..0c5611dc55 100644 --- a/contrib/loaders/flash/armv4_5_cfi_intel_16.s +++ b/contrib/loaders/flash/armv4_5_cfi_intel_16.s @@ -1,23 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/armv4_5_cfi_intel_32.s b/contrib/loaders/flash/armv4_5_cfi_intel_32.s index db477178a7..473a78234d 100644 --- a/contrib/loaders/flash/armv4_5_cfi_intel_32.s +++ b/contrib/loaders/flash/armv4_5_cfi_intel_32.s @@ -1,23 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/armv4_5_cfi_intel_8.s b/contrib/loaders/flash/armv4_5_cfi_intel_8.s index d50acd2ade..18f4bb811c 100644 --- a/contrib/loaders/flash/armv4_5_cfi_intel_8.s +++ b/contrib/loaders/flash/armv4_5_cfi_intel_8.s @@ -1,23 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/armv4_5_cfi_span_16.s b/contrib/loaders/flash/armv4_5_cfi_span_16.s index 532727140f..da02037f64 100644 --- a/contrib/loaders/flash/armv4_5_cfi_span_16.s +++ b/contrib/loaders/flash/armv4_5_cfi_span_16.s @@ -1,23 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/armv4_5_cfi_span_16_dq7.s b/contrib/loaders/flash/armv4_5_cfi_span_16_dq7.s index 919f6e1647..fb7679e4ce 100644 --- a/contrib/loaders/flash/armv4_5_cfi_span_16_dq7.s +++ b/contrib/loaders/flash/armv4_5_cfi_span_16_dq7.s @@ -1,23 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/armv4_5_cfi_span_32.s b/contrib/loaders/flash/armv4_5_cfi_span_32.s index c8f87b12b0..7e377e25fc 100644 --- a/contrib/loaders/flash/armv4_5_cfi_span_32.s +++ b/contrib/loaders/flash/armv4_5_cfi_span_32.s @@ -1,23 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/armv4_5_cfi_span_8.s b/contrib/loaders/flash/armv4_5_cfi_span_8.s index 46018e18b8..ad4ee267b9 100644 --- a/contrib/loaders/flash/armv4_5_cfi_span_8.s +++ b/contrib/loaders/flash/armv4_5_cfi_span_8.s @@ -1,23 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/armv7m_cfi_span_16.s b/contrib/loaders/flash/armv7m_cfi_span_16.s index d4915a78c3..0a5279e3db 100644 --- a/contrib/loaders/flash/armv7m_cfi_span_16.s +++ b/contrib/loaders/flash/armv7m_cfi_span_16.s @@ -1,23 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/armv7m_cfi_span_16_dq7.s b/contrib/loaders/flash/armv7m_cfi_span_16_dq7.s index 5b29a3bda7..592c811bcc 100644 --- a/contrib/loaders/flash/armv7m_cfi_span_16_dq7.s +++ b/contrib/loaders/flash/armv7m_cfi_span_16_dq7.s @@ -1,23 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2010 Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/armv7m_io.s b/contrib/loaders/flash/armv7m_io.s index f6dbbe9bf9..9d8439e1a6 100644 --- a/contrib/loaders/flash/armv7m_io.s +++ b/contrib/loaders/flash/armv7m_io.s @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2013 by Henrik Nilsson * * henrik.nilsson@bytequest.se * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/at91sam7x/at91sam7x_ocl_flash.script b/contrib/loaders/flash/at91sam7x/at91sam7x_ocl_flash.script index 85450c14c0..1099d83de9 100644 --- a/contrib/loaders/flash/at91sam7x/at91sam7x_ocl_flash.script +++ b/contrib/loaders/flash/at91sam7x/at91sam7x_ocl_flash.script @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + soft_reset_halt load_image at91sam7x_ocl.bin 0x200000 resume 0x200000 diff --git a/contrib/loaders/flash/at91sam7x/at91sam7x_ram.ld b/contrib/loaders/flash/at91sam7x/at91sam7x_ram.ld index 8cb21184f8..b093523781 100644 --- a/contrib/loaders/flash/at91sam7x/at91sam7x_ram.ld +++ b/contrib/loaders/flash/at91sam7x/at91sam7x_ram.ld @@ -1,32 +1,7 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. Neither the name of the author nor the names of its contributors may -* be used to endorse or promote products derived from this software -* without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -* THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -* SUCH DAMAGE. -* **************************************************************************** * * History: diff --git a/contrib/loaders/flash/at91sam7x/crt.s b/contrib/loaders/flash/at91sam7x/crt.s index 94ed66d738..77df43ce26 100644 --- a/contrib/loaders/flash/at91sam7x/crt.s +++ b/contrib/loaders/flash/at91sam7x/crt.s @@ -1,32 +1,7 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /**************************************************************************** * Copyright (c) 2006 by Michael Fischer. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. Neither the name of the author nor the names of its contributors may -* be used to endorse or promote products derived from this software -* without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -* THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -* SUCH DAMAGE. -* **************************************************************************** * * History: diff --git a/contrib/loaders/flash/at91sam7x/dcc.c b/contrib/loaders/flash/at91sam7x/dcc.c index a5c32e7e6c..ee95a34449 100644 --- a/contrib/loaders/flash/at91sam7x/dcc.c +++ b/contrib/loaders/flash/at91sam7x/dcc.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * - * * - * 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 . * ***************************************************************************/ #include "dcc.h" diff --git a/contrib/loaders/flash/at91sam7x/dcc.h b/contrib/loaders/flash/at91sam7x/dcc.h index 428bf49ff4..5baca6ca1f 100644 --- a/contrib/loaders/flash/at91sam7x/dcc.h +++ b/contrib/loaders/flash/at91sam7x/dcc.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * - * * - * 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 . * ***************************************************************************/ #ifndef dccH #define dccH diff --git a/contrib/loaders/flash/at91sam7x/main.c b/contrib/loaders/flash/at91sam7x/main.c index 47c9440827..a29c6e605b 100644 --- a/contrib/loaders/flash/at91sam7x/main.c +++ b/contrib/loaders/flash/at91sam7x/main.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * - * * - * 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 . * ***************************************************************************/ #include "platform.h" diff --git a/contrib/loaders/flash/at91sam7x/makefile b/contrib/loaders/flash/at91sam7x/makefile index 39482976ec..3d101c1a0e 100644 --- a/contrib/loaders/flash/at91sam7x/makefile +++ b/contrib/loaders/flash/at91sam7x/makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ############################################################################################## # Start of default section # diff --git a/contrib/loaders/flash/at91sam7x/ocl.h b/contrib/loaders/flash/at91sam7x/ocl.h index bd8a5f7a02..e458b5864a 100644 --- a/contrib/loaders/flash/at91sam7x/ocl.h +++ b/contrib/loaders/flash/at91sam7x/ocl.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * - * * - * 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 . * ***************************************************************************/ #ifndef OCL_H #define OCL_H diff --git a/contrib/loaders/flash/at91sam7x/platform.h b/contrib/loaders/flash/at91sam7x/platform.h index 3dfa4dc088..538df9b48d 100644 --- a/contrib/loaders/flash/at91sam7x/platform.h +++ b/contrib/loaders/flash/at91sam7x/platform.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * - * * - * 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 . * ***************************************************************************/ #ifndef platformH #define platformH diff --git a/contrib/loaders/flash/at91sam7x/samflash.c b/contrib/loaders/flash/at91sam7x/samflash.c index 30953942ab..fcb76fbf98 100644 --- a/contrib/loaders/flash/at91sam7x/samflash.c +++ b/contrib/loaders/flash/at91sam7x/samflash.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * - * * - * 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 . * ***************************************************************************/ #include "samflash.h" diff --git a/contrib/loaders/flash/at91sam7x/samflash.h b/contrib/loaders/flash/at91sam7x/samflash.h index 18973a70d8..059c2b2ea0 100644 --- a/contrib/loaders/flash/at91sam7x/samflash.h +++ b/contrib/loaders/flash/at91sam7x/samflash.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * - * * - * 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 . * ***************************************************************************/ #ifndef samflashH #define samflashH diff --git a/contrib/loaders/flash/at91sam7x/samregs.h b/contrib/loaders/flash/at91sam7x/samregs.h index b206fd28e4..3e34a8d6d9 100644 --- a/contrib/loaders/flash/at91sam7x/samregs.h +++ b/contrib/loaders/flash/at91sam7x/samregs.h @@ -1,32 +1,8 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /* * Copyright (C) 2005-2006 by egnite Software GmbH. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the names of - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE - * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * * For additional information see http://www.ethernut.de/ */ diff --git a/contrib/loaders/flash/bluenrg-x/Makefile b/contrib/loaders/flash/bluenrg-x/Makefile index 1a5cfc013f..81d479aa55 100644 --- a/contrib/loaders/flash/bluenrg-x/Makefile +++ b/contrib/loaders/flash/bluenrg-x/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../../src/helper/bin2char.sh CROSS_COMPILE ?= arm-none-eabi- diff --git a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c index f09f7f58ab..1bc72d5921 100644 --- a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c +++ b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* To be built with arm-none-eabi-gcc -c -mthumb -mcpu=cortex-m0 -O3 bluenrgx.c */ /* Then postprocess output of command "arm-none-eabi-objdump -d bluenrgx.o" to make a C array of bytes */ diff --git a/contrib/loaders/flash/cc26xx/Makefile b/contrib/loaders/flash/cc26xx/Makefile index 7cc1fb3c4d..550e1d098a 100644 --- a/contrib/loaders/flash/cc26xx/Makefile +++ b/contrib/loaders/flash/cc26xx/Makefile @@ -1,3 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause + +# Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + BIN2C = ../../../../src/helper/bin2char.sh CROSS_COMPILE ?= arm-none-eabi- diff --git a/contrib/loaders/flash/cc26xx/cc26x0/cc26x0r2f.lds b/contrib/loaders/flash/cc26xx/cc26x0/cc26x0r2f.lds index 9a126fc2bc..79cbfc4fcf 100644 --- a/contrib/loaders/flash/cc26xx/cc26x0/cc26x0r2f.lds +++ b/contrib/loaders/flash/cc26xx/cc26x0/cc26x0r2f.lds @@ -1,35 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /****************************************************************************** * * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ /* Entry Point */ diff --git a/contrib/loaders/flash/cc26xx/cc26x2/cc26x2r1f.lds b/contrib/loaders/flash/cc26xx/cc26x2/cc26x2r1f.lds index fb7cc56110..2394c0cc0c 100644 --- a/contrib/loaders/flash/cc26xx/cc26x2/cc26x2r1f.lds +++ b/contrib/loaders/flash/cc26xx/cc26x2/cc26x2r1f.lds @@ -1,35 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /****************************************************************************** * * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ /* Entry Point */ diff --git a/contrib/loaders/flash/cc26xx/flash.c b/contrib/loaders/flash/cc26xx/flash.c index c19cb735d9..affd029553 100644 --- a/contrib/loaders/flash/cc26xx/flash.c +++ b/contrib/loaders/flash/cc26xx/flash.c @@ -1,35 +1,9 @@ +// SPDX-License-Identifier: BSD-3-Clause + /****************************************************************************** * * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #include diff --git a/contrib/loaders/flash/cc26xx/flash.h b/contrib/loaders/flash/cc26xx/flash.h index dd0a3745a5..07acf26f2a 100644 --- a/contrib/loaders/flash/cc26xx/flash.h +++ b/contrib/loaders/flash/cc26xx/flash.h @@ -1,35 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /****************************************************************************** * * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_CC26XX_FLASH_H diff --git a/contrib/loaders/flash/cc26xx/flashloader.c b/contrib/loaders/flash/cc26xx/flashloader.c index 2eaf618647..8e9636d45b 100644 --- a/contrib/loaders/flash/cc26xx/flashloader.c +++ b/contrib/loaders/flash/cc26xx/flashloader.c @@ -1,35 +1,9 @@ +// SPDX-License-Identifier: BSD-3-Clause + /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #include diff --git a/contrib/loaders/flash/cc26xx/flashloader.h b/contrib/loaders/flash/cc26xx/flashloader.h index aec74aaa91..a6695576e7 100644 --- a/contrib/loaders/flash/cc26xx/flashloader.h +++ b/contrib/loaders/flash/cc26xx/flashloader.h @@ -1,35 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_CC26XX_FLASHLOADER_H diff --git a/contrib/loaders/flash/cc26xx/hw_regs.h b/contrib/loaders/flash/cc26xx/hw_regs.h index 830d3af257..78c81be242 100644 --- a/contrib/loaders/flash/cc26xx/hw_regs.h +++ b/contrib/loaders/flash/cc26xx/hw_regs.h @@ -1,35 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_CC26XX_HW_REGS_H diff --git a/contrib/loaders/flash/cc26xx/main.c b/contrib/loaders/flash/cc26xx/main.c index 13204b4580..6b626a3b84 100644 --- a/contrib/loaders/flash/cc26xx/main.c +++ b/contrib/loaders/flash/cc26xx/main.c @@ -1,35 +1,9 @@ +// SPDX-License-Identifier: BSD-3-Clause + /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #include diff --git a/contrib/loaders/flash/cc26xx/startup.c b/contrib/loaders/flash/cc26xx/startup.c index 53d8ea8c75..3117eb10a1 100644 --- a/contrib/loaders/flash/cc26xx/startup.c +++ b/contrib/loaders/flash/cc26xx/startup.c @@ -1,35 +1,9 @@ +// SPDX-License-Identifier: BSD-3-Clause + /****************************************************************************** * * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #include diff --git a/contrib/loaders/flash/cc3220sf/Makefile b/contrib/loaders/flash/cc3220sf/Makefile index d1dcc25fda..1c745770f3 100644 --- a/contrib/loaders/flash/cc3220sf/Makefile +++ b/contrib/loaders/flash/cc3220sf/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../../src/helper/bin2char.sh CROSS_COMPILE ?= arm-none-eabi- diff --git a/contrib/loaders/flash/cc3220sf/cc3220sf.s b/contrib/loaders/flash/cc3220sf/cc3220sf.s index cffcfa0532..ea82c85a7d 100644 --- a/contrib/loaders/flash/cc3220sf/cc3220sf.s +++ b/contrib/loaders/flash/cc3220sf/cc3220sf.s @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2017 by Texas Instruments, Inc. * - * * - * 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 . * ***************************************************************************/ /* Params: diff --git a/contrib/loaders/flash/cortex-m0.S b/contrib/loaders/flash/cortex-m0.S index b4416e783c..74b071dca8 100644 --- a/contrib/loaders/flash/cortex-m0.S +++ b/contrib/loaders/flash/cortex-m0.S @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2014 by Angus Gratton * * Derived from stm32f1x.S: @@ -5,19 +7,6 @@ * andreas.fritiofson@gmail.com * * Copyright (C) 2013 by Roman Dmitrienko * * me@iamroman.org * - * * - * 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 . * ***************************************************************************/ .text .syntax unified diff --git a/contrib/loaders/flash/efm32.S b/contrib/loaders/flash/efm32.S index c5de55c27a..b6938512a9 100644 --- a/contrib/loaders/flash/efm32.S +++ b/contrib/loaders/flash/efm32.S @@ -1,23 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * * Copyright (C) 2013 by Roman Dmitrienko * * me@iamroman.org * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/fespi/Makefile b/contrib/loaders/flash/fespi/Makefile index edecf0a729..d63b819f62 100644 --- a/contrib/loaders/flash/fespi/Makefile +++ b/contrib/loaders/flash/fespi/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../../src/helper/bin2char.sh CROSS_COMPILE ?= riscv64-unknown-elf- diff --git a/contrib/loaders/flash/fespi/riscv.lds b/contrib/loaders/flash/fespi/riscv.lds index 77fe0e5582..7473128bf7 100644 --- a/contrib/loaders/flash/fespi/riscv.lds +++ b/contrib/loaders/flash/fespi/riscv.lds @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + OUTPUT_ARCH( "riscv" ) SECTIONS diff --git a/contrib/loaders/flash/fespi/riscv_fespi.c b/contrib/loaders/flash/fespi/riscv_fespi.c index b6164330d3..17ae2fd22e 100644 --- a/contrib/loaders/flash/fespi/riscv_fespi.c +++ b/contrib/loaders/flash/fespi/riscv_fespi.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + #include #include #include diff --git a/contrib/loaders/flash/fespi/riscv_wrapper.S b/contrib/loaders/flash/fespi/riscv_wrapper.S index 4f632a76ec..4bc4fe6dd9 100644 --- a/contrib/loaders/flash/fespi/riscv_wrapper.S +++ b/contrib/loaders/flash/fespi/riscv_wrapper.S @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + #if __riscv_xlen == 64 # define LREG ld # define SREG sd diff --git a/contrib/loaders/flash/fm4/Makefile b/contrib/loaders/flash/fm4/Makefile index 207b9d0fa4..5e6593b46e 100644 --- a/contrib/loaders/flash/fm4/Makefile +++ b/contrib/loaders/flash/fm4/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../../src/helper/bin2char.sh CROSS_COMPILE ?= arm-none-eabi- diff --git a/contrib/loaders/flash/fm4/erase.S b/contrib/loaders/flash/fm4/erase.S index 6fdf81dc2a..666487d88c 100644 --- a/contrib/loaders/flash/fm4/erase.S +++ b/contrib/loaders/flash/fm4/erase.S @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Spansion FM4 flash sector erase algorithm * diff --git a/contrib/loaders/flash/fm4/fm4.h b/contrib/loaders/flash/fm4/fm4.h index 603aac8762..76a4f3321b 100644 --- a/contrib/loaders/flash/fm4/fm4.h +++ b/contrib/loaders/flash/fm4/fm4.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Spansion FM4 flash macros * diff --git a/contrib/loaders/flash/fm4/write.S b/contrib/loaders/flash/fm4/write.S index a8d01cde24..0819da7c3c 100644 --- a/contrib/loaders/flash/fm4/write.S +++ b/contrib/loaders/flash/fm4/write.S @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Spansion FM4 flash write algorithm * diff --git a/contrib/loaders/flash/fpga/xilinx_bscan_spi.py b/contrib/loaders/flash/fpga/xilinx_bscan_spi.py index 4246aa2f3a..408cfdd79f 100755 --- a/contrib/loaders/flash/fpga/xilinx_bscan_spi.py +++ b/contrib/loaders/flash/fpga/xilinx_bscan_spi.py @@ -1,17 +1,7 @@ #!/usr/bin/python3 -# +# SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (C) 2015 Robert Jordens -# -# 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. -# import unittest diff --git a/contrib/loaders/flash/gd32v/gd32vf103.inc b/contrib/loaders/flash/gd32v/gd32vf103.inc deleted file mode 100644 index d68b1737e6..0000000000 --- a/contrib/loaders/flash/gd32v/gd32vf103.inc +++ /dev/null @@ -1,8 +0,0 @@ -/* Autogenerated with ../../../../src/helper/bin2char.sh */ -0x6f,0x00,0x80,0x00,0x73,0x00,0x10,0x00,0x03,0x2b,0x06,0x00,0x63,0x0c,0x0b,0x04, -0x83,0x2a,0x46,0x00,0xb3,0x87,0x6a,0x41,0xe3,0x88,0x07,0xfe,0x03,0xdb,0x0a,0x00, -0x23,0x10,0x67,0x01,0x93,0x8a,0x2a,0x00,0x13,0x07,0x27,0x00,0x83,0x2b,0xc5,0x00, -0x93,0xf7,0x1b,0x00,0xe3,0x9c,0x07,0xfe,0x93,0xf7,0x4b,0x01,0x63,0x90,0x07,0x02, -0x63,0xe6,0xda,0x00,0x93,0x0a,0x06,0x00,0x93,0x8a,0x8a,0x00,0x23,0x22,0x56,0x01, -0x93,0x85,0xf5,0xff,0x63,0x88,0x05,0x00,0x6f,0xf0,0x1f,0xfb,0x13,0x05,0x00,0x00, -0x23,0x22,0xa6,0x00,0x13,0x85,0x0b,0x00,0x6f,0xf0,0xdf,0xf9, diff --git a/contrib/loaders/flash/gd32vf103/Makefile b/contrib/loaders/flash/gd32vf103/Makefile index 2c34e08c08..812fd8acaf 100644 --- a/contrib/loaders/flash/gd32vf103/Makefile +++ b/contrib/loaders/flash/gd32vf103/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../../src/helper/bin2char.sh CROSS_COMPILE ?= riscv-none-embed- diff --git a/contrib/loaders/flash/gd32vf103/gd32vf103.c b/contrib/loaders/flash/gd32vf103/gd32vf103.c index 69225a0267..927014c740 100644 --- a/contrib/loaders/flash/gd32vf103/gd32vf103.c +++ b/contrib/loaders/flash/gd32vf103/gd32vf103.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later #include diff --git a/contrib/loaders/flash/k1921vk01t.S b/contrib/loaders/flash/k1921vk01t.S index b8f0b53d5e..d8e3cd6fa3 100644 --- a/contrib/loaders/flash/k1921vk01t.S +++ b/contrib/loaders/flash/k1921vk01t.S @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2015 by Bogdan Kolbov * * kolbov@niiet.ru * - * * - * 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, write to the * - * Free Software Foundation, Inc. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/kinetis/Makefile b/contrib/loaders/flash/kinetis/Makefile index b240f53d44..d6c072bb4f 100644 --- a/contrib/loaders/flash/kinetis/Makefile +++ b/contrib/loaders/flash/kinetis/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../../src/helper/bin2char.sh CROSS_COMPILE ?= arm-none-eabi- diff --git a/contrib/loaders/flash/kinetis/kinetis_flash.s b/contrib/loaders/flash/kinetis/kinetis_flash.s index c8e6e05a89..5b9d3c69c9 100644 --- a/contrib/loaders/flash/kinetis/kinetis_flash.s +++ b/contrib/loaders/flash/kinetis/kinetis_flash.s @@ -1,19 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2015 by Ivan Meleca * * ivan@artekit.eu * * * * Copyright (C) 2016 by Tomas Vanek * * vanekt@fbl.cz * - * * - * 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. * ***************************************************************************/ /* Params: diff --git a/contrib/loaders/flash/kinetis_ke/Makefile b/contrib/loaders/flash/kinetis_ke/Makefile index 7d8dba8c73..17cbf3298b 100644 --- a/contrib/loaders/flash/kinetis_ke/Makefile +++ b/contrib/loaders/flash/kinetis_ke/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../../src/helper/bin2char.sh CROSS_COMPILE ?= arm-none-eabi- diff --git a/contrib/loaders/flash/kinetis_ke/kinetis_ke_flash.s b/contrib/loaders/flash/kinetis_ke/kinetis_ke_flash.s index 1fa761336a..f082b46496 100644 --- a/contrib/loaders/flash/kinetis_ke/kinetis_ke_flash.s +++ b/contrib/loaders/flash/kinetis_ke/kinetis_ke_flash.s @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2015 by Ivan Meleca * * ivan@artekit.eu * - * * - * 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. * ***************************************************************************/ /* Params: diff --git a/contrib/loaders/flash/kinetis_ke/kinetis_ke_watchdog.s b/contrib/loaders/flash/kinetis_ke/kinetis_ke_watchdog.s index 289662d075..e0ff0b1f17 100644 --- a/contrib/loaders/flash/kinetis_ke/kinetis_ke_watchdog.s +++ b/contrib/loaders/flash/kinetis_ke/kinetis_ke_watchdog.s @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2015 by Ivan Meleca * * ivan@artekit.eu * - * * - * 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. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/lpcspifi_erase.S b/contrib/loaders/flash/lpcspifi_erase.S index 350aa93cb8..70cdcfa28b 100644 --- a/contrib/loaders/flash/lpcspifi_erase.S +++ b/contrib/loaders/flash/lpcspifi_erase.S @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2012 by George Harris * * george@luminairecoffee.com * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/lpcspifi_init.S b/contrib/loaders/flash/lpcspifi_init.S index 9872892f5b..651298acef 100644 --- a/contrib/loaders/flash/lpcspifi_init.S +++ b/contrib/loaders/flash/lpcspifi_init.S @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2012 by George Harris * * george@luminairecoffee.com * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ /*************************************************************************** diff --git a/contrib/loaders/flash/lpcspifi_write.S b/contrib/loaders/flash/lpcspifi_write.S index 8435a20453..476e143aa4 100644 --- a/contrib/loaders/flash/lpcspifi_write.S +++ b/contrib/loaders/flash/lpcspifi_write.S @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2012 by George Harris * * george@luminairecoffee.com * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/max32xxx/Makefile b/contrib/loaders/flash/max32xxx/Makefile index 8f3f9242e4..1565c811c1 100644 --- a/contrib/loaders/flash/max32xxx/Makefile +++ b/contrib/loaders/flash/max32xxx/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../../src/helper/bin2char.sh CROSS_COMPILE ?= arm-none-eabi- diff --git a/contrib/loaders/flash/max32xxx/max32xxx.s b/contrib/loaders/flash/max32xxx/max32xxx.s index f5306d6c5d..38a4f12c32 100644 --- a/contrib/loaders/flash/max32xxx/max32xxx.s +++ b/contrib/loaders/flash/max32xxx/max32xxx.s @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2016 by Maxim Integrated * * Kevin Gillespie . * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/mdr32fx.S b/contrib/loaders/flash/mdr32fx.S index 73f4b6fde6..3a25d2029b 100644 --- a/contrib/loaders/flash/mdr32fx.S +++ b/contrib/loaders/flash/mdr32fx.S @@ -1,24 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * * * * Copyright (C) 2013 by Paul Fertser * * fercerpav@gmail.com * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/mrvlqspi_write.S b/contrib/loaders/flash/mrvlqspi_write.S index e1088e38da..5865da007b 100644 --- a/contrib/loaders/flash/mrvlqspi_write.S +++ b/contrib/loaders/flash/mrvlqspi_write.S @@ -1,24 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2014 by Mahavir Jain * * * * Adapted from (contrib/loaders/flash/lpcspifi_write.S): * * Copyright (C) 2012 by George Harris * * george@luminairecoffee.com * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/msp432/MSP432E4_FlashLibIf.h b/contrib/loaders/flash/msp432/MSP432E4_FlashLibIf.h index d406d6003d..aad39896b1 100644 --- a/contrib/loaders/flash/msp432/MSP432E4_FlashLibIf.h +++ b/contrib/loaders/flash/msp432/MSP432E4_FlashLibIf.h @@ -1,35 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /****************************************************************************** * * Copyright (C) 2014-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_MSP432_MSP432E4_FLASHLIBIF_H diff --git a/contrib/loaders/flash/msp432/MSP432P4_FlashLibIf.h b/contrib/loaders/flash/msp432/MSP432P4_FlashLibIf.h index c438097efc..b9334816dc 100644 --- a/contrib/loaders/flash/msp432/MSP432P4_FlashLibIf.h +++ b/contrib/loaders/flash/msp432/MSP432P4_FlashLibIf.h @@ -1,35 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /****************************************************************************** * * Copyright (C) 2014-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_MSP432_MSP432P4_FLASHLIBIF_H diff --git a/contrib/loaders/flash/msp432/Makefile b/contrib/loaders/flash/msp432/Makefile index 608333140a..cb1092c66b 100644 --- a/contrib/loaders/flash/msp432/Makefile +++ b/contrib/loaders/flash/msp432/Makefile @@ -1,3 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause + +# Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + BIN2C = ../../../../src/helper/bin2char.sh CROSS_COMPILE ?= arm-none-eabi- diff --git a/contrib/loaders/flash/msp432/driverlib.c b/contrib/loaders/flash/msp432/driverlib.c index ac6dfd4541..6f483b83da 100644 --- a/contrib/loaders/flash/msp432/driverlib.c +++ b/contrib/loaders/flash/msp432/driverlib.c @@ -1,35 +1,9 @@ +// SPDX-License-Identifier: BSD-3-Clause + /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #include diff --git a/contrib/loaders/flash/msp432/driverlib.h b/contrib/loaders/flash/msp432/driverlib.h index 23ba7b520a..1a087373f3 100644 --- a/contrib/loaders/flash/msp432/driverlib.h +++ b/contrib/loaders/flash/msp432/driverlib.h @@ -1,35 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_MSP432_DRIVERLIB_H diff --git a/contrib/loaders/flash/msp432/main_msp432e4x.c b/contrib/loaders/flash/msp432/main_msp432e4x.c index 23540ac606..7974f48c77 100644 --- a/contrib/loaders/flash/msp432/main_msp432e4x.c +++ b/contrib/loaders/flash/msp432/main_msp432e4x.c @@ -1,35 +1,9 @@ +// SPDX-License-Identifier: BSD-3-Clause + /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #include diff --git a/contrib/loaders/flash/msp432/main_msp432p401x.c b/contrib/loaders/flash/msp432/main_msp432p401x.c index 7992f11686..47fb7fa476 100644 --- a/contrib/loaders/flash/msp432/main_msp432p401x.c +++ b/contrib/loaders/flash/msp432/main_msp432p401x.c @@ -1,35 +1,9 @@ +// SPDX-License-Identifier: BSD-3-Clause + /****************************************************************************** * * Copyright (C) 2013-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #include diff --git a/contrib/loaders/flash/msp432/main_msp432p411x.c b/contrib/loaders/flash/msp432/main_msp432p411x.c index be1f709760..efc05a3b78 100644 --- a/contrib/loaders/flash/msp432/main_msp432p411x.c +++ b/contrib/loaders/flash/msp432/main_msp432p411x.c @@ -1,35 +1,9 @@ +// SPDX-License-Identifier: BSD-3-Clause + /****************************************************************************** * * Copyright (C) 2013-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #include diff --git a/contrib/loaders/flash/msp432/msp432e4x.h b/contrib/loaders/flash/msp432/msp432e4x.h index 2a9d15511e..c0bc7b4fc3 100644 --- a/contrib/loaders/flash/msp432/msp432e4x.h +++ b/contrib/loaders/flash/msp432/msp432e4x.h @@ -1,35 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_MSP432_MSP432E4X_H diff --git a/contrib/loaders/flash/msp432/msp432e4x/msp432e4x.lds b/contrib/loaders/flash/msp432/msp432e4x/msp432e4x.lds index af97458e63..2782209707 100644 --- a/contrib/loaders/flash/msp432/msp432e4x/msp432e4x.lds +++ b/contrib/loaders/flash/msp432/msp432e4x/msp432e4x.lds @@ -1,35 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ MEMORY { diff --git a/contrib/loaders/flash/msp432/msp432p401x.h b/contrib/loaders/flash/msp432/msp432p401x.h index ca219fdd66..b8ccea8d9a 100644 --- a/contrib/loaders/flash/msp432/msp432p401x.h +++ b/contrib/loaders/flash/msp432/msp432p401x.h @@ -1,35 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /****************************************************************************** * * Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_MSP432_MSP432P401X_H diff --git a/contrib/loaders/flash/msp432/msp432p401x/msp432p401x.lds b/contrib/loaders/flash/msp432/msp432p401x/msp432p401x.lds index f9d04ed885..178eaf403f 100644 --- a/contrib/loaders/flash/msp432/msp432p401x/msp432p401x.lds +++ b/contrib/loaders/flash/msp432/msp432p401x/msp432p401x.lds @@ -1,35 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /****************************************************************************** * * Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ MEMORY { diff --git a/contrib/loaders/flash/msp432/msp432p411x.h b/contrib/loaders/flash/msp432/msp432p411x.h index 6482dd3331..3225fa45f2 100644 --- a/contrib/loaders/flash/msp432/msp432p411x.h +++ b/contrib/loaders/flash/msp432/msp432p411x.h @@ -1,35 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /****************************************************************************** * * Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #ifndef OPENOCD_LOADERS_FLASH_MSP432_MSP432P411X_H diff --git a/contrib/loaders/flash/msp432/msp432p411x/msp432p411x.lds b/contrib/loaders/flash/msp432/msp432p411x/msp432p411x.lds index 0e7aa2dee5..cec3c53f48 100644 --- a/contrib/loaders/flash/msp432/msp432p411x/msp432p411x.lds +++ b/contrib/loaders/flash/msp432/msp432p411x/msp432p411x.lds @@ -1,35 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /****************************************************************************** * * Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ MEMORY { diff --git a/contrib/loaders/flash/msp432/startup_msp432e4.c b/contrib/loaders/flash/msp432/startup_msp432e4.c index 494da46e7d..49789609fc 100644 --- a/contrib/loaders/flash/msp432/startup_msp432e4.c +++ b/contrib/loaders/flash/msp432/startup_msp432e4.c @@ -1,35 +1,9 @@ +// SPDX-License-Identifier: BSD-3-Clause + /****************************************************************************** * * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #include diff --git a/contrib/loaders/flash/msp432/startup_msp432p4.c b/contrib/loaders/flash/msp432/startup_msp432p4.c index 09103b0e43..350fd35e8a 100644 --- a/contrib/loaders/flash/msp432/startup_msp432p4.c +++ b/contrib/loaders/flash/msp432/startup_msp432p4.c @@ -1,35 +1,9 @@ +// SPDX-License-Identifier: BSD-3-Clause + /****************************************************************************** * * Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/ * -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the -* distribution. -* -* Neither the name of Texas Instruments Incorporated nor the names of -* its contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* ******************************************************************************/ #include diff --git a/contrib/loaders/flash/npcx/npcx_algo.inc b/contrib/loaders/flash/npcx/npcx_algo.inc index 4312fdb1b4..46b79d8d9c 100644 --- a/contrib/loaders/flash/npcx/npcx_algo.inc +++ b/contrib/loaders/flash/npcx/npcx_algo.inc @@ -1,60 +1,70 @@ /* Autogenerated with ../../../../src/helper/bin2char.sh */ -0x08,0xb5,0xdf,0xf8,0x08,0xd0,0x00,0xf0,0x2f,0xf9,0x00,0x00,0x48,0x15,0x0c,0x20, -0x03,0x4b,0x18,0x70,0x19,0x72,0x08,0x33,0x1a,0x78,0xd2,0x09,0xfc,0xd1,0x70,0x47, -0x16,0x00,0x02,0x40,0x70,0xb5,0x11,0x4c,0x23,0x78,0x03,0xf0,0xfd,0x03,0x23,0x70, -0xc0,0x21,0x05,0x20,0xff,0xf7,0xec,0xff,0x0d,0x4a,0x0e,0x49,0x6f,0xf0,0x7f,0x43, -0x6f,0xf0,0x2e,0x05,0x10,0x46,0x15,0x70,0x06,0x78,0xf6,0x09,0xfc,0xd1,0x0e,0x78, -0xf6,0x07,0x01,0xd5,0x01,0x3b,0xf6,0xd1,0x22,0x78,0x42,0xf0,0x02,0x02,0x00,0x2b, -0x22,0x70,0x0c,0xbf,0x03,0x20,0x00,0x20,0x70,0xbd,0x00,0xbf,0x1f,0x00,0x02,0x40, +0x08,0xb5,0xdf,0xf8,0x08,0xd0,0x00,0xf0,0x95,0xf9,0x00,0x00,0xec,0x15,0x0c,0x20, +0x03,0x4b,0x18,0x70,0x08,0x33,0x19,0x70,0x1a,0x78,0xd2,0x09,0xfc,0xd1,0x70,0x47, +0x16,0x00,0x02,0x40,0x13,0x4b,0x14,0x49,0x1a,0x68,0xea,0xb1,0x1a,0x68,0x01,0x2a, +0x1e,0xd0,0x1b,0x68,0x02,0x2b,0x1b,0xd1,0x10,0x4b,0x1a,0x78,0x50,0xb1,0x02,0xf0, +0xf7,0x02,0x1a,0x70,0x01,0x22,0x08,0x78,0x01,0x23,0x93,0x40,0x03,0x43,0xdb,0xb2, +0x0b,0x70,0x70,0x47,0x42,0xf0,0x08,0x02,0x1a,0x70,0x01,0x22,0x08,0x78,0x01,0x23, +0x93,0x40,0x20,0xea,0x03,0x03,0xf3,0xe7,0x01,0x22,0x00,0x28,0xf6,0xd0,0xea,0xe7, +0x00,0x22,0xfa,0xe7,0x00,0x00,0x0c,0x20,0x1f,0x00,0x02,0x40,0x43,0x00,0x02,0x40, +0x73,0xb5,0x04,0x46,0x00,0x20,0x15,0x46,0x0e,0x46,0xff,0xf7,0xcb,0xff,0x0f,0x4b, +0x01,0x94,0xc4,0xf3,0x07,0x44,0x1c,0x70,0x9d,0xf8,0x05,0x20,0x5a,0x70,0x9d,0xf8, +0x04,0x20,0x9a,0x70,0xf3,0x21,0x02,0x20,0xff,0xf7,0xb2,0xff,0x2c,0x46,0x63,0x1b, +0xb3,0x42,0x05,0xd3,0x01,0x20,0x02,0xb0,0xbd,0xe8,0x70,0x40,0xff,0xf7,0xb2,0xbf, +0xe0,0x21,0x14,0xf8,0x01,0x0b,0xff,0xf7,0xa3,0xff,0xf0,0xe7,0x1a,0x00,0x02,0x40, +0x08,0x4b,0x1b,0x68,0x02,0x2b,0x08,0x4b,0x07,0xd1,0x08,0x4a,0x80,0x21,0x11,0x70, +0xc0,0x22,0x1a,0x70,0x00,0x22,0x1a,0x71,0x70,0x47,0x1a,0x78,0x42,0xf0,0x80,0x02, +0x1a,0x70,0x70,0x47,0x00,0x00,0x0c,0x20,0x10,0x30,0x0c,0x40,0x00,0x30,0x0c,0x40, +0x38,0xb5,0x00,0x20,0xff,0xf7,0x8e,0xff,0xc0,0x21,0x05,0x20,0xff,0xf7,0x80,0xff, +0x0b,0x4b,0x0c,0x4a,0x6f,0xf0,0x7f,0x44,0x6f,0xf0,0x2e,0x00,0x19,0x46,0x18,0x70, +0x0d,0x78,0xed,0x09,0xfc,0xd1,0x15,0x78,0xed,0x07,0x01,0xd5,0x01,0x3c,0xf6,0xd1, +0x01,0x20,0xff,0xf7,0x77,0xff,0x00,0x2c,0x0c,0xbf,0x03,0x20,0x00,0x20,0x38,0xbd, 0x1e,0x00,0x02,0x40,0x1a,0x00,0x02,0x40,0x08,0xb5,0xc0,0x21,0x06,0x20,0xff,0xf7, -0xc7,0xff,0xff,0xf7,0xcf,0xff,0x28,0xb9,0x03,0x4b,0x1b,0x78,0x13,0xf0,0x02,0x0f, -0x08,0xbf,0x02,0x20,0x08,0xbd,0x00,0xbf,0x1a,0x00,0x02,0x40,0xf8,0xb5,0x12,0x4c, -0x23,0x78,0x03,0xf0,0xfd,0x03,0x23,0x70,0x10,0x4b,0x17,0x46,0xc0,0xf3,0x07,0x42, -0x1a,0x70,0xc0,0xf3,0x07,0x22,0xc0,0xb2,0x03,0xf8,0x01,0x2c,0x0e,0x46,0x03,0xf8, -0x02,0x0c,0xe8,0x21,0x02,0x20,0xff,0xf7,0xa3,0xff,0x00,0x25,0xae,0x42,0x04,0xd8, -0x23,0x78,0x43,0xf0,0x02,0x03,0x23,0x70,0xf8,0xbd,0x78,0x5d,0xe0,0x21,0xff,0xf7, -0x97,0xff,0x01,0x35,0xf2,0xe7,0x00,0xbf,0x1f,0x00,0x02,0x40,0x19,0x00,0x02,0x40, -0x70,0x47,0x2d,0xe9,0xf0,0x41,0x00,0xf1,0xff,0x06,0x26,0xf0,0xff,0x06,0x34,0x1a, -0x8c,0x42,0x28,0xbf,0x0c,0x46,0x80,0x46,0x0d,0x46,0x17,0x46,0x5c,0xb1,0xff,0xf7, -0xb3,0xff,0x58,0xb9,0x3a,0x46,0xa1,0xb2,0x40,0x46,0xff,0xf7,0xbf,0xff,0xff,0xf7, -0x81,0xff,0x18,0xb9,0x27,0x44,0x2c,0x1b,0x14,0xb9,0x20,0x46,0xbd,0xe8,0xf0,0x81, -0xb4,0xf5,0x80,0x7f,0x25,0x46,0x28,0xbf,0x4f,0xf4,0x80,0x75,0xff,0xf7,0x9c,0xff, -0x00,0x28,0xf3,0xd1,0x3a,0x46,0xa9,0xb2,0x30,0x46,0xff,0xf7,0xa7,0xff,0xff,0xf7, -0x69,0xff,0x00,0x28,0xea,0xd1,0x2f,0x44,0x2e,0x44,0x64,0x1b,0xe4,0xe7,0x00,0x00, -0x2d,0xe9,0xf0,0x47,0x14,0x4e,0x15,0x4f,0xdf,0xf8,0x54,0x80,0x05,0x46,0x0c,0x46, -0x8a,0x46,0x05,0xeb,0x04,0x09,0xa9,0xeb,0x0a,0x09,0xba,0xf1,0x00,0x0f,0x02,0xd1, -0x50,0x46,0xbd,0xe8,0xf0,0x87,0xff,0xf7,0x77,0xff,0x00,0x28,0xf9,0xd1,0xc9,0xf3, -0x07,0x43,0x33,0x70,0xc9,0xf3,0x07,0x23,0x5f,0xfa,0x89,0xf9,0x3b,0x70,0xc8,0x21, -0x20,0x20,0x88,0xf8,0x00,0x90,0xff,0xf7,0x33,0xff,0xff,0xf7,0x3b,0xff,0x00,0x28, -0xe7,0xd1,0xaa,0xf5,0x80,0x5a,0xdc,0xe7,0x19,0x00,0x02,0x40,0x18,0x00,0x02,0x40, -0x17,0x00,0x02,0x40,0x08,0xb5,0xff,0xf7,0x57,0xff,0x38,0xb9,0xc0,0x21,0xc7,0x20, -0xff,0xf7,0x1e,0xff,0xbd,0xe8,0x08,0x40,0xff,0xf7,0x24,0xbf,0x08,0xbd,0x00,0x00, -0x38,0xb5,0xff,0xf7,0x49,0xff,0x04,0x46,0xc0,0xb9,0x0d,0x4b,0x0d,0x4d,0xf2,0x21, -0x28,0x70,0x18,0x70,0x01,0x20,0xff,0xf7,0x0b,0xff,0xff,0xf7,0x13,0xff,0x04,0x46, -0x60,0xb9,0xc1,0x21,0x05,0x20,0xff,0xf7,0x03,0xff,0x2b,0x78,0x2b,0xb9,0xc1,0x21, -0x35,0x20,0xff,0xf7,0xfd,0xfe,0x2b,0x78,0x03,0xb1,0x02,0x24,0x20,0x46,0x38,0xbd, -0x1b,0x00,0x02,0x40,0x1a,0x00,0x02,0x40,0x10,0xb5,0xc3,0x21,0x04,0x46,0x9f,0x20, -0xff,0xf7,0xee,0xfe,0x06,0x4b,0x07,0x4a,0x19,0x78,0x01,0x33,0x00,0x20,0x1b,0x78, -0x12,0x78,0x1b,0x02,0x43,0xea,0x01,0x43,0x13,0x43,0x23,0x60,0x10,0xbd,0x00,0xbf, -0x1a,0x00,0x02,0x40,0x1c,0x00,0x02,0x40,0x08,0xb5,0x10,0x22,0x00,0x21,0x00,0xf0, -0x4d,0xf8,0x00,0x20,0x08,0xbd,0x00,0x00,0x73,0xb5,0x21,0x48,0x20,0x4c,0xff,0xf7, -0xf3,0xff,0x20,0x4a,0x13,0x78,0x43,0xf0,0x80,0x03,0x13,0x70,0xff,0xf7,0xb0,0xff, -0x05,0x46,0x58,0xb9,0x1c,0x4e,0xe3,0x68,0x00,0x2b,0xfc,0xd0,0xa3,0x68,0x01,0x3b, -0x03,0x2b,0x2a,0xd8,0xdf,0xe8,0x03,0xf0,0x04,0x18,0x20,0x23,0xe5,0x60,0xfd,0xe7, -0x01,0xa8,0xff,0xf7,0xc1,0xff,0xa8,0xb9,0x01,0x9b,0x33,0x70,0x1a,0x0a,0x1b,0x0c, -0x72,0x70,0xb3,0x70,0xf0,0x70,0x23,0x7b,0x25,0x73,0x63,0x7b,0x65,0x73,0xa3,0x7b, -0xa5,0x73,0xe3,0x7b,0xe5,0x73,0xde,0xe7,0x20,0x68,0x61,0x68,0xff,0xf7,0x48,0xff, -0x00,0x28,0xf0,0xd0,0xe0,0x60,0xfe,0xe7,0xff,0xf7,0x74,0xff,0xf8,0xe7,0x20,0x68, -0x61,0x68,0x32,0x46,0xff,0xf7,0x05,0xff,0xf2,0xe7,0x01,0x20,0xf2,0xe7,0x00,0xbf, -0x00,0x00,0x0c,0x20,0x10,0x30,0x0c,0x40,0x10,0x00,0x0c,0x20,0xf0,0xb5,0x05,0x00, -0x83,0x07,0x4e,0xd0,0x54,0x1e,0x00,0x2a,0x46,0xd0,0x0a,0x06,0x12,0x0e,0x03,0x00, -0x03,0x26,0x02,0xe0,0x01,0x35,0x01,0x3c,0x3e,0xd3,0x01,0x33,0x2a,0x70,0x33,0x42, -0xf8,0xd1,0x03,0x2c,0x2f,0xd9,0xff,0x22,0x0a,0x40,0x15,0x02,0x15,0x43,0x2a,0x04, -0x15,0x43,0x0f,0x2c,0x38,0xd9,0x27,0x00,0x10,0x3f,0x3f,0x09,0x3e,0x01,0xb4,0x46, -0x1e,0x00,0x1a,0x00,0x10,0x36,0x66,0x44,0x15,0x60,0x55,0x60,0x95,0x60,0xd5,0x60, -0x10,0x32,0xb2,0x42,0xf8,0xd1,0x0f,0x26,0x0c,0x22,0x01,0x37,0x3f,0x01,0x26,0x40, -0xdb,0x19,0x37,0x00,0x22,0x42,0x1a,0xd0,0x3e,0x1f,0xb6,0x08,0xb4,0x00,0xa4,0x46, -0x1a,0x00,0x1c,0x1d,0x64,0x44,0x20,0xc2,0xa2,0x42,0xfc,0xd1,0x03,0x24,0x01,0x36, -0xb6,0x00,0x9b,0x19,0x3c,0x40,0x00,0x2c,0x06,0xd0,0x09,0x06,0x1c,0x19,0x09,0x0e, -0x19,0x70,0x01,0x33,0x9c,0x42,0xfb,0xd1,0xf0,0xbc,0x02,0xbc,0x08,0x47,0x34,0x00, -0xf1,0xe7,0x14,0x00,0x03,0x00,0xbc,0xe7,0x27,0x00,0xdd,0xe7, +0x5f,0xff,0xff,0xf7,0xd5,0xff,0x28,0xb9,0x03,0x4b,0x1b,0x78,0x13,0xf0,0x02,0x0f, +0x08,0xbf,0x02,0x20,0x08,0xbd,0x00,0xbf,0x1a,0x00,0x02,0x40,0x70,0x47,0x00,0x00, +0x38,0xb5,0x17,0x4c,0xc1,0x21,0x05,0x20,0xff,0xf7,0x4a,0xff,0x25,0x78,0xc1,0x21, +0x35,0x20,0xff,0xf7,0x45,0xff,0x23,0x78,0xed,0xb2,0xdb,0xb2,0x05,0xb9,0xd3,0xb1, +0xff,0xf7,0xda,0xff,0xd0,0xb9,0x0f,0x4b,0x20,0x70,0xf2,0x21,0x18,0x70,0x01,0x20, +0xff,0xf7,0x36,0xff,0xff,0xf7,0xac,0xff,0x80,0xb9,0xc1,0x21,0x05,0x20,0xff,0xf7, +0x2f,0xff,0x25,0x78,0xc1,0x21,0x35,0x20,0xff,0xf7,0x2a,0xff,0x23,0x78,0xed,0xb2, +0xdb,0xb2,0x15,0xb9,0x0b,0xb9,0x00,0x20,0x38,0xbd,0x02,0x20,0x38,0xbd,0x00,0xbf, +0x1a,0x00,0x02,0x40,0x1b,0x00,0x02,0x40,0x2d,0xe9,0xf8,0x43,0x81,0x46,0x0d,0x46, +0x90,0x46,0xff,0xf7,0x75,0xff,0xff,0xf7,0xc3,0xff,0x06,0x46,0xb8,0xb9,0x09,0xf1, +0xff,0x07,0x27,0xf0,0xff,0x07,0xa7,0xeb,0x09,0x04,0xac,0x42,0x28,0xbf,0x2c,0x46, +0x5c,0xb1,0xff,0xf7,0xa1,0xff,0x10,0xbb,0x42,0x46,0xa1,0xb2,0x48,0x46,0xff,0xf7, +0x37,0xff,0xff,0xf7,0x75,0xff,0xd0,0xb9,0xa0,0x44,0x2c,0x1b,0x14,0xb9,0x30,0x46, +0xbd,0xe8,0xf8,0x83,0xff,0xf7,0x90,0xff,0x88,0xb9,0xb4,0xf5,0x80,0x7f,0x25,0x46, +0x28,0xbf,0x4f,0xf4,0x80,0x75,0x42,0x46,0xa9,0xb2,0x38,0x46,0xff,0xf7,0x20,0xff, +0xff,0xf7,0x5e,0xff,0x18,0xb9,0xa8,0x44,0x2f,0x44,0x64,0x1b,0xe6,0xe7,0x06,0x46, +0xe5,0xe7,0x00,0x00,0x2d,0xe9,0xf7,0x4f,0x06,0x46,0x0d,0x46,0xff,0xf7,0x38,0xff, +0xff,0xf7,0x86,0xff,0x82,0x46,0x58,0xb9,0x15,0x4f,0xdf,0xf8,0x58,0x80,0xdf,0xf8, +0x58,0x90,0xab,0x46,0x74,0x19,0xa4,0xeb,0x0b,0x04,0xbb,0xf1,0x00,0x0f,0x03,0xd1, +0x50,0x46,0x03,0xb0,0xbd,0xe8,0xf0,0x8f,0xff,0xf7,0x5e,0xff,0xa8,0xb9,0x01,0x94, +0xc4,0xf3,0x07,0x44,0x3c,0x70,0x9d,0xf8,0x05,0x30,0x88,0xf8,0x00,0x30,0x9d,0xf8, +0x04,0x30,0x89,0xf8,0x00,0x30,0xf3,0x21,0x20,0x20,0xff,0xf7,0xb1,0xfe,0xff,0xf7, +0x27,0xff,0x10,0xb9,0xab,0xf5,0x80,0x5b,0xdc,0xe7,0x82,0x46,0xe0,0xe7,0x00,0xbf, +0x1a,0x00,0x02,0x40,0x1b,0x00,0x02,0x40,0x1c,0x00,0x02,0x40,0x08,0xb5,0xff,0xf7, +0xff,0xfe,0xff,0xf7,0x4d,0xff,0x50,0xb9,0xff,0xf7,0x36,0xff,0x38,0xb9,0xc0,0x21, +0xc7,0x20,0xff,0xf7,0x95,0xfe,0xbd,0xe8,0x08,0x40,0xff,0xf7,0x09,0xbf,0x08,0xbd, +0x10,0xb5,0x04,0x46,0xff,0xf7,0xec,0xfe,0xc3,0x21,0x9f,0x20,0xff,0xf7,0x88,0xfe, +0x06,0x4b,0x07,0x4a,0x19,0x78,0x01,0x33,0x00,0x20,0x1b,0x78,0x12,0x78,0x1b,0x02, +0x43,0xea,0x01,0x43,0x13,0x43,0x23,0x60,0x10,0xbd,0x00,0xbf,0x1a,0x00,0x02,0x40, +0x1c,0x00,0x02,0x40,0x08,0xb5,0x14,0x22,0x00,0x21,0x00,0xf0,0x41,0xf8,0x00,0x20, +0x08,0xbd,0x00,0x00,0x73,0xb5,0x1c,0x48,0x1b,0x4e,0x1c,0x4d,0xff,0xf7,0xf2,0xff, +0x34,0x46,0x33,0x69,0x00,0x2b,0xfc,0xd0,0xf3,0x68,0x01,0x3b,0x03,0x2b,0x29,0xd8, +0xdf,0xe8,0x03,0xf0,0x02,0x17,0x1f,0x22,0x01,0xa8,0xff,0xf7,0xc9,0xff,0xb0,0xb9, +0x01,0x9b,0x2b,0x70,0x19,0x0a,0x1b,0x0c,0x69,0x70,0xab,0x70,0xe8,0x70,0x23,0x7c, +0x00,0x23,0x23,0x74,0x62,0x7c,0x63,0x74,0xa2,0x7c,0xa3,0x74,0xe2,0x7c,0xe3,0x74, +0xdf,0xe7,0x60,0x68,0xa1,0x68,0xff,0xf7,0x65,0xff,0x00,0x28,0xef,0xd0,0x20,0x61, +0xfe,0xe7,0xff,0xf7,0x9b,0xff,0xf8,0xe7,0x60,0x68,0xa1,0x68,0x2a,0x46,0xff,0xf7, +0x1b,0xff,0xf2,0xe7,0x01,0x20,0xf2,0xe7,0x00,0x00,0x0c,0x20,0x14,0x00,0x0c,0x20, +0xf0,0xb5,0x83,0x07,0x47,0xd0,0x54,0x1e,0x00,0x2a,0x41,0xd0,0x0d,0x06,0x2d,0x0e, +0x02,0x00,0x03,0x26,0x02,0xe0,0x1a,0x00,0x01,0x3c,0x39,0xd3,0x53,0x1c,0x15,0x70, +0x33,0x42,0xf8,0xd1,0x03,0x2c,0x2a,0xd9,0xff,0x22,0x0a,0x40,0x15,0x02,0x15,0x43, +0x2a,0x04,0x15,0x43,0x0f,0x2c,0x14,0xd9,0x27,0x00,0x1a,0x00,0x10,0x3f,0x3e,0x09, +0x01,0x36,0x36,0x01,0x9e,0x19,0x15,0x60,0x55,0x60,0x95,0x60,0xd5,0x60,0x10,0x32, +0x96,0x42,0xf8,0xd1,0x0f,0x22,0x97,0x43,0x10,0x37,0xdb,0x19,0x14,0x40,0x03,0x2c, +0x0d,0xd9,0x1a,0x00,0x27,0x1f,0xbe,0x08,0x01,0x36,0xb6,0x00,0x9e,0x19,0x20,0xc2, +0xb2,0x42,0xfc,0xd1,0x03,0x22,0x97,0x43,0x04,0x37,0xdb,0x19,0x14,0x40,0x00,0x2c, +0x06,0xd0,0x09,0x06,0x1c,0x19,0x09,0x0e,0x19,0x70,0x01,0x33,0x9c,0x42,0xfb,0xd1, +0xf0,0xbc,0x02,0xbc,0x08,0x47,0x14,0x00,0x03,0x00,0xc3,0xe7, diff --git a/contrib/loaders/flash/npcx/npcx_flash.c b/contrib/loaders/flash/npcx/npcx_flash.c index d60624ae8f..6df01b2d43 100644 --- a/contrib/loaders/flash/npcx/npcx_flash.c +++ b/contrib/loaders/flash/npcx/npcx_flash.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2020 by Nuvoton Technology Corporation @@ -10,9 +10,29 @@ #include #include "npcx_flash.h" +/* flashloader parameter structure */ +__attribute__ ((section(".buffers.g_cfg"))) +static volatile struct npcx_flash_params g_cfg; +/* data buffer */ +__attribute__ ((section(".buffers.g_buf"))) +static uint8_t g_buf[NPCX_FLASH_LOADER_BUFFER_SIZE]; + /*---------------------------------------------------------------------------- * NPCX flash driver *----------------------------------------------------------------------------*/ +static void flash_init(void) +{ + if (g_cfg.fiu_ver == NPCX_FIU_NPCK) { + /* Set pinmux to SHD flash */ + NPCX_DEVCNT = 0x80; + NPCX_DEVALT(0) = 0xC0; + NPCX_DEVALT(4) = 0x00; + } else { + /* Avoid F_CS0 toggles while programming the internal flash. */ + NPCX_SET_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_NO_F_SPI); + } +} + static void flash_execute_cmd(uint8_t code, uint8_t cts) { /* Set UMA code */ @@ -26,11 +46,26 @@ static void flash_execute_cmd(uint8_t code, uint8_t cts) static void flash_cs_level(uint8_t level) { + int sw_cs = 0; + + if (g_cfg.fiu_ver == NPCX_FIU_NPCX) { + sw_cs = 1; + } else if (g_cfg.fiu_ver == NPCX_FIU_NPCX_V2) { + sw_cs = 0; + } else if (g_cfg.fiu_ver == NPCX_FIU_NPCK) { + sw_cs = 1; + /* Unlock UMA before pulling down CS in NPCK series */ + if (level) + NPCX_CLEAR_BIT(NPCX_FIU_MSR_IE_CFG, NPCX_FIU_MSR_IE_CFG_UMA_BLOCK); + else + NPCX_SET_BIT(NPCX_FIU_MSR_IE_CFG, NPCX_FIU_MSR_IE_CFG_UMA_BLOCK); + } + /* Program chip select pin to high/low level */ if (level) - NPCX_SET_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_SW_CS1); + NPCX_SET_BIT(NPCX_UMA_ECTS, sw_cs); else - NPCX_CLEAR_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_SW_CS1); + NPCX_CLEAR_BIT(NPCX_UMA_ECTS, sw_cs); } static void flash_set_address(uint32_t dest_addr) @@ -38,15 +73,15 @@ static void flash_set_address(uint32_t dest_addr) uint8_t *addr = (uint8_t *)&dest_addr; /* Set target flash address */ - NPCX_UMA_AB2 = addr[2]; - NPCX_UMA_AB1 = addr[1]; - NPCX_UMA_AB0 = addr[0]; + NPCX_UMA_DB0 = addr[2]; + NPCX_UMA_DB1 = addr[1]; + NPCX_UMA_DB2 = addr[0]; } -void delay(uint32_t i) +static void delay(uint32_t i) { while (i--) - ; + __asm__ volatile ("nop"); } static int flash_wait_ready(uint32_t timeout) @@ -104,7 +139,7 @@ static void flash_burst_write(uint32_t dest_addr, uint16_t bytes, /* Set write address */ flash_set_address(dest_addr); /* Start programming */ - flash_execute_cmd(NPCX_CMD_FLASH_PROGRAM, NPCX_MASK_CMD_WR_ADR); + flash_execute_cmd(NPCX_CMD_FLASH_PROGRAM, NPCX_MASK_CMD_WR_3BYTE); for (uint32_t i = 0; i < bytes; i++) { flash_execute_cmd(*data, NPCX_MASK_CMD_WR_ONLY); data++; @@ -114,6 +149,15 @@ static void flash_burst_write(uint32_t dest_addr, uint16_t bytes, flash_cs_level(1); } +static void flash_get_stsreg(uint8_t *reg1, uint8_t *reg2) +{ + /* Read status register 1/2 for checking */ + flash_execute_cmd(NPCX_CMD_READ_STATUS_REG, NPCX_MASK_CMD_RD_1BYTE); + *reg1 = NPCX_UMA_DB0; + flash_execute_cmd(NPCX_CMD_READ_STATUS_REG2, NPCX_MASK_CMD_RD_1BYTE); + *reg2 = NPCX_UMA_DB0; +} + /* The data to write cannot cross 256 Bytes boundary */ static int flash_program_write(uint32_t addr, uint32_t size, const uint8_t *data) @@ -126,7 +170,41 @@ static int flash_program_write(uint32_t addr, uint32_t size, return flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); } -int flash_physical_write(uint32_t offset, uint32_t size, const uint8_t *data) +static int flash_physical_clear_stsreg(void) +{ + int status; + uint8_t reg1, reg2; + + /* Read status register 1/2 for checking */ + flash_get_stsreg(®1, ®2); + if (reg1 == 0x00 && reg2 == 0x00) + return NPCX_FLASH_STATUS_OK; + + /* Enable write */ + status = flash_write_enable(); + if (status != NPCX_FLASH_STATUS_OK) + return status; + + NPCX_UMA_DB0 = 0x0; + NPCX_UMA_DB1 = 0x0; + + /* Write status register 1/2 */ + flash_execute_cmd(NPCX_CMD_WRITE_STATUS_REG, NPCX_MASK_CMD_WR_2BYTE); + + /* Wait writing completed */ + status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); + if (status != NPCX_FLASH_STATUS_OK) + return status; + + /* Read status register 1/2 for checking */ + flash_get_stsreg(®1, ®2); + if (reg1 != 0x00 || reg2 != 0x00) + return NPCX_FLASH_STATUS_FAILED; + + return NPCX_FLASH_STATUS_OK; +} + +static int flash_physical_write(uint32_t offset, uint32_t size, const uint8_t *data) { int status; uint32_t trunk_start = (offset + 0xff) & ~0xff; @@ -135,6 +213,13 @@ int flash_physical_write(uint32_t offset, uint32_t size, const uint8_t *data) uint32_t dest_addr = offset; uint32_t write_len = ((trunk_start - offset) > size) ? size : (trunk_start - offset); + /* Configure fiu and clear status registers if needed */ + flash_init(); + status = flash_physical_clear_stsreg(); + if (status != NPCX_FLASH_STATUS_OK) + return status; + + if (write_len) { status = flash_program_write(dest_addr, write_len, data); if (status != NPCX_FLASH_STATUS_OK) @@ -162,8 +247,16 @@ int flash_physical_write(uint32_t offset, uint32_t size, const uint8_t *data) return NPCX_FLASH_STATUS_OK; } -int flash_physical_erase(uint32_t offset, uint32_t size) +static int flash_physical_erase(uint32_t offset, uint32_t size) { + /* Configure fiu */ + flash_init(); + + /* clear flash status registers */ + int status = flash_physical_clear_stsreg(); + if (status != NPCX_FLASH_STATUS_OK) + return status; + /* Alignment has been checked in upper layer */ for (; size > 0; size -= NPCX_FLASH_ERASE_SIZE, offset += NPCX_FLASH_ERASE_SIZE) { @@ -175,7 +268,7 @@ int flash_physical_erase(uint32_t offset, uint32_t size) /* Set erase address */ flash_set_address(offset); /* Start erase */ - flash_execute_cmd(NPCX_CMD_SECTOR_ERASE, NPCX_MASK_CMD_ADR); + flash_execute_cmd(NPCX_CMD_SECTOR_ERASE, NPCX_MASK_CMD_WR_3BYTE); /* Wait erase completed */ status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); if (status != NPCX_FLASH_STATUS_OK) @@ -185,55 +278,36 @@ int flash_physical_erase(uint32_t offset, uint32_t size) return NPCX_FLASH_STATUS_OK; } -int flash_physical_erase_all(void) +static int flash_physical_erase_all(void) { - /* Enable write */ - int status = flash_write_enable(); - if (status != NPCX_FLASH_STATUS_OK) - return status; - - /* Start erase */ - flash_execute_cmd(NPCX_CMD_CHIP_ERASE, NPCX_MASK_CMD_ONLY); + int status; - /* Wait erase completed */ - status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); + /* Configure fiu and clear status register if needed */ + flash_init(); + status = flash_physical_clear_stsreg(); if (status != NPCX_FLASH_STATUS_OK) return status; - return NPCX_FLASH_STATUS_OK; -} - -int flash_physical_clear_stsreg(void) -{ /* Enable write */ - int status = flash_write_enable(); + status = flash_write_enable(); if (status != NPCX_FLASH_STATUS_OK) return status; - NPCX_UMA_DB0 = 0x0; - NPCX_UMA_DB1 = 0x0; - - /* Write status register 1/2 */ - flash_execute_cmd(NPCX_CMD_WRITE_STATUS_REG, NPCX_MASK_CMD_WR_2BYTE); + /* Start erase */ + flash_execute_cmd(NPCX_CMD_CHIP_ERASE, NPCX_MASK_CMD_ONLY); - /* Wait writing completed */ + /* Wait erase completed */ status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT); if (status != NPCX_FLASH_STATUS_OK) return status; - /* Read status register 1/2 for checking */ - flash_execute_cmd(NPCX_CMD_READ_STATUS_REG, NPCX_MASK_CMD_RD_1BYTE); - if (NPCX_UMA_DB0 != 0x00) - return NPCX_FLASH_STATUS_FAILED; - flash_execute_cmd(NPCX_CMD_READ_STATUS_REG2, NPCX_MASK_CMD_RD_1BYTE); - if (NPCX_UMA_DB0 != 0x00) - return NPCX_FLASH_STATUS_FAILED; - return NPCX_FLASH_STATUS_OK; } -int flash_get_id(uint32_t *id) +static int flash_get_id(uint32_t *id) { + flash_init(); + flash_execute_cmd(NPCX_CMD_READ_ID, NPCX_MASK_CMD_RD_3BYTE); *id = NPCX_UMA_DB0 << 16 | NPCX_UMA_DB1 << 8 | NPCX_UMA_DB2; @@ -243,7 +317,7 @@ int flash_get_id(uint32_t *id) /*---------------------------------------------------------------------------- * flash loader function *----------------------------------------------------------------------------*/ -uint32_t flashloader_init(struct npcx_flash_params *params) +static uint32_t flashloader_init(struct npcx_flash_params *params) { /* Initialize params buffers */ memset(params, 0, sizeof(struct npcx_flash_params)); @@ -254,30 +328,13 @@ uint32_t flashloader_init(struct npcx_flash_params *params) /*---------------------------------------------------------------------------- * Functions *----------------------------------------------------------------------------*/ -/* flashloader parameter structure */ -__attribute__ ((section(".buffers.g_cfg"))) -volatile struct npcx_flash_params g_cfg; -/* data buffer */ -__attribute__ ((section(".buffers.g_buf"))) -uint8_t g_buf[NPCX_FLASH_LOADER_BUFFER_SIZE]; - -int main(void) +static int main(void) { - uint32_t id; + uint32_t id, status; /* set buffer */ flashloader_init((struct npcx_flash_params *)&g_cfg); - /* Avoid F_CS0 toggles while programming the internal flash. */ - NPCX_SET_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_NO_F_SPI); - - /* clear flash status registers */ - int status = flash_physical_clear_stsreg(); - if (status != NPCX_FLASH_STATUS_OK) { - while (1) - g_cfg.sync = status; - } - while (1) { /* wait command*/ while (g_cfg.sync == NPCX_FLASH_LOADER_WAIT) diff --git a/contrib/loaders/flash/npcx/npcx_flash.h b/contrib/loaders/flash/npcx/npcx_flash.h index cc4f1ad506..48e5d82fd3 100644 --- a/contrib/loaders/flash/npcx/npcx_flash.h +++ b/contrib/loaders/flash/npcx/npcx_flash.h @@ -80,6 +80,7 @@ #define NPCX_FIU_DMM_CYC NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x032) #define NPCX_FIU_EXT_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x033) #define NPCX_FIU_UMA_AB0_3 NPCX_HW_DWORD(NPCX_FIU_BASE_ADDR + 0x034) +#define NPCX_FIU_MSR_IE_CFG NPCX_HW_BYTE(NPCX_FIU_BASE_ADDR + 0x043) /* FIU register fields */ #define NPCX_RESP_CFG_IAD_EN 0 @@ -93,6 +94,7 @@ #define NPCX_UMA_ECTS_SW_CS1 1 #define NPCX_UMA_ECTS_SEC_CS 2 #define NPCX_UMA_ECTS_UMA_LOCK 3 +#define NPCX_FIU_MSR_IE_CFG_UMA_BLOCK 3 /* Flash UMA commands for npcx internal SPI flash */ #define NPCX_CMD_READ_ID 0x9F @@ -130,7 +132,6 @@ #define NPCX_SPI_FLASH_SR1_BUSY (1 << 0) #define NPCX_MASK_CMD_ONLY (0xC0) -#define NPCX_MASK_CMD_ADR (0xC0 | 0x08) #define NPCX_MASK_CMD_ADR_WR (0xC0 | 0x20 | 0x08 | 0x01) #define NPCX_MASK_RD_1BYTE (0xC0 | 0x10 | 0x01) #define NPCX_MASK_RD_2BYTE (0xC0 | 0x10 | 0x02) @@ -143,10 +144,12 @@ #define NPCX_MASK_CMD_WR_ONLY (0xC0 | 0x20) #define NPCX_MASK_CMD_WR_1BYTE (0xC0 | 0x20 | 0x10 | 0x01) #define NPCX_MASK_CMD_WR_2BYTE (0xC0 | 0x20 | 0x10 | 0x02) -#define NPCX_MASK_CMD_WR_ADR (0xC0 | 0x20 | 0x08) +#define NPCX_MASK_CMD_WR_3BYTE (0xC0 | 0x20 | 0x10 | 0x03) +#define NPCX_MASK_CMD_WR_4BYTE (0xC0 | 0x20 | 0x10 | 0x04) /* Flash loader parameters */ struct __attribute__((__packed__)) npcx_flash_params { + uint32_t fiu_ver; /* Flash controller unit version */ uint32_t addr; /* Address in flash */ uint32_t len; /* Number of bytes */ uint32_t cmd; /* Command */ @@ -176,4 +179,10 @@ enum npcx_flash_status { NPCX_FLASH_STATUS_FAILED_TIMEOUT, }; +enum npcx_fiu_ver { + NPCX_FIU_NPCX = 0, + NPCX_FIU_NPCX_V2, + NPCX_FIU_NPCK, +}; + #endif /* OPENOCD_LOADERS_FLASH_NPCX_NPCX_FLASH_H */ diff --git a/contrib/loaders/flash/npcx/npcx_flash_config.h b/contrib/loaders/flash/npcx/npcx_flash_config.h index 9ec1c5e331..4abd23e348 100644 --- a/contrib/loaders/flash/npcx/npcx_flash_config.h +++ b/contrib/loaders/flash/npcx/npcx_flash_config.h @@ -18,7 +18,7 @@ /* NPCX flash loader information */ #define NPCX_FLASH_LOADER_WORKING_ADDR 0x200C0000 #define NPCX_FLASH_LOADER_PARAMS_ADDR NPCX_FLASH_LOADER_WORKING_ADDR -#define NPCX_FLASH_LOADER_PARAMS_SIZE 16 +#define NPCX_FLASH_LOADER_PARAMS_SIZE 20 #define NPCX_FLASH_LOADER_BUFFER_ADDR (NPCX_FLASH_LOADER_PARAMS_ADDR + NPCX_FLASH_LOADER_PARAMS_SIZE) #define NPCX_FLASH_LOADER_BUFFER_SIZE NPCX_FLASH_ERASE_SIZE #define NPCX_FLASH_LOADER_PROGRAM_ADDR (NPCX_FLASH_LOADER_BUFFER_ADDR + NPCX_FLASH_LOADER_BUFFER_SIZE) diff --git a/contrib/loaders/flash/nrf5/Makefile b/contrib/loaders/flash/nrf5/Makefile index 67390b9bdb..254ccd7da6 100644 --- a/contrib/loaders/flash/nrf5/Makefile +++ b/contrib/loaders/flash/nrf5/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../../src/helper/bin2char.sh CROSS_COMPILE ?= arm-none-eabi- diff --git a/contrib/loaders/flash/nrf5/nrf5.S b/contrib/loaders/flash/nrf5/nrf5.S index 12b1d92b5a..4115b0311e 100644 --- a/contrib/loaders/flash/nrf5/nrf5.S +++ b/contrib/loaders/flash/nrf5/nrf5.S @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2014 Angus Gratton * * gus@projectgus.com * - * * - * 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, write to the * - * Free Software Foundation, Inc. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/numicro/Makefile b/contrib/loaders/flash/numicro/Makefile new file mode 100644 index 0000000000..e4f44417c1 --- /dev/null +++ b/contrib/loaders/flash/numicro/Makefile @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +BIN2C = ../../../../src/helper/bin2char.sh + +CROSS_COMPILE ?= arm-none-eabi- + +CC=$(CROSS_COMPILE)gcc +OBJCOPY=$(CROSS_COMPILE)objcopy +OBJDUMP=$(CROSS_COMPILE)objdump + + +AFLAGS = -static -nostartfiles -mlittle-endian -Wa,-EL + +all: numicro_m0.inc numicro_m4.inc + +.PHONY: clean + +%.elf: %.S + $(CC) $(AFLAGS) $< -o $@ + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +%.bin: %.elf + $(OBJCOPY) -Obinary $< $@ + +%.inc: %.bin + $(BIN2C) < $< > $@ + +clean: + -rm -f *.elf *.lst *.bin *.inc diff --git a/contrib/loaders/flash/numicro/numicro_m0.S b/contrib/loaders/flash/numicro/numicro_m0.S new file mode 100644 index 0000000000..37d4355324 --- /dev/null +++ b/contrib/loaders/flash/numicro/numicro_m0.S @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2015 Nemui Trinomius * + * nemuisan_kawausogasuki@live.jp * + * * + * Copyright (C) 2017 Zale Yu * + * CYYU@nuvoton.com * + * * + * Copyright (C) 2022 Jian-Hong Pan * + * chienhung.pan@gmail.com * + ***************************************************************************/ + + .text + .cpu cortex-m0 + .thumb + + /* Params: + * r0 - workarea buffer / result + * r1 - target address + * r2 - wordcount + * Clobbered: + * r4 - tmp + * r5 - tmp + * r6 - tmp + * r7 - tmp + */ + +.L1: + /* for(register uint32_t i=0;i $@ + +%.bin: %.elf + $(OBJCOPY) -Obinary $< $@ + +%.inc: %.bin + $(BIN2C) < $< > $@ + +clean: + -rm -f *.elf *.lst *.bin *.inc diff --git a/contrib/loaders/flash/rsl10/rom_launcher.S b/contrib/loaders/flash/rsl10/rom_launcher.S new file mode 100644 index 0000000000..aafedfb462 --- /dev/null +++ b/contrib/loaders/flash/rsl10/rom_launcher.S @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Toms StÅ«rmanis * + * toms.sturmanis@gmail.com * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m4 + .thumb + .align 8 + +/* + * Params : + * r0-r2 = arguments + * r3 = target address in rom + */ + + .thumb_func + .global _start +_start: +launch_program_in_rom: + // variables are already set, address to jump is in r3 + blx r3 +exit: + // Wait for OpenOCD + bkpt #0x00 diff --git a/contrib/loaders/flash/rsl10/rom_launcher.inc b/contrib/loaders/flash/rsl10/rom_launcher.inc new file mode 100644 index 0000000000..795c8e0d92 --- /dev/null +++ b/contrib/loaders/flash/rsl10/rom_launcher.inc @@ -0,0 +1,2 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x98,0x47,0x00,0xbe, diff --git a/contrib/loaders/flash/sh_qspi/Makefile b/contrib/loaders/flash/sh_qspi/Makefile index 2bfbad1b00..a7e0aea4ec 100644 --- a/contrib/loaders/flash/sh_qspi/Makefile +++ b/contrib/loaders/flash/sh_qspi/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + CROSS_COMPILE=arm-linux-gnueabihf- BIN2C = ../../../../src/helper/bin2char.sh diff --git a/contrib/loaders/flash/sh_qspi/sh_qspi.S b/contrib/loaders/flash/sh_qspi/sh_qspi.S index 78eb1e8187..b46514a487 100644 --- a/contrib/loaders/flash/sh_qspi/sh_qspi.S +++ b/contrib/loaders/flash/sh_qspi/sh_qspi.S @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * SH QSPI (Quad SPI) driver * Copyright (C) 2019 Marek Vasut diff --git a/contrib/loaders/flash/sh_qspi/sh_qspi.ld b/contrib/loaders/flash/sh_qspi/sh_qspi.ld index 2683c520b5..71cc3e380d 100644 --- a/contrib/loaders/flash/sh_qspi/sh_qspi.ld +++ b/contrib/loaders/flash/sh_qspi/sh_qspi.ld @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(_start) diff --git a/contrib/loaders/flash/sim3x.s b/contrib/loaders/flash/sim3x.s index cdb3ef6811..6031f0c31f 100644 --- a/contrib/loaders/flash/sim3x.s +++ b/contrib/loaders/flash/sim3x.s @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2014 by Ladislav Bábel * * ladababel@seznam.cz * - * * - * 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. * ***************************************************************************/ #define INITIAL_UNLOCK 0x5A diff --git a/contrib/loaders/flash/stellaris.s b/contrib/loaders/flash/stellaris.s index 6e1ed69cd1..0f2d0f59e9 100644 --- a/contrib/loaders/flash/stellaris.s +++ b/contrib/loaders/flash/stellaris.s @@ -1,24 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/stm32/Makefile b/contrib/loaders/flash/stm32/Makefile index cee282aa3e..5a97e7bb9c 100644 --- a/contrib/loaders/flash/stm32/Makefile +++ b/contrib/loaders/flash/stm32/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../../src/helper/bin2char.sh CROSS_COMPILE ?= arm-none-eabi- diff --git a/contrib/loaders/flash/stm32/stm32f1x.S b/contrib/loaders/flash/stm32/stm32f1x.S index a1c41358a8..fb214da31e 100644 --- a/contrib/loaders/flash/stm32/stm32f1x.S +++ b/contrib/loaders/flash/stm32/stm32f1x.S @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * - * * - * 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. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/stm32/stm32f2x.S b/contrib/loaders/flash/stm32/stm32f2x.S index 8caf5ba9a6..95e5e384fb 100644 --- a/contrib/loaders/flash/stm32/stm32f2x.S +++ b/contrib/loaders/flash/stm32/stm32f2x.S @@ -1,19 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/stm32/stm32h7x.S b/contrib/loaders/flash/stm32/stm32h7x.S index 8ef42a4cf9..e4a172a166 100644 --- a/contrib/loaders/flash/stm32/stm32h7x.S +++ b/contrib/loaders/flash/stm32/stm32h7x.S @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2017 by STMicroelectronics * - * * - * 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, write to the * - * Free Software Foundation, Inc. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/stm32/stm32l4x.c b/contrib/loaders/flash/stm32/stm32l4x.c index 54c88a3355..b657ec9aea 100644 --- a/contrib/loaders/flash/stm32/stm32l4x.c +++ b/contrib/loaders/flash/stm32/stm32l4x.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later /** * Copyright (C) 2021 Tarek BOCHKATI diff --git a/contrib/loaders/flash/stm32/stm32lx.S b/contrib/loaders/flash/stm32/stm32lx.S index 7cfe485452..fc90847b1b 100644 --- a/contrib/loaders/flash/stm32/stm32lx.S +++ b/contrib/loaders/flash/stm32/stm32lx.S @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * @@ -10,16 +12,6 @@ * * * Copyright (C) 2017 Armin van der Togt * * armin@otheruse.nl * - * * - * 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. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/stmqspi/Makefile b/contrib/loaders/flash/stmqspi/Makefile index 810c7e87c1..b07d452a82 100644 --- a/contrib/loaders/flash/stmqspi/Makefile +++ b/contrib/loaders/flash/stmqspi/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../../src/helper/bin2char.sh SRCS=stmqspi_erase_check.S stmqspi_crc32.S stmqspi_read.S stmqspi_write.S \ diff --git a/contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl b/contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl index b7538640ed..49b15c2022 100755 --- a/contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl +++ b/contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl @@ -1,4 +1,6 @@ #!/usr/bin/perl +# SPDX-License-Identifier: GPL-2.0-or-later + # # Helper for generating GPIO setup for STM32F0, F4, F7, H7, L0, L1, L4, L4+ # and F1 (for 'stmqspi' and 'cmspi' drivers). diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_crc32.S b/contrib/loaders/flash/stmqspi/stmoctospi_crc32.S index 941ea42c63..338fba370b 100644 --- a/contrib/loaders/flash/stmqspi/stmoctospi_crc32.S +++ b/contrib/loaders/flash/stmqspi/stmoctospi_crc32.S @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2019 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * - * * - * 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 . * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S b/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S index 3af82d4d8a..6593a8edea 100644 --- a/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S +++ b/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2019 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * - * * - * 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 . * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_read.S b/contrib/loaders/flash/stmqspi/stmoctospi_read.S index fb5ff1ff9c..8cc786ed6f 100644 --- a/contrib/loaders/flash/stmqspi/stmoctospi_read.S +++ b/contrib/loaders/flash/stmqspi/stmoctospi_read.S @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2019 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * - * * - * 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 . * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_write.S b/contrib/loaders/flash/stmqspi/stmoctospi_write.S index 867a024830..245b99c559 100644 --- a/contrib/loaders/flash/stmqspi/stmoctospi_write.S +++ b/contrib/loaders/flash/stmqspi/stmoctospi_write.S @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2018 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * - * * - * 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 . * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/stmqspi/stmqspi_crc32.S b/contrib/loaders/flash/stmqspi/stmqspi_crc32.S index bfb2662ca3..4dd5671cae 100644 --- a/contrib/loaders/flash/stmqspi/stmqspi_crc32.S +++ b/contrib/loaders/flash/stmqspi/stmqspi_crc32.S @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2019 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * - * * - * 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 . * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/stmqspi/stmqspi_erase_check.S b/contrib/loaders/flash/stmqspi/stmqspi_erase_check.S index d011103a2f..5fddbcbb9c 100644 --- a/contrib/loaders/flash/stmqspi/stmqspi_erase_check.S +++ b/contrib/loaders/flash/stmqspi/stmqspi_erase_check.S @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2019 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * - * * - * 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 . * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/stmqspi/stmqspi_read.S b/contrib/loaders/flash/stmqspi/stmqspi_read.S index b84d4ebd72..f6bf87633f 100644 --- a/contrib/loaders/flash/stmqspi/stmqspi_read.S +++ b/contrib/loaders/flash/stmqspi/stmqspi_read.S @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2019 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * - * * - * 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 . * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/stmqspi/stmqspi_write.S b/contrib/loaders/flash/stmqspi/stmqspi_write.S index 40953acf68..9991d346ea 100644 --- a/contrib/loaders/flash/stmqspi/stmqspi_write.S +++ b/contrib/loaders/flash/stmqspi/stmqspi_write.S @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2016 - 2018 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * - * * - * 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 . * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/str7x.s b/contrib/loaders/flash/str7x.s index cd19013be1..8630bb7872 100644 --- a/contrib/loaders/flash/str7x.s +++ b/contrib/loaders/flash/str7x.s @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/str9x.s b/contrib/loaders/flash/str9x.s index 279b175036..53d385698a 100644 --- a/contrib/loaders/flash/str9x.s +++ b/contrib/loaders/flash/str9x.s @@ -1,21 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ .text diff --git a/contrib/loaders/flash/xmc1xxx/Makefile b/contrib/loaders/flash/xmc1xxx/Makefile index b97c602d03..0bda5b72ab 100644 --- a/contrib/loaders/flash/xmc1xxx/Makefile +++ b/contrib/loaders/flash/xmc1xxx/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../../src/helper/bin2char.sh CROSS_COMPILE ?= arm-none-eabi- diff --git a/contrib/loaders/flash/xmc1xxx/erase.S b/contrib/loaders/flash/xmc1xxx/erase.S index e5a4808fcc..9d3d9925c1 100644 --- a/contrib/loaders/flash/xmc1xxx/erase.S +++ b/contrib/loaders/flash/xmc1xxx/erase.S @@ -1,11 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Infineon XMC1000 flash sectors erase * * Copyright (c) 2016 Andreas Färber * * Based on XMC1100 AA-Step Reference Manual - * - * License: GPL-2.0+ */ #include "xmc1xxx.S" diff --git a/contrib/loaders/flash/xmc1xxx/erase_check.S b/contrib/loaders/flash/xmc1xxx/erase_check.S index 6c993443a9..311c2044d2 100644 --- a/contrib/loaders/flash/xmc1xxx/erase_check.S +++ b/contrib/loaders/flash/xmc1xxx/erase_check.S @@ -1,11 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Infineon XMC1000 flash sector erase check * * Copyright (c) 2016 Andreas Färber * * Based on XMC1100 AA-Step Reference Manual - * - * License: GPL-2.0+ */ #include "xmc1xxx.S" diff --git a/contrib/loaders/flash/xmc1xxx/write.S b/contrib/loaders/flash/xmc1xxx/write.S index 640f6ca960..1754252445 100644 --- a/contrib/loaders/flash/xmc1xxx/write.S +++ b/contrib/loaders/flash/xmc1xxx/write.S @@ -1,11 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Infineon XMC1000 flash write * * Copyright (c) 2016 Andreas Färber * * Based on XMC1100 AA-Step Reference Manual - * - * License: GPL-2.0+ */ #include "xmc1xxx.S" diff --git a/contrib/loaders/flash/xmc1xxx/xmc1xxx.S b/contrib/loaders/flash/xmc1xxx/xmc1xxx.S index dfe7d3f41e..5be141d6df 100644 --- a/contrib/loaders/flash/xmc1xxx/xmc1xxx.S +++ b/contrib/loaders/flash/xmc1xxx/xmc1xxx.S @@ -1,11 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Infineon XMC1000 flash * * Copyright (c) 2016 Andreas Färber * * Based on XMC1100 AA-Step Reference Manual - * - * License: GPL-2.0+ */ .text diff --git a/contrib/loaders/reset/espressif/common.mk b/contrib/loaders/reset/espressif/common.mk new file mode 100644 index 0000000000..f77efe6769 --- /dev/null +++ b/contrib/loaders/reset/espressif/common.mk @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# ESP32 Makefile to compile the SoC reset program +# Copyright (C) 2022 Espressif Systems Ltd. + +# Pass V=1 to see the commands being executed by make +ifneq ("$(V)","1") +Q = @ +endif + +BIN2C = ../../../../../src/helper/bin2char.sh + +APP = cpu_reset_handler + +BUILD_DIR = build + +APP_OBJ = $(BUILD_DIR)/$(APP).o +APP_BIN = $(BUILD_DIR)/$(APP)_code.bin +APP_CODE = $(APP)_code.inc + +CFLAGS += -mtext-section-literals + +.PHONY: all cleanxten + +all: $(BUILD_DIR) $(APP_OBJ) $(APP_CODE) + +$(BUILD_DIR): + $(Q) mkdir $@ + +$(APP_OBJ): $(SRCS) + @echo " CC $^ -> $@" + $(Q) $(CROSS)gcc -c $(CFLAGS) -o $@ $^ + +$(APP_CODE): $(APP_OBJ) + @echo " CC $^ -> $@" + $(Q) $(CROSS)objcopy -O binary -j.text $^ $(APP_BIN) + $(Q) $(BIN2C) < $(APP_BIN) > $@ + +clean: + $(Q) rm -rf $(BUILD_DIR) diff --git a/contrib/loaders/reset/espressif/esp32/Makefile b/contrib/loaders/reset/espressif/esp32/Makefile new file mode 100644 index 0000000000..a63178065f --- /dev/null +++ b/contrib/loaders/reset/espressif/esp32/Makefile @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# ESP32 Makefile to compile the SoC reset program +# Copyright (C) 2022 Espressif Systems Ltd. + +# Prefix for ESP32 cross compilers (can include a directory path) +CROSS ?= xtensa-esp32-elf- + +APP_ARCH := xtensa +APP_CHIP := ESP32 +APP_CHIP_PATH := $(shell pwd) +SRCS := $(APP_CHIP_PATH)/esp32_cpu_reset_handler.S + +CFLAGS := +LDFLAGS := + +INCLUDES := +DEFINES := + +include ../common.mk diff --git a/contrib/loaders/reset/espressif/esp32/cpu_reset_handler_code.inc b/contrib/loaders/reset/espressif/esp32/cpu_reset_handler_code.inc new file mode 100644 index 0000000000..57ee12d19c --- /dev/null +++ b/contrib/loaders/reset/espressif/esp32/cpu_reset_handler_code.inc @@ -0,0 +1,15 @@ +/* Autogenerated with ../../../../../src/helper/bin2char.sh */ +0x06,0x1e,0x00,0x00,0x06,0x14,0x00,0x00,0x34,0x80,0xf4,0x3f,0xb0,0x80,0xf4,0x3f, +0xb4,0x80,0xf4,0x3f,0x70,0x80,0xf4,0x3f,0x10,0x22,0x00,0x00,0x00,0x20,0x49,0x9c, +0x00,0x80,0xf4,0x3f,0xa1,0x3a,0xd8,0x50,0xa4,0x80,0xf4,0x3f,0x64,0xf0,0xf5,0x3f, +0x64,0x00,0xf6,0x3f,0x8c,0x80,0xf4,0x3f,0x48,0xf0,0xf5,0x3f,0x48,0x00,0xf6,0x3f, +0xfc,0xa1,0xf5,0x3f,0x38,0x00,0xf0,0x3f,0x30,0x00,0xf0,0x3f,0x2c,0x00,0xf0,0x3f, +0x34,0x80,0xf4,0x3f,0x00,0x30,0x00,0x00,0x50,0x55,0x30,0x41,0xeb,0xff,0x59,0x04, +0x41,0xeb,0xff,0x59,0x04,0x41,0xea,0xff,0x59,0x04,0x41,0xea,0xff,0x31,0xea,0xff, +0x39,0x04,0x31,0xea,0xff,0x41,0xea,0xff,0x39,0x04,0x00,0x00,0x60,0xeb,0x03,0x60, +0x61,0x04,0x56,0x66,0x04,0x50,0x55,0x30,0x31,0xe7,0xff,0x41,0xe7,0xff,0x39,0x04, +0x41,0xe7,0xff,0x39,0x04,0x41,0xe6,0xff,0x39,0x04,0x41,0xe6,0xff,0x59,0x04,0x41, +0xe6,0xff,0x59,0x04,0x41,0xe6,0xff,0x59,0x04,0x41,0xe5,0xff,0x59,0x04,0x41,0xe5, +0xff,0x59,0x04,0x41,0xe5,0xff,0x0c,0x13,0x39,0x04,0x41,0xe4,0xff,0x0c,0x13,0x39, +0x04,0x59,0x04,0x41,0xe3,0xff,0x31,0xe3,0xff,0x32,0x64,0x00,0x00,0x70,0x00,0x46, +0xfe,0xff, diff --git a/contrib/loaders/reset/espressif/esp32/esp32_cpu_reset_handler.S b/contrib/loaders/reset/espressif/esp32/esp32_cpu_reset_handler.S new file mode 100644 index 0000000000..506d41e85c --- /dev/null +++ b/contrib/loaders/reset/espressif/esp32/esp32_cpu_reset_handler.S @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Reset stub used by esp32 target * + * Copyright (C) 2017 Espressif Systems Ltd. * + ***************************************************************************/ + +#define RTC_CNTL_RESET_STATE_REG 0x3ff48034 +#define RTC_CNTL_RESET_STATE_DEF 0x3000 +#define RTC_CNTL_CLK_CONF_REG 0x3ff48070 +#define RTC_CNTL_CLK_CONF_DEF 0x2210 +#define RTC_CNTL_STORE4_REG 0x3ff480b0 +#define RTC_CNTL_STORE5_REG 0x3ff480b4 +#define WDT_WKEY_VALUE 0x50D83AA1 +#define TIMG0_WDTWPROTECT_REG 0x3ff5f064 +#define TIMG0_WDTCONFIG0_REG 0x3ff5f048 +#define TIMG1_WDTWPROTECT_REG 0x3FF60064 +#define TIMG1_WDTCONFIG0_REG 0x3ff60048 +#define RTC_CNTL_WDTCONFIG0_REG 0x3ff4808c +#define RTC_CNTL_WDTWPROTECT_REG 0x3ff480a4 +#define JTAG_ENABLE_REG 0x3ff5a1fc +#define RTC_CNTL_OPTIONS0_REG 0x3ff48000 +#define RTC_CNTL_OPTIONS0_DEF 0x1c492000 +#define RTC_CNTL_SW_SYS_RST 0x80000000 +#define DPORT_APPCPU_CTRL_A_REG 0x3ff0002c +#define DPORT_APPCPU_RST_EN 0x1 +#define DPORT_APPCPU_CTRL_B_REG 0x3ff00030 +#define DPORT_APPCPU_CLKGATE_EN 0x1 +#define DPORT_APPCPU_CTRL_C_REG 0x3ff00034 +#define DPORT_APPCPU_CTRL_D_REG 0x3ff00038 + + +/* This stub is copied to RTC_SLOW_MEM by OpenOCD, and the CPU starts executing + * it instead of the ROM code (0x40000400). This stub disables watchdogs and + * goes into a loop. + * OpenOCD will then halt the target and perform CPU reset using OCD. + */ + + +/* Has to be at offset 0. This is the entry point of the CPU, once + * RTC_CNTL_PROCPU_STAT_VECTOR_SEL is cleared. + * CPU will come here after the system reset, triggered by RTC_CNTL_SW_SYS_RST. + */ + .global cpu_at_start_handler + .type cpu_at_start_handler,@function + .align 4 +cpu_at_start_handler: + j start + + +/* Has to be at offset 4. Once the stub code has been uploaded into RTC Slow + * memory, OpenOCD will set the PC to this address, and resume execution. + * The stub will then jump to 'reset' label and perform the reset. + */ + .global cpu_reset_handler + .type cpu_reset_handler,@function + .align 4 +cpu_reset_handler: + j reset + + .align 4 + .literal_position + + .align 4 +reset: + /* Use a5 as a zero register */ + xor a5, a5, a5 + /* Select static reset vector 0 (XCHAL_RESET_VECTOR0_VADDR, 0x50000000) */ + movi a4, RTC_CNTL_RESET_STATE_REG + s32i a5, a4, 0 + /* Set some clock-related RTC registers to the default values */ + movi a4, RTC_CNTL_STORE4_REG + s32i a5, a4, 0 + movi a4, RTC_CNTL_STORE5_REG + s32i a5, a4, 0 + movi a4, RTC_CNTL_CLK_CONF_REG + movi a3, RTC_CNTL_CLK_CONF_DEF + s32i a3, a4, 0 + /* Reset the digital part of the chip (RTC controller doesn't get reset) */ + movi a3, (RTC_CNTL_OPTIONS0_DEF | RTC_CNTL_SW_SYS_RST) + movi a4, RTC_CNTL_OPTIONS0_REG + s32i a3, a4, 0 + /* Doesn't reach beyond this instruction */ + + .align 4 +start: + /* If running on the APP CPU, skip directly to the parking loop */ + rsr.prid a6 + extui a6, a6, 1, 1 + bnez a6, parking_loop + + /* Use a5 as a zero register */ + xor a5, a5, a5 + /* Disable the watchdogs */ + movi a3, WDT_WKEY_VALUE + movi a4, RTC_CNTL_WDTWPROTECT_REG + s32i.n a3, a4, 0 + movi a4, TIMG0_WDTWPROTECT_REG + s32i.n a3, a4, 0 + movi a4, TIMG1_WDTWPROTECT_REG + s32i.n a3, a4, 0 + movi a4, RTC_CNTL_WDTCONFIG0_REG + s32i.n a5, a4, 0 + movi a4, TIMG0_WDTCONFIG0_REG + s32i.n a5, a4, 0 + movi a4, TIMG1_WDTCONFIG0_REG + s32i.n a5, a4, 0 + /* Enable JTAG (needed since rev. 3) */ + movi a4, JTAG_ENABLE_REG + s32i.n a5, a4, 0 + /* Clear APP_CPU boot address */ + movi a4, DPORT_APPCPU_CTRL_D_REG + s32i.n a5, a4, 0 + /* Clear APP_CPU clock gating */ + movi a4, DPORT_APPCPU_CTRL_B_REG + movi a3, DPORT_APPCPU_CLKGATE_EN + s32i.n a3, a4, 0 + /* Set and clear APP_CPU reset */ + movi a4, DPORT_APPCPU_CTRL_A_REG + movi a3, DPORT_APPCPU_RST_EN + s32i.n a3, a4, 0 + s32i.n a5, a4, 0 + /* Restore the reset vector to ROM */ + movi a4, RTC_CNTL_RESET_STATE_REG + movi a3, RTC_CNTL_RESET_STATE_DEF + s32i.n a3, a4, 0 + + +parking_loop: + /* PRO and APP CPU will be in this loop, until OpenOCD + * finds the JTAG taps and puts the CPUs into debug mode. + */ + waiti 0 + j parking_loop diff --git a/contrib/loaders/reset/espressif/esp32s3/Makefile b/contrib/loaders/reset/espressif/esp32s3/Makefile new file mode 100644 index 0000000000..37d5f82815 --- /dev/null +++ b/contrib/loaders/reset/espressif/esp32s3/Makefile @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# ESP32 Makefile to compile the SoC reset program +# Copyright (C) 2022 Espressif Systems Ltd. + +# Prefix for ESP32 cross compilers (can include a directory path) +CROSS ?= xtensa-esp32s3-elf- + +APP_ARCH := xtensa +APP_CHIP := ESP32S3 +APP_CHIP_PATH := $(shell pwd) +SRCS := $(APP_CHIP_PATH)/esp32s3_cpu_reset_handler.S + +CFLAGS := +LDFLAGS := + +INCLUDES := +DEFINES := + +include ../common.mk diff --git a/contrib/loaders/reset/espressif/esp32s3/cpu_reset_handler_code.inc b/contrib/loaders/reset/espressif/esp32s3/cpu_reset_handler_code.inc new file mode 100644 index 0000000000..dc9702c621 --- /dev/null +++ b/contrib/loaders/reset/espressif/esp32s3/cpu_reset_handler_code.inc @@ -0,0 +1,17 @@ +/* Autogenerated with ../../../../../src/helper/bin2char.sh */ +0x06,0x23,0x00,0x00,0x06,0x18,0x00,0x00,0x38,0x80,0x00,0x60,0xc0,0x80,0x00,0x60, +0xc4,0x80,0x00,0x60,0x90,0x80,0x00,0x60,0x74,0x80,0x00,0x60,0x18,0x32,0x58,0x01, +0x00,0xa0,0x00,0x9c,0x00,0x80,0x00,0x60,0xa1,0x3a,0xd8,0x50,0xac,0x80,0x00,0x60, +0x64,0xf0,0x01,0x60,0x64,0x00,0x02,0x60,0x94,0x80,0x00,0x60,0x48,0xf0,0x01,0x60, +0x48,0x00,0x02,0x60,0xb4,0x80,0x00,0x60,0x2a,0x31,0x1d,0x8f,0xb0,0x80,0x00,0x60, +0x00,0x00,0xb0,0x84,0x04,0x00,0x0c,0x60,0x00,0x00,0x0c,0x60,0x00,0x00,0x0c,0x60, +0x38,0x80,0x00,0x60,0x00,0x30,0x00,0x00,0x50,0x55,0x30,0x41,0xe7,0xff,0x59,0x04, +0x41,0xe7,0xff,0x59,0x04,0x41,0xe6,0xff,0x59,0x04,0x41,0xe6,0xff,0x59,0x04,0x41, +0xe6,0xff,0x31,0xe6,0xff,0x39,0x04,0x31,0xe6,0xff,0x41,0xe6,0xff,0x39,0x04,0x00, +0x60,0xeb,0x03,0x60,0x61,0x04,0x56,0x26,0x05,0x50,0x55,0x30,0x31,0xe3,0xff,0x41, +0xe3,0xff,0x39,0x04,0x41,0xe3,0xff,0x39,0x04,0x41,0xe2,0xff,0x39,0x04,0x41,0xe2, +0xff,0x59,0x04,0x41,0xe2,0xff,0x59,0x04,0x41,0xe2,0xff,0x59,0x04,0x41,0xe1,0xff, +0x31,0xe2,0xff,0x39,0x04,0x41,0xe1,0xff,0x31,0xe2,0xff,0x39,0x04,0x41,0xe1,0xff, +0x59,0x04,0x41,0xe1,0xff,0x0c,0x23,0x39,0x04,0x41,0xe0,0xff,0x0c,0x43,0x39,0x04, +0x52,0x64,0x00,0x41,0xdf,0xff,0x31,0xdf,0xff,0x32,0x64,0x00,0x00,0x70,0x00,0x46, +0xfe,0xff, diff --git a/contrib/loaders/reset/espressif/esp32s3/esp32s3_cpu_reset_handler.S b/contrib/loaders/reset/espressif/esp32s3/esp32s3_cpu_reset_handler.S new file mode 100644 index 0000000000..5fc635725f --- /dev/null +++ b/contrib/loaders/reset/espressif/esp32s3/esp32s3_cpu_reset_handler.S @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Reset stub used by esp32s3 target * + * Copyright (C) 2020 Espressif Systems (Shanghai) Co. Ltd. * + ***************************************************************************/ + +#define RTC_CNTL_RESET_STATE_REG 0x60008038 +#define RTC_CNTL_RESET_STATE_DEF 0x3000 +#define RTC_CNTL_CLK_CONF_REG 0x60008074 +#define RTC_CNTL_CLK_CONF_DEF 0x1583218 +#define RTC_CNTL_STORE4_REG 0x600080C0 +#define RTC_CNTL_STORE5_REG 0x600080C4 +#define WDT_WKEY_VALUE 0x50D83AA1 +#define TIMG0_WDTWPROTECT_REG 0x6001F064 +#define TIMG0_WDTCONFIG0_REG 0x6001F048 +#define TIMG1_WDTWPROTECT_REG 0x60020064 +#define TIMG1_WDTCONFIG0_REG 0x60020048 +#define RTC_CNTL_WDTCONFIG0_REG 0x60008094 +#define RTC_CNTL_WDTWPROTECT_REG 0x600080AC +#define RTC_CNTL_OPTIONS0_REG 0x60008000 +#define RTC_CNTL_OPTIONS0_DEF 0x1C00A000 +#define RTC_CNTL_SW_SYS_RST 0x80000000 +#define RTC_CNTL_DIG_PWC_REG 0x60008090 +#define RTC_CNTL_SWD_CONF_REG 0x600080B0 +#define RTC_CNTL_SWD_CONF_VAL 0x84B00000 +#define RTC_CNTL_SWD_WPROTECT_REG 0x600080B4 +#define RTC_CNTL_SWD_WKEY_VALUE 0x8F1D312A +#define SYSTEM_CORE_1_CONTROL_0_REG 0x600C0000 +#define SYSTEM_CONTROL_CORE_1_RESETING 0x4 +#define SYSTEM_CONTROL_CORE_1_CLKGATE_EN 0x2 +#define SYSTEM_CORE_1_CONTROL_1_REG 0x600C0004 + + +/* This stub is copied to RTC_SLOW_MEM by OpenOCD, and the CPU starts executing + * it instead of the ROM code (0x40000400). This stub disables watchdogs and + * goes into a loop. + * OpenOCD will then halt the target and perform CPU reset using OCD. + */ + + +/* Has to be at offset 0. This is the entry point of the CPU, once + * RTC_CNTL_PROCPU_STAT_VECTOR_SEL is cleared. + * CPU will come here after the system reset, triggered by RTC_CNTL_SW_SYS_RST. + */ + .global cpu_at_start_handler + .type cpu_at_start_handler,@function + .align 4 +cpu_at_start_handler: + j start + + +/* Has to be at offset 4. Once the stub code has been uploaded into RTC Slow + * memory, OpenOCD will set the PC to this address, and resume execution. + * The stub will then jump to 'reset' label and perform the reset. + */ + .global cpu_reset_handler + .type cpu_reset_handler,@function + .align 4 +cpu_reset_handler: + j reset + + .align 4 + .literal_position + + .align 4 +reset: + /* Use a5 as a zero register */ + xor a5, a5, a5 + /* Select static reset vector 0 (XCHAL_RESET_VECTOR0_VADDR, 0x50000000) */ + movi a4, RTC_CNTL_RESET_STATE_REG + s32i a5, a4, 0 + /* Set some clock-related RTC registers to the default values */ + movi a4, RTC_CNTL_STORE4_REG + s32i a5, a4, 0 + movi a4, RTC_CNTL_STORE5_REG + s32i a5, a4, 0 + movi a4, RTC_CNTL_DIG_PWC_REG + s32i a5, a4, 0 + movi a4, RTC_CNTL_CLK_CONF_REG + movi a3, RTC_CNTL_CLK_CONF_DEF + s32i a3, a4, 0 + /* Reset the digital part of the chip (RTC controller doesn't get reset) */ + movi a3, (RTC_CNTL_OPTIONS0_DEF | RTC_CNTL_SW_SYS_RST) + movi a4, RTC_CNTL_OPTIONS0_REG + s32i a3, a4, 0 + /* Doesn't reach beyond this instruction */ + + .align 4 +start: + /* If running on the APP CPU, skip directly to the parking loop */ + rsr.prid a6 + extui a6, a6, 1, 1 + bnez a6, parking_loop + + /* Use a5 as a zero register */ + xor a5, a5, a5 + /* Disable the watchdogs */ + movi a3, WDT_WKEY_VALUE + movi a4, RTC_CNTL_WDTWPROTECT_REG + s32i.n a3, a4, 0 + movi a4, TIMG0_WDTWPROTECT_REG + s32i.n a3, a4, 0 + movi a4, TIMG1_WDTWPROTECT_REG + s32i.n a3, a4, 0 + movi a4, RTC_CNTL_WDTCONFIG0_REG + s32i.n a5, a4, 0 + movi a4, TIMG0_WDTCONFIG0_REG + s32i.n a5, a4, 0 + movi a4, TIMG1_WDTCONFIG0_REG + s32i.n a5, a4, 0 + movi a4, RTC_CNTL_SWD_WPROTECT_REG + movi a3, RTC_CNTL_SWD_WKEY_VALUE + s32i.n a3, a4, 0 + movi a4, RTC_CNTL_SWD_CONF_REG + movi a3, RTC_CNTL_SWD_CONF_VAL + s32i.n a3, a4, 0 + /* Clear APP_CPU boot address */ + movi a4, SYSTEM_CORE_1_CONTROL_1_REG + s32i.n a5, a4, 0 + /* Clear APP_CPU clock gating */ + movi a4, SYSTEM_CORE_1_CONTROL_0_REG + movi a3, SYSTEM_CONTROL_CORE_1_CLKGATE_EN + s32i.n a3, a4, 0 + /* Set and clear APP_CPU reset */ + movi a4, SYSTEM_CORE_1_CONTROL_0_REG + movi a3, SYSTEM_CONTROL_CORE_1_RESETING + s32i.n a3, a4, 0 + s32i.n a5, a4, 0 + /* Restore the reset vector to ROM */ + movi a4, RTC_CNTL_RESET_STATE_REG + movi a3, RTC_CNTL_RESET_STATE_DEF + s32i.n a3, a4, 0 + + +parking_loop: + /* PRO and APP CPU will be in this loop, until OpenOCD + * finds the JTAG taps and puts the CPUs into debug mode. + */ + waiti 0 + j parking_loop diff --git a/contrib/loaders/trampoline/espressif/xtensa/Makefile b/contrib/loaders/trampoline/espressif/xtensa/Makefile new file mode 100644 index 0000000000..bd1f630449 --- /dev/null +++ b/contrib/loaders/trampoline/espressif/xtensa/Makefile @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Espressif Xtensa Makefile to compile flasher stub wrapper +# Copyright (C) 2023 Espressif Systems Ltd. + +# Prefix for Espressif xtensa cross compilers (can include a directory path) +CROSS ?= xtensa-esp32-elf- + +APP_ARCH := xtensa +APP_CHIP_PATH := $(shell pwd) +SRCS := $(APP_CHIP_PATH)/esp_xtensa_stub_tramp_win.S + +BIN2C = ../../../../../src/helper/bin2char.sh +BUILD_DIR = build + +APP = esp_xtensa_stub_tramp_win +APP_OBJ = $(BUILD_DIR)/$(APP).o +APP_BIN = $(BUILD_DIR)/$(APP).bin +APP_CODE = $(APP).inc + +.PHONY: all clean + +all: $(BUILD_DIR) $(APP_OBJ) $(APP_CODE) + +$(BUILD_DIR): + $(Q) mkdir $@ + +$(APP_OBJ): $(SRCS) + @echo " CC $^ -> $@" + $(Q) $(CROSS)gcc -c $(CFLAGS) -o $@ $^ + +$(APP_CODE): $(APP_OBJ) + @echo " CC $^ -> $@" + $(Q) $(CROSS)objcopy -O binary -j.text $^ $(APP_BIN) + $(Q) $(BIN2C) < $(APP_BIN) > $@ + +clean: + $(Q) rm -rf $(BUILD_DIR) diff --git a/contrib/loaders/trampoline/espressif/xtensa/esp_xtensa_stub_tramp_win.S b/contrib/loaders/trampoline/espressif/xtensa/esp_xtensa_stub_tramp_win.S new file mode 100644 index 0000000000..e0c827d9f3 --- /dev/null +++ b/contrib/loaders/trampoline/espressif/xtensa/esp_xtensa_stub_tramp_win.S @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Xtensa flasher stub wrapper * + * Copyright (C) 2017 Espressif Systems Ltd. * + ***************************************************************************/ + +/* + * Expects : + * a0 = zero + * a1 = stack_base + stack_size - 16, 16 bytes aligned + * a8 = address of the function to call + * Params : + * a2 = command arg0, result (out) + * a3 = command arg1 + * a4 = command arg2 + * a5 = command arg3 + * a6 = command arg4 + * Maximum 5 user args + */ + .text + + .align 4 +_stub_enter: + /* initialize initial stack frame for callx8 */ + addi a9, sp, 32 /* point 16 past extra save area */ + s32e a9, sp, -12 /* access to extra save area */ + /* prepare args */ + mov a10, a2 + mov a11, a3 + mov a12, a4 + mov a13, a5 + mov a14, a6 + /* call stub */ + callx8 a8 + /* prepare return value */ + mov a2, a10 + break 0,0 + +_idle_loop: + j _idle_loop diff --git a/contrib/loaders/trampoline/espressif/xtensa/esp_xtensa_stub_tramp_win.inc b/contrib/loaders/trampoline/espressif/xtensa/esp_xtensa_stub_tramp_win.inc new file mode 100644 index 0000000000..1657223e1b --- /dev/null +++ b/contrib/loaders/trampoline/espressif/xtensa/esp_xtensa_stub_tramp_win.inc @@ -0,0 +1,3 @@ +/* Autogenerated with ../../../../../src/helper/bin2char.sh */ +0x92,0xc1,0x20,0x90,0xd1,0x49,0xad,0x02,0xbd,0x03,0xcd,0x04,0xdd,0x05,0x60,0xe6, +0x20,0xe0,0x08,0x00,0x2d,0x0a,0x00,0x40,0x00,0x06,0xff,0xff, diff --git a/contrib/loaders/watchdog/Makefile b/contrib/loaders/watchdog/Makefile index ed6d8f4e55..2da9c32eca 100644 --- a/contrib/loaders/watchdog/Makefile +++ b/contrib/loaders/watchdog/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + BIN2C = ../../../src/helper/bin2char.sh ARM_CROSS_COMPILE ?= arm-none-eabi- diff --git a/contrib/loaders/watchdog/armv7m_kinetis_wdog.s b/contrib/loaders/watchdog/armv7m_kinetis_wdog.s index 2a7eb89842..d4e78ea030 100644 --- a/contrib/loaders/watchdog/armv7m_kinetis_wdog.s +++ b/contrib/loaders/watchdog/armv7m_kinetis_wdog.s @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2015 Tomas Vanek * * vanekt@fbl.cz * - * * - * 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, write to the * - * Free Software Foundation, Inc. * ***************************************************************************/ /* diff --git a/contrib/loaders/watchdog/armv7m_kinetis_wdog32.s b/contrib/loaders/watchdog/armv7m_kinetis_wdog32.s index 1284ab0a2f..2d96346bab 100644 --- a/contrib/loaders/watchdog/armv7m_kinetis_wdog32.s +++ b/contrib/loaders/watchdog/armv7m_kinetis_wdog32.s @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2017 Tomas Vanek * * vanekt@fbl.cz * - * * - * 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, write to the * - * Free Software Foundation, Inc. * ***************************************************************************/ /* diff --git a/contrib/remote_bitbang/remote_bitbang_sysfsgpio.c b/contrib/remote_bitbang/remote_bitbang_sysfsgpio.c index 6cf30c3bc4..1588eb9a3c 100644 --- a/contrib/remote_bitbang/remote_bitbang_sysfsgpio.c +++ b/contrib/remote_bitbang/remote_bitbang_sysfsgpio.c @@ -1,41 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** + * Copyright (C) 2021 by Manuel Wick * * Copyright (C) 2013 Paul Fertser * * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au * - * * - * 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 . * ***************************************************************************/ /* - This is a test application to be used as a remote bitbang server for - the OpenOCD remote_bitbang interface driver. - - To compile run: - gcc -Wall -ansi -pedantic -std=c99 -o remote_bitbang_sysfsgpio remote_bitbang_sysfsgpio.c - - - Usage example: - - On Raspberry Pi run: - socat TCP6-LISTEN:7777,fork EXEC:"sudo ./remote_bitbang_sysfsgpio tck 11 tms 25 tdo 9 tdi 10" - - On host run: - openocd -c "interface remote_bitbang; remote_bitbang host raspberrypi; remote_bitbang port 7777" \ - -f target/stm32f1x.cfg - - Or if you want to test UNIX sockets, run both on Raspberry Pi: - socat UNIX-LISTEN:/tmp/remotebitbang-socket,fork EXEC:"sudo ./remote_bitbang_sysfsgpio tck 11 tms 25 tdo 9 tdi 10" - openocd -c "interface remote_bitbang; remote_bitbang host /tmp/remotebitbang-socket" -f target/stm32f1x.cfg + * This is a test application to be used as a remote bitbang server for + * the OpenOCD remote_bitbang interface driver. + * + * To compile run: + * gcc -Wall -ansi -pedantic -std=c99 -o remote_bitbang_sysfsgpio remote_bitbang_sysfsgpio.c + * + * + * Usage example: + * + * On Raspberry Pi run: + * socat TCP6-LISTEN:7777,fork EXEC:"sudo ./remote_bitbang_sysfsgpio tck 11 tms 25 tdo 9 tdi 10" + * + * On host run: + * openocd -c "adapter driver remote_bitbang; remote_bitbang host raspberrypi; remote_bitbang port 7777" \ + * -f target/stm32f1x.cfg + * + * Or if you want to test UNIX sockets, run both on Raspberry Pi: + * socat UNIX-LISTEN:/tmp/remotebitbang-socket,fork EXEC:"sudo ./remote_bitbang_sysfsgpio tck 11 tms 25 tdo 9 tdi 10" + * openocd -c "adapter driver remote_bitbang; remote_bitbang host /tmp/remotebitbang-socket" -f target/stm32f1x.cfg */ #include @@ -108,11 +98,14 @@ static void unexport_sysfs_gpio(int gpio) * If the gpio is an output, it is initialized according to init_high, * otherwise it is ignored. * + * When open_rw is set, the file descriptor will be open as read and write, + * e.g. for SWDIO (TMS) that is used as input and output. + * * If the gpio is already exported we just show a warning and continue; if * openocd happened to crash (or was killed by user) then the gpios will not * have been cleaned up. */ -static int setup_sysfs_gpio(int gpio, int is_output, int init_high) +static int setup_sysfs_gpio(int gpio, int is_output, int init_high, int open_rw) { char buf[40]; char gpiostr[4]; @@ -143,7 +136,9 @@ static int setup_sysfs_gpio(int gpio, int is_output, int init_high) } snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio); - if (is_output) + if (open_rw) + ret = open(buf, O_RDWR | O_NONBLOCK | O_SYNC); + else if (is_output) ret = open(buf, O_WRONLY | O_NONBLOCK | O_SYNC); else ret = open(buf, O_RDONLY | O_NONBLOCK | O_SYNC); @@ -154,6 +149,37 @@ static int setup_sysfs_gpio(int gpio, int is_output, int init_high) return ret; } +/* + * Change direction for gpio. + */ +static int change_dir_sysfs_gpio(int gpio, int is_output, int init_high) +{ + char buf[40]; + int ret; + + if (!is_gpio_valid(gpio)) + return ERROR_OK; + + snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", gpio); + ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in"); + if (ret < 0) { + LOG_ERROR("Couldn't set direction for gpio %d", gpio); + perror("sysfsgpio: "); + unexport_sysfs_gpio(gpio); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +/* gpio numbers for each gpio. Negative values are invalid */ +static int tck_gpio = -1; +static int tms_gpio = -1; +static int tdi_gpio = -1; +static int tdo_gpio = -1; +static int trst_gpio = -1; +static int srst_gpio = -1; + /* * file descriptors for /sys/class/gpio/gpioXX/value * Set up during init. @@ -165,6 +191,15 @@ static int tdo_fd = -1; static int trst_fd = -1; static int srst_fd = -1; +/* + * GPIO state of /sys/class/gpio/gpioXX/value + */ +static int last_tck = -1; +static int last_tms = -1; +static int last_tms_drive = -1; +static int last_tdi = -1; +static int last_initialized = -1; + /* * Bitbang interface read of TDO * @@ -190,26 +225,22 @@ static int sysfsgpio_read(void) /* * Bitbang interface write of TCK, TMS, TDI * - * Seeing as this is the only function where the outputs are changed, - * we can cache the old value to avoid needlessly writing it. + * Output states are changed here and in sysfsgpio_write_swd, + * which are not used simultaneously, so we can cache the old + * value to avoid needlessly writing it. */ static void sysfsgpio_write(int tck, int tms, int tdi) { const char one[] = "1"; const char zero[] = "0"; - static int last_tck; - static int last_tms; - static int last_tdi; - - static int first_time; size_t bytes_written; - if (!first_time) { + if (!last_initialized) { last_tck = !tck; last_tms = !tms; last_tdi = !tdi; - first_time = 1; + last_initialized = 1; } if (tdi != last_tdi) { @@ -262,13 +293,81 @@ static void sysfsgpio_reset(int trst, int srst) } } -/* gpio numbers for each gpio. Negative values are invalid */ -static int tck_gpio = -1; -static int tms_gpio = -1; -static int tdi_gpio = -1; -static int tdo_gpio = -1; -static int trst_gpio = -1; -static int srst_gpio = -1; +/* + * Bitbang interface set direction of SWDIO (TMS) + */ +static void sysfsgpio_swdio_drive(int is_output) +{ + int ret; + + if (is_output != 0 && last_tms == -1) + last_tms = 0; + + ret = change_dir_sysfs_gpio(tms_gpio, (is_output != 0) ? 1 : 0, last_tms); + if (ret != ERROR_OK) + LOG_WARNING("Failed to change SWDIO (TMS) direction to output"); + else + last_tms_drive = (is_output != 0) ? 1 : 0; +} + +/* + * Bitbang interface read of SWDIO (TMS) + * + * The sysfs value will read back either '0' or '1'. The trick here is to call + * lseek to bypass buffering in the sysfs kernel driver. + */ +static int sysfsgpio_swdio_read(void) +{ + char buf[1]; + + /* important to seek to signal sysfs of new read */ + lseek(tms_fd, 0, SEEK_SET); + int ret = read(tms_fd, &buf, sizeof(buf)); + + if (ret < 0) { + LOG_WARNING("reading swdio (tms) failed"); + return 0; + } + + return buf[0]; +} + +/* + * Bitbang interface write of SWCLK (TCK) and SWDIO (TMS) + * + * Output states are changed here and in sysfsgpio_write, which + * are not used simultaneously, so we can cache the old value + * to avoid needlessly writing it. + */ +static void sysfsgpio_swd_write(int swclk, int swdio) +{ + static const char one[] = "1"; + static const char zero[] = "0"; + + size_t bytes_written; + + if (!last_initialized) { + last_tck = !swclk; + last_tms = !swdio; + last_initialized = 1; + } + + if (last_tms_drive == 1 && swdio != last_tms) { + bytes_written = write(tms_fd, swdio ? &one : &zero, 1); + if (bytes_written != 1) + LOG_WARNING("writing swdio (tms) failed"); + } + + /* write clk last */ + if (swclk != last_tck) { + bytes_written = write(tck_fd, swclk ? &one : &zero, 1); + if (bytes_written != 1) + LOG_WARNING("writing swclk (tck) failed"); + } + + last_tms = swdio; + last_tck = swclk; +} /* helper func to close and cleanup files only if they were valid/ used */ static void cleanup_fd(int fd, int gpio) @@ -304,13 +403,21 @@ static void process_remote_protocol(void) char d = c - 'r'; sysfsgpio_reset(!!(d & 2), (d & 1)); - } else if (c >= '0' && c <= '0' + 7) {/* Write */ + } else if (c >= '0' && c <= '0' + 7) { /* Write */ char d = c - '0'; sysfsgpio_write(!!(d & 4), !!(d & 2), (d & 1)); } else if (c == 'R') putchar(sysfsgpio_read()); + else if (c == 'c') /* SWDIO read */ + putchar(sysfsgpio_swdio_read()); + else if (c == 'o' || c == 'O') /* SWDIO drive */ + sysfsgpio_swdio_drive(c == 'o' ? 0 : 1); + else if (c >= 'd' && c <= 'g') { /* SWD write */ + char d = c - 'd'; + sysfsgpio_swd_write((d & 2), (d & 1)); + } else LOG_ERROR("Unknown command '%c' received", c); } @@ -318,7 +425,7 @@ static void process_remote_protocol(void) int main(int argc, char *argv[]) { - LOG_WARNING("SysfsGPIO remote_bitbang JTAG driver\n"); + LOG_WARNING("SysfsGPIO remote_bitbang JTAG+SWD driver\n"); for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "tck")) @@ -360,36 +467,39 @@ int main(int argc, char *argv[]) * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. */ - tck_fd = setup_sysfs_gpio(tck_gpio, 1, 0); + tck_fd = setup_sysfs_gpio(tck_gpio, 1, 0, 0); if (tck_fd < 0) goto out_error; - tms_fd = setup_sysfs_gpio(tms_gpio, 1, 1); + tms_fd = setup_sysfs_gpio(tms_gpio, 1, 1, 1); if (tms_fd < 0) goto out_error; + last_tms_drive = 0; - tdi_fd = setup_sysfs_gpio(tdi_gpio, 1, 0); + tdi_fd = setup_sysfs_gpio(tdi_gpio, 1, 0, 0); if (tdi_fd < 0) goto out_error; - tdo_fd = setup_sysfs_gpio(tdo_gpio, 0, 0); + tdo_fd = setup_sysfs_gpio(tdo_gpio, 0, 0, 0); if (tdo_fd < 0) goto out_error; /* assume active low */ if (trst_gpio > 0) { - trst_fd = setup_sysfs_gpio(trst_gpio, 1, 1); + trst_fd = setup_sysfs_gpio(trst_gpio, 1, 1, 0); if (trst_fd < 0) goto out_error; } /* assume active low */ if (srst_gpio > 0) { - srst_fd = setup_sysfs_gpio(srst_gpio, 1, 1); + srst_fd = setup_sysfs_gpio(srst_gpio, 1, 1, 0); if (srst_fd < 0) goto out_error; } + last_initialized = 0; + LOG_WARNING("SysfsGPIO nums: tck = %d, tms = %d, tdi = %d, tdo = %d", tck_gpio, tms_gpio, tdi_gpio, tdo_gpio); LOG_WARNING("SysfsGPIO num: srst = %d", srst_gpio); diff --git a/contrib/rpc_examples/ocd_rpc_example.py b/contrib/rpc_examples/ocd_rpc_example.py index e6146f6179..53e3e2afcf 100755 --- a/contrib/rpc_examples/ocd_rpc_example.py +++ b/contrib/rpc_examples/ocd_rpc_example.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-3.0-or-later + """ OpenOCD RPC example, covered by GNU GPLv3 or later Copyright (C) 2014 Andreas Ortmann (ortmann@finf.uni-hannover.de) diff --git a/contrib/rpc_examples/ocdrpc.hs b/contrib/rpc_examples/ocdrpc.hs index 859864131d..6a92366b7a 100644 --- a/contrib/rpc_examples/ocdrpc.hs +++ b/contrib/rpc_examples/ocdrpc.hs @@ -1,4 +1,6 @@ --- OpenOCD RPC example, covered by GNU GPLv3 or later +-- SPDX-License-Identifier: GPL-3.0-or-later + +-- OpenOCD RPC example -- Copyright (C) 2014 Paul Fertser -- -- Example output: diff --git a/contrib/rtos-helpers/FreeRTOS-openocd.c b/contrib/rtos-helpers/FreeRTOS-openocd.c index 81a3ab77ab..5f82ac7a2c 100644 --- a/contrib/rtos-helpers/FreeRTOS-openocd.c +++ b/contrib/rtos-helpers/FreeRTOS-openocd.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: CC0-1.0 + /* * Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer * present in the kernel, so it has to be supplied by other means for diff --git a/contrib/rtos-helpers/uCOS-III-openocd.c b/contrib/rtos-helpers/uCOS-III-openocd.c index 5a37bd4c52..ff2789e0ab 100644 --- a/contrib/rtos-helpers/uCOS-III-openocd.c +++ b/contrib/rtos-helpers/uCOS-III-openocd.c @@ -1,3 +1,14 @@ +// SPDX-License-Identifier: Apache-2.0 + +/* + * The original version of this file did not reported any license nor + * copyright, but the author clearly stated that: + * "This file should be linked along with the [uC/OS-III user's] project + * to enable RTOS support for uC/OS-III." + * Such statement implies the willing to have this file's license compatible + * with the license Apache 2.0 of uC/OS-III. + */ + /* * uC/OS-III does not provide a fixed layout for OS_TCB, which makes it * impossible to determine the appropriate offsets within the structure diff --git a/contrib/xsvf_tools/svf2xsvf.py b/contrib/xsvf_tools/svf2xsvf.py index 6da7ff4a82..abbac20362 100644 --- a/contrib/xsvf_tools/svf2xsvf.py +++ b/contrib/xsvf_tools/svf2xsvf.py @@ -1,27 +1,9 @@ #!/usr/bin/python3.0 +# SPDX-License-Identifier: GPL-2.0-or-later # Copyright 2008, SoftPLC Corporation http://softplc.com # Dick Hollenbeck dick@softplc.com - -# 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, you may find one here: -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html -# or you may search the http://www.gnu.org website for the version 2 license, -# or you may write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - - # A python program to convert an SVF file to an XSVF file. There is an # option to include comments containing the source file line number from the origin # SVF file before each outputted XSVF statement. diff --git a/contrib/xsvf_tools/xsvfdump.py b/contrib/xsvf_tools/xsvfdump.py index 0e00ca05ce..3ed4009bdf 100644 --- a/contrib/xsvf_tools/xsvfdump.py +++ b/contrib/xsvf_tools/xsvfdump.py @@ -1,25 +1,9 @@ #!/usr/bin/python3.0 +# SPDX-License-Identifier: GPL-2.0-or-later # Copyright 2008, SoftPLC Corporation http://softplc.com # Dick Hollenbeck dick@softplc.com -# 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, you may find one here: -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html -# or you may search the http://www.gnu.org website for the version 2 license, -# or you may write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - # Dump an Xilinx XSVF file to stdout # This program is written for python 3.0, and it is not easy to change this diff --git a/doc/checkpatch.rst b/doc/checkpatch.rst new file mode 100644 index 0000000000..b52452bc29 --- /dev/null +++ b/doc/checkpatch.rst @@ -0,0 +1,1249 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +========== +Checkpatch +========== + +Checkpatch (scripts/checkpatch.pl) is a perl script which checks for trivial +style violations in patches and optionally corrects them. Checkpatch can +also be run on file contexts and without the kernel tree. + +Checkpatch is not always right. Your judgement takes precedence over checkpatch +messages. If your code looks better with the violations, then its probably +best left alone. + + +Options +======= + +This section will describe the options checkpatch can be run with. + +Usage:: + + ./scripts/checkpatch.pl [OPTION]... [FILE]... + +Available options: + + - -q, --quiet + + Enable quiet mode. + + - -v, --verbose + Enable verbose mode. Additional verbose test descriptions are output + so as to provide information on why that particular message is shown. + + - --no-tree + + Run checkpatch without the kernel tree. + + - --no-signoff + + Disable the 'Signed-off-by' line check. The sign-off is a simple line at + the end of the explanation for the patch, which certifies that you wrote it + or otherwise have the right to pass it on as an open-source patch. + + Example:: + + Signed-off-by: Random J Developer + + Setting this flag effectively stops a message for a missing signed-off-by + line in a patch context. + + - --patch + + Treat FILE as a patch. This is the default option and need not be + explicitly specified. + + - --emacs + + Set output to emacs compile window format. This allows emacs users to jump + from the error in the compile window directly to the offending line in the + patch. + + - --terse + + Output only one line per report. + + - --showfile + + Show the diffed file position instead of the input file position. + + - -g, --git + + Treat FILE as a single commit or a git revision range. + + Single commit with: + + - + - ^ + - ~n + + Multiple commits with: + + - .. + - ... + - - + + - -f, --file + + Treat FILE as a regular source file. This option must be used when running + checkpatch on source files in the kernel. + + - --subjective, --strict + + Enable stricter tests in checkpatch. By default the tests emitted as CHECK + do not activate by default. Use this flag to activate the CHECK tests. + + - --list-types + + Every message emitted by checkpatch has an associated TYPE. Add this flag + to display all the types in checkpatch. + + Note that when this flag is active, checkpatch does not read the input FILE, + and no message is emitted. Only a list of types in checkpatch is output. + + - --types TYPE(,TYPE2...) + + Only display messages with the given types. + + Example:: + + ./scripts/checkpatch.pl mypatch.patch --types EMAIL_SUBJECT,BRACES + + - --ignore TYPE(,TYPE2...) + + Checkpatch will not emit messages for the specified types. + + Example:: + + ./scripts/checkpatch.pl mypatch.patch --ignore EMAIL_SUBJECT,BRACES + + - --show-types + + By default checkpatch doesn't display the type associated with the messages. + Set this flag to show the message type in the output. + + - --max-line-length=n + + Set the max line length (default 100). If a line exceeds the specified + length, a LONG_LINE message is emitted. + + + The message level is different for patch and file contexts. For patches, + a WARNING is emitted. While a milder CHECK is emitted for files. So for + file contexts, the --strict flag must also be enabled. + + - --min-conf-desc-length=n + + Set the Kconfig entry minimum description length, if shorter, warn. + + - --tab-size=n + + Set the number of spaces for tab (default 8). + + - --root=PATH + + PATH to the kernel tree root. + + This option must be specified when invoking checkpatch from outside + the kernel root. + + - --no-summary + + Suppress the per file summary. + + - --mailback + + Only produce a report in case of Warnings or Errors. Milder Checks are + excluded from this. + + - --summary-file + + Include the filename in summary. + + - --debug KEY=[0|1] + + Turn on/off debugging of KEY, where KEY is one of 'values', 'possible', + 'type', and 'attr' (default is all off). + + - --fix + + This is an EXPERIMENTAL feature. If correctable errors exists, a file + .EXPERIMENTAL-checkpatch-fixes is created which has the + automatically fixable errors corrected. + + - --fix-inplace + + EXPERIMENTAL - Similar to --fix but input file is overwritten with fixes. + + DO NOT USE this flag unless you are absolutely sure and you have a backup + in place. + + - --ignore-perl-version + + Override checking of perl version. Runtime errors maybe encountered after + enabling this flag if the perl version does not meet the minimum specified. + + - --codespell + + Use the codespell dictionary for checking spelling errors. + + - --codespellfile + + Use the specified codespell file. + Default is '/usr/share/codespell/dictionary.txt'. + + - --typedefsfile + + Read additional types from this file. + + - --color[=WHEN] + + Use colors 'always', 'never', or only when output is a terminal ('auto'). + Default is 'auto'. + + - --kconfig-prefix=WORD + + Use WORD as a prefix for Kconfig symbols (default is `CONFIG_`). + + - -h, --help, --version + + Display the help text. + +Message Levels +============== + +Messages in checkpatch are divided into three levels. The levels of messages +in checkpatch denote the severity of the error. They are: + + - ERROR + + This is the most strict level. Messages of type ERROR must be taken + seriously as they denote things that are very likely to be wrong. + + - WARNING + + This is the next stricter level. Messages of type WARNING requires a + more careful review. But it is milder than an ERROR. + + - CHECK + + This is the mildest level. These are things which may require some thought. + +Type Descriptions +================= + +This section contains a description of all the message types in checkpatch. + +.. Types in this section are also parsed by checkpatch. +.. The types are grouped into subsections based on use. + + +Allocation style +---------------- + + **ALLOC_ARRAY_ARGS** + The first argument for kcalloc or kmalloc_array should be the + number of elements. sizeof() as the first argument is generally + wrong. + + See: https://www.kernel.org/doc/html/latest/core-api/memory-allocation.html + + **ALLOC_SIZEOF_STRUCT** + The allocation style is bad. In general for family of + allocation functions using sizeof() to get memory size, + constructs like:: + + p = alloc(sizeof(struct foo), ...) + + should be:: + + p = alloc(sizeof(*p), ...) + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#allocating-memory + + **ALLOC_WITH_MULTIPLY** + Prefer kmalloc_array/kcalloc over kmalloc/kzalloc with a + sizeof multiply. + + See: https://www.kernel.org/doc/html/latest/core-api/memory-allocation.html + + +API usage +--------- + + **ARCH_DEFINES** + Architecture specific defines should be avoided wherever + possible. + + **ARCH_INCLUDE_LINUX** + Whenever asm/file.h is included and linux/file.h exists, a + conversion can be made when linux/file.h includes asm/file.h. + However this is not always the case (See signal.h). + This message type is emitted only for includes from arch/. + + **AVOID_BUG** + BUG() or BUG_ON() should be avoided totally. + Use WARN() and WARN_ON() instead, and handle the "impossible" + error condition as gracefully as possible. + + See: https://www.kernel.org/doc/html/latest/process/deprecated.html#bug-and-bug-on + + **CONSIDER_KSTRTO** + The simple_strtol(), simple_strtoll(), simple_strtoul(), and + simple_strtoull() functions explicitly ignore overflows, which + may lead to unexpected results in callers. The respective kstrtol(), + kstrtoll(), kstrtoul(), and kstrtoull() functions tend to be the + correct replacements. + + See: https://www.kernel.org/doc/html/latest/process/deprecated.html#simple-strtol-simple-strtoll-simple-strtoul-simple-strtoull + + **CONSTANT_CONVERSION** + Use of __constant_ form is discouraged for the following functions:: + + __constant_cpu_to_be[x] + __constant_cpu_to_le[x] + __constant_be[x]_to_cpu + __constant_le[x]_to_cpu + __constant_htons + __constant_ntohs + + Using any of these outside of include/uapi/ is not preferred as using the + function without __constant_ is identical when the argument is a + constant. + + In big endian systems, the macros like __constant_cpu_to_be32(x) and + cpu_to_be32(x) expand to the same expression:: + + #define __constant_cpu_to_be32(x) ((__force __be32)(__u32)(x)) + #define __cpu_to_be32(x) ((__force __be32)(__u32)(x)) + + In little endian systems, the macros __constant_cpu_to_be32(x) and + cpu_to_be32(x) expand to __constant_swab32 and __swab32. __swab32 + has a __builtin_constant_p check:: + + #define __swab32(x) \ + (__builtin_constant_p((__u32)(x)) ? \ + ___constant_swab32(x) : \ + __fswab32(x)) + + So ultimately they have a special case for constants. + Similar is the case with all of the macros in the list. Thus + using the __constant_... forms are unnecessarily verbose and + not preferred outside of include/uapi. + + See: https://lore.kernel.org/lkml/1400106425.12666.6.camel@joe-AO725/ + + **DEPRECATED_API** + Usage of a deprecated RCU API is detected. It is recommended to replace + old flavourful RCU APIs by their new vanilla-RCU counterparts. + + The full list of available RCU APIs can be viewed from the kernel docs. + + See: https://www.kernel.org/doc/html/latest/RCU/whatisRCU.html#full-list-of-rcu-apis + + **DEPRECATED_VARIABLE** + EXTRA_{A,C,CPP,LD}FLAGS are deprecated and should be replaced by the new + flags added via commit f77bf01425b1 ("kbuild: introduce ccflags-y, + asflags-y and ldflags-y"). + + The following conversion scheme maybe used:: + + EXTRA_AFLAGS -> asflags-y + EXTRA_CFLAGS -> ccflags-y + EXTRA_CPPFLAGS -> cppflags-y + EXTRA_LDFLAGS -> ldflags-y + + See: + + 1. https://lore.kernel.org/lkml/20070930191054.GA15876@uranus.ravnborg.org/ + 2. https://lore.kernel.org/lkml/1313384834-24433-12-git-send-email-lacombar@gmail.com/ + 3. https://www.kernel.org/doc/html/latest/kbuild/makefiles.html#compilation-flags + + **DEVICE_ATTR_FUNCTIONS** + The function names used in DEVICE_ATTR is unusual. + Typically, the store and show functions are used with _store and + _show, where is a named attribute variable of the device. + + Consider the following examples:: + + static DEVICE_ATTR(type, 0444, type_show, NULL); + static DEVICE_ATTR(power, 0644, power_show, power_store); + + The function names should preferably follow the above pattern. + + See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes + + **DEVICE_ATTR_RO** + The DEVICE_ATTR_RO(name) helper macro can be used instead of + DEVICE_ATTR(name, 0444, name_show, NULL); + + Note that the macro automatically appends _show to the named + attribute variable of the device for the show method. + + See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes + + **DEVICE_ATTR_RW** + The DEVICE_ATTR_RW(name) helper macro can be used instead of + DEVICE_ATTR(name, 0644, name_show, name_store); + + Note that the macro automatically appends _show and _store to the + named attribute variable of the device for the show and store methods. + + See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes + + **DEVICE_ATTR_WO** + The DEVICE_AATR_WO(name) helper macro can be used instead of + DEVICE_ATTR(name, 0200, NULL, name_store); + + Note that the macro automatically appends _store to the + named attribute variable of the device for the store method. + + See: https://www.kernel.org/doc/html/latest/driver-api/driver-model/device.html#attributes + + **DUPLICATED_SYSCTL_CONST** + Commit d91bff3011cf ("proc/sysctl: add shared variables for range + check") added some shared const variables to be used instead of a local + copy in each source file. + + Consider replacing the sysctl range checking value with the shared + one in include/linux/sysctl.h. The following conversion scheme may + be used:: + + &zero -> SYSCTL_ZERO + &one -> SYSCTL_ONE + &int_max -> SYSCTL_INT_MAX + + See: + + 1. https://lore.kernel.org/lkml/20190430180111.10688-1-mcroce@redhat.com/ + 2. https://lore.kernel.org/lkml/20190531131422.14970-1-mcroce@redhat.com/ + + **ENOSYS** + ENOSYS means that a nonexistent system call was called. + Earlier, it was wrongly used for things like invalid operations on + otherwise valid syscalls. This should be avoided in new code. + + See: https://lore.kernel.org/lkml/5eb299021dec23c1a48fa7d9f2c8b794e967766d.1408730669.git.luto@amacapital.net/ + + **ENOTSUPP** + ENOTSUPP is not a standard error code and should be avoided in new patches. + EOPNOTSUPP should be used instead. + + See: https://lore.kernel.org/netdev/20200510182252.GA411829@lunn.ch/ + + **EXPORT_SYMBOL** + EXPORT_SYMBOL should immediately follow the symbol to be exported. + + **IN_ATOMIC** + in_atomic() is not for driver use so any such use is reported as an ERROR. + Also in_atomic() is often used to determine if sleeping is permitted, + but it is not reliable in this use model. Therefore its use is + strongly discouraged. + + However, in_atomic() is ok for core kernel use. + + See: https://lore.kernel.org/lkml/20080320201723.b87b3732.akpm@linux-foundation.org/ + + **LOCKDEP** + The lockdep_no_validate class was added as a temporary measure to + prevent warnings on conversion of device->sem to device->mutex. + It should not be used for any other purpose. + + See: https://lore.kernel.org/lkml/1268959062.9440.467.camel@laptop/ + + **MALFORMED_INCLUDE** + The #include statement has a malformed path. This has happened + because the author has included a double slash "//" in the pathname + accidentally. + + **USE_LOCKDEP** + lockdep_assert_held() annotations should be preferred over + assertions based on spin_is_locked() + + See: https://www.kernel.org/doc/html/latest/locking/lockdep-design.html#annotations + + **UAPI_INCLUDE** + No #include statements in include/uapi should use a uapi/ path. + + **USLEEP_RANGE** + usleep_range() should be preferred over udelay(). The proper way of + using usleep_range() is mentioned in the kernel docs. + + See: https://www.kernel.org/doc/html/latest/timers/timers-howto.html#delays-information-on-the-various-kernel-delay-sleep-mechanisms + + +Comments +-------- + + **BLOCK_COMMENT_STYLE** + The comment style is incorrect. The preferred style for multi- + line comments is:: + + /* + * This is the preferred style + * for multi line comments. + */ + + The networking comment style is a bit different, with the first line + not empty like the former:: + + /* This is the preferred comment style + * for files in net/ and drivers/net/ + */ + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#commenting + + **C99_COMMENTS** + C99 style single line comments (//) should not be used. + Prefer the block comment style instead. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#commenting + + **DATA_RACE** + Applications of data_race() should have a comment so as to document the + reasoning behind why it was deemed safe. + + See: https://lore.kernel.org/lkml/20200401101714.44781-1-elver@google.com/ + + **FSF_MAILING_ADDRESS** + Kernel maintainers reject new instances of the GPL boilerplate paragraph + directing people to write to the FSF for a copy of the GPL, since the + FSF has moved in the past and may do so again. + So do not write paragraphs about writing to the Free Software Foundation's + mailing address. + + See: https://lore.kernel.org/lkml/20131006222342.GT19510@leaf/ + + +Commit message +-------------- + + **BAD_SIGN_OFF** + The signed-off-by line does not fall in line with the standards + specified by the community. + + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#developer-s-certificate-of-origin-1-1 + + **BAD_STABLE_ADDRESS_STYLE** + The email format for stable is incorrect. + Some valid options for stable address are:: + + 1. stable@vger.kernel.org + 2. stable@kernel.org + + For adding version info, the following comment style should be used:: + + stable@vger.kernel.org # version info + + **COMMIT_COMMENT_SYMBOL** + Commit log lines starting with a '#' are ignored by git as + comments. To solve this problem addition of a single space + infront of the log line is enough. + + **COMMIT_MESSAGE** + The patch is missing a commit description. A brief + description of the changes made by the patch should be added. + + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes + + **EMAIL_SUBJECT** + Naming the tool that found the issue is not very useful in the + subject line. A good subject line summarizes the change that + the patch brings. + + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes + + **FROM_SIGN_OFF_MISMATCH** + The author's email does not match with that in the Signed-off-by: + line(s). This can be sometimes caused due to an improperly configured + email client. + + This message is emitted due to any of the following reasons:: + + - The email names do not match. + - The email addresses do not match. + - The email subaddresses do not match. + - The email comments do not match. + + **MISSING_SIGN_OFF** + The patch is missing a Signed-off-by line. A signed-off-by + line should be added according to Developer's certificate of + Origin. + + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin + + **NO_AUTHOR_SIGN_OFF** + The author of the patch has not signed off the patch. It is + required that a simple sign off line should be present at the + end of explanation of the patch to denote that the author has + written it or otherwise has the rights to pass it on as an open + source patch. + + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin + + **DIFF_IN_COMMIT_MSG** + Avoid having diff content in commit message. + This causes problems when one tries to apply a file containing both + the changelog and the diff because patch(1) tries to apply the diff + which it found in the changelog. + + See: https://lore.kernel.org/lkml/20150611134006.9df79a893e3636019ad2759e@linux-foundation.org/ + + **GERRIT_CHANGE_ID** + To be picked up by gerrit, the footer of the commit message might + have a Change-Id like:: + + Change-Id: Ic8aaa0728a43936cd4c6e1ed590e01ba8f0fbf5b + Signed-off-by: A. U. Thor + + The Change-Id line must be removed before submitting. + + **GIT_COMMIT_ID** + The proper way to reference a commit id is: + commit <12+ chars of sha1> ("") + + An example may be:: + + Commit e21d2170f36602ae2708 ("video: remove unnecessary + platform_set_drvdata()") removed the unnecessary + platform_set_drvdata(), but left the variable "dev" unused, + delete it. + + See: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes + + +Comparison style +---------------- + + **ASSIGN_IN_IF** + Do not use assignments in if condition. + Example:: + + if ((foo = bar(...)) < BAZ) { + + should be written as:: + + foo = bar(...); + if (foo < BAZ) { + + **BOOL_COMPARISON** + Comparisons of A to true and false are better written + as A and !A. + + See: https://lore.kernel.org/lkml/1365563834.27174.12.camel@joe-AO722/ + + **COMPARISON_TO_NULL** + Comparisons to NULL in the form (foo == NULL) or (foo != NULL) + are better written as (!foo) and (foo). + + **CONSTANT_COMPARISON** + Comparisons with a constant or upper case identifier on the left + side of the test should be avoided. + + +Indentation and Line Breaks +--------------------------- + + **CODE_INDENT** + Code indent should use tabs instead of spaces. + Outside of comments, documentation and Kconfig, + spaces are never used for indentation. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#indentation + + **DEEP_INDENTATION** + Indentation with 6 or more tabs usually indicate overly indented + code. + + It is suggested to refactor excessive indentation of + if/else/for/do/while/switch statements. + + See: https://lore.kernel.org/lkml/1328311239.21255.24.camel@joe2Laptop/ + + **SWITCH_CASE_INDENT_LEVEL** + switch should be at the same indent as case. + Example:: + + switch (suffix) { + case 'G': + case 'g': + mem <<= 30; + break; + case 'M': + case 'm': + mem <<= 20; + break; + case 'K': + case 'k': + mem <<= 10; + fallthrough; + default: + break; + } + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#indentation + + **LONG_LINE** + The line has exceeded the specified maximum length. + To use a different maximum line length, the --max-line-length=n option + may be added while invoking checkpatch. + + Earlier, the default line length was 80 columns. Commit bdc48fa11e46 + ("checkpatch/coding-style: deprecate 80-column warning") increased the + limit to 100 columns. This is not a hard limit either and it's + preferable to stay within 80 columns whenever possible. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings + + **LONG_LINE_STRING** + A string starts before but extends beyond the maximum line length. + To use a different maximum line length, the --max-line-length=n option + may be added while invoking checkpatch. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings + + **LONG_LINE_COMMENT** + A comment starts before but extends beyond the maximum line length. + To use a different maximum line length, the --max-line-length=n option + may be added while invoking checkpatch. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings + + **SPLIT_STRING** + Quoted strings that appear as messages in userspace and can be + grepped, should not be split across multiple lines. + + See: https://lore.kernel.org/lkml/20120203052727.GA15035@leaf/ + + **MULTILINE_DEREFERENCE** + A single dereferencing identifier spanned on multiple lines like:: + + struct_identifier->member[index]. + member = <foo>; + + is generally hard to follow. It can easily lead to typos and so makes + the code vulnerable to bugs. + + If fixing the multiple line dereferencing leads to an 80 column + violation, then either rewrite the code in a more simple way or if the + starting part of the dereferencing identifier is the same and used at + multiple places then store it in a temporary variable, and use that + temporary variable only at all the places. For example, if there are + two dereferencing identifiers:: + + member1->member2->member3.foo1; + member1->member2->member3.foo2; + + then store the member1->member2->member3 part in a temporary variable. + It not only helps to avoid the 80 column violation but also reduces + the program size by removing the unnecessary dereferences. + + But if none of the above methods work then ignore the 80 column + violation because it is much easier to read a dereferencing identifier + on a single line. + + **TRAILING_STATEMENTS** + Trailing statements (for example after any conditional) should be + on the next line. + Statements, such as:: + + if (x == y) break; + + should be:: + + if (x == y) + break; + + +Macros, Attributes and Symbols +------------------------------ + + **ARRAY_SIZE** + The ARRAY_SIZE(foo) macro should be preferred over + sizeof(foo)/sizeof(foo[0]) for finding number of elements in an + array. + + The macro is defined in include/linux/kernel.h:: + + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + + **AVOID_EXTERNS** + Function prototypes don't need to be declared extern in .h + files. It's assumed by the compiler and is unnecessary. + + **AVOID_L_PREFIX** + Local symbol names that are prefixed with `.L` should be avoided, + as this has special meaning for the assembler; a symbol entry will + not be emitted into the symbol table. This can prevent `objtool` + from generating correct unwind info. + + Symbols with STB_LOCAL binding may still be used, and `.L` prefixed + local symbol names are still generally usable within a function, + but `.L` prefixed local symbol names should not be used to denote + the beginning or end of code regions via + `SYM_CODE_START_LOCAL`/`SYM_CODE_END` + + **BIT_MACRO** + Defines like: 1 << <digit> could be BIT(digit). + The BIT() macro is defined via include/linux/bits.h:: + + #define BIT(nr) (1UL << (nr)) + + **CONST_READ_MOSTLY** + When a variable is tagged with the __read_mostly annotation, it is a + signal to the compiler that accesses to the variable will be mostly + reads and rarely(but NOT never) a write. + + const __read_mostly does not make any sense as const data is already + read-only. The __read_mostly annotation thus should be removed. + + **DATE_TIME** + It is generally desirable that building the same source code with + the same set of tools is reproducible, i.e. the output is always + exactly the same. + + The kernel does *not* use the ``__DATE__`` and ``__TIME__`` macros, + and enables warnings if they are used as they can lead to + non-deterministic builds. + + See: https://www.kernel.org/doc/html/latest/kbuild/reproducible-builds.html#timestamps + + **DEFINE_ARCH_HAS** + The ARCH_HAS_xyz and ARCH_HAVE_xyz patterns are wrong. + + For big conceptual features use Kconfig symbols instead. And for + smaller things where we have compatibility fallback functions but + want architectures able to override them with optimized ones, we + should either use weak functions (appropriate for some cases), or + the symbol that protects them should be the same symbol we use. + + See: https://lore.kernel.org/lkml/CA+55aFycQ9XJvEOsiM3txHL5bjUc8CeKWJNR_H+MiicaddB42Q@mail.gmail.com/ + + **DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON** + do {} while(0) macros should not have a trailing semicolon. + + **INIT_ATTRIBUTE** + Const init definitions should use __initconst instead of + __initdata. + + Similarly init definitions without const require a separate + use of const. + + **INLINE_LOCATION** + The inline keyword should sit between storage class and type. + + For example, the following segment:: + + inline static int example_function(void) + { + ... + } + + should be:: + + static inline int example_function(void) + { + ... + } + + **MISPLACED_INIT** + It is possible to use section markers on variables in a way + which gcc doesn't understand (or at least not the way the + developer intended):: + + static struct __initdata samsung_pll_clock exynos4_plls[nr_plls] = { + + does not put exynos4_plls in the .initdata section. The __initdata + marker can be virtually anywhere on the line, except right after + "struct". The preferred location is before the "=" sign if there is + one, or before the trailing ";" otherwise. + + See: https://lore.kernel.org/lkml/1377655732.3619.19.camel@joe-AO722/ + + **MULTISTATEMENT_MACRO_USE_DO_WHILE** + Macros with multiple statements should be enclosed in a + do - while block. Same should also be the case for macros + starting with `if` to avoid logic defects:: + + #define macrofun(a, b, c) \ + do { \ + if (a == 5) \ + do_this(b, c); \ + } while (0) + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#macros-enums-and-rtl + + **PREFER_FALLTHROUGH** + Use the `fallthrough;` pseudo keyword instead of + `/* fallthrough */` like comments. + + **TRAILING_SEMICOLON** + Macro definition should not end with a semicolon. The macro + invocation style should be consistent with function calls. + This can prevent any unexpected code paths:: + + #define MAC do_something; + + If this macro is used within a if else statement, like:: + + if (some_condition) + MAC; + + else + do_something; + + Then there would be a compilation error, because when the macro is + expanded there are two trailing semicolons, so the else branch gets + orphaned. + + See: https://lore.kernel.org/lkml/1399671106.2912.21.camel@joe-AO725/ + + **SINGLE_STATEMENT_DO_WHILE_MACRO** + For the multi-statement macros, it is necessary to use the do-while + loop to avoid unpredictable code paths. The do-while loop helps to + group the multiple statements into a single one so that a + function-like macro can be used as a function only. + + But for the single statement macros, it is unnecessary to use the + do-while loop. Although the code is syntactically correct but using + the do-while loop is redundant. So remove the do-while loop for single + statement macros. + + **WEAK_DECLARATION** + Using weak declarations like __attribute__((weak)) or __weak + can have unintended link defects. Avoid using them. + + +Functions and Variables +----------------------- + + **CAMELCASE** + Avoid CamelCase Identifiers. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#naming + + **CONST_CONST** + Using `const <type> const *` is generally meant to be + written `const <type> * const`. + + **CONST_STRUCT** + Using const is generally a good idea. Checkpatch reads + a list of frequently used structs that are always or + almost always constant. + + The existing structs list can be viewed from + `scripts/const_structs.checkpatch`. + + See: https://lore.kernel.org/lkml/alpine.DEB.2.10.1608281509480.3321@hadrien/ + + **EMBEDDED_FUNCTION_NAME** + Embedded function names are less appropriate to use as + refactoring can cause function renaming. Prefer the use of + "%s", __func__ to embedded function names. + + Note that this does not work with -f (--file) checkpatch option + as it depends on patch context providing the function name. + + **FUNCTION_ARGUMENTS** + This warning is emitted due to any of the following reasons: + + 1. Arguments for the function declaration do not follow + the identifier name. Example:: + + void foo + (int bar, int baz) + + This should be corrected to:: + + void foo(int bar, int baz) + + 2. Some arguments for the function definition do not + have an identifier name. Example:: + + void foo(int) + + All arguments should have identifier names. + + **FUNCTION_WITHOUT_ARGS** + Function declarations without arguments like:: + + int foo() + + should be:: + + int foo(void) + + **GLOBAL_INITIALISERS** + Global variables should not be initialized explicitly to + 0 (or NULL, false, etc.). Your compiler (or rather your + loader, which is responsible for zeroing out the relevant + sections) automatically does it for you. + + **INITIALISED_STATIC** + Static variables should not be initialized explicitly to zero. + Your compiler (or rather your loader) automatically does + it for you. + + **MULTIPLE_ASSIGNMENTS** + Multiple assignments on a single line makes the code unnecessarily + complicated. So on a single line assign value to a single variable + only, this makes the code more readable and helps avoid typos. + + **RETURN_PARENTHESES** + return is not a function and as such doesn't need parentheses:: + + return (bar); + + can simply be:: + + return bar; + + +Permissions +----------- + + **DEVICE_ATTR_PERMS** + The permissions used in DEVICE_ATTR are unusual. + Typically only three permissions are used - 0644 (RW), 0444 (RO) + and 0200 (WO). + + See: https://www.kernel.org/doc/html/latest/filesystems/sysfs.html#attributes + + **EXECUTE_PERMISSIONS** + There is no reason for source files to be executable. The executable + bit can be removed safely. + + **EXPORTED_WORLD_WRITABLE** + Exporting world writable sysfs/debugfs files is usually a bad thing. + When done arbitrarily they can introduce serious security bugs. + In the past, some of the debugfs vulnerabilities would seemingly allow + any local user to write arbitrary values into device registers - a + situation from which little good can be expected to emerge. + + See: https://lore.kernel.org/linux-arm-kernel/cover.1296818921.git.segoon@openwall.com/ + + **NON_OCTAL_PERMISSIONS** + Permission bits should use 4 digit octal permissions (like 0700 or 0444). + Avoid using any other base like decimal. + + **SYMBOLIC_PERMS** + Permission bits in the octal form are more readable and easier to + understand than their symbolic counterparts because many command-line + tools use this notation. Experienced kernel developers have been using + these traditional Unix permission bits for decades and so they find it + easier to understand the octal notation than the symbolic macros. + For example, it is harder to read S_IWUSR|S_IRUGO than 0644, which + obscures the developer's intent rather than clarifying it. + + See: https://lore.kernel.org/lkml/CA+55aFw5v23T-zvDZp-MmD_EYxF8WbafwwB59934FV7g21uMGQ@mail.gmail.com/ + + +Spacing and Brackets +-------------------- + + **ASSIGNMENT_CONTINUATIONS** + Assignment operators should not be written at the start of a + line but should follow the operand at the previous line. + + **BRACES** + The placement of braces is stylistically incorrect. + The preferred way is to put the opening brace last on the line, + and put the closing brace first:: + + if (x is true) { + we do y + } + + This applies for all non-functional blocks. + However, there is one special case, namely functions: they have the + opening brace at the beginning of the next line, thus:: + + int function(int x) + { + body of function + } + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces + + **BRACKET_SPACE** + Whitespace before opening bracket '[' is prohibited. + There are some exceptions: + + 1. With a type on the left:: + + int [] a; + + 2. At the beginning of a line for slice initialisers:: + + [0...10] = 5, + + 3. Inside a curly brace:: + + = { [0...10] = 5 } + + **CONCATENATED_STRING** + Concatenated elements should have a space in between. + Example:: + + printk(KERN_INFO"bar"); + + should be:: + + printk(KERN_INFO "bar"); + + **ELSE_AFTER_BRACE** + `else {` should follow the closing block `}` on the same line. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces + + **LINE_SPACING** + Vertical space is wasted given the limited number of lines an + editor window can display when multiple blank lines are used. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces + + **OPEN_BRACE** + The opening brace should be following the function definitions on the + next line. For any non-functional block it should be on the same line + as the last construct. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces + + **POINTER_LOCATION** + When using pointer data or a function that returns a pointer type, + the preferred use of * is adjacent to the data name or function name + and not adjacent to the type name. + Examples:: + + char *linux_banner; + unsigned long long memparse(char *ptr, char **retptr); + char *match_strdup(substring_t *s); + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces + + **SPACING** + Whitespace style used in the kernel sources is described in kernel docs. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces + + **TRAILING_WHITESPACE** + Trailing whitespace should always be removed. + Some editors highlight the trailing whitespace and cause visual + distractions when editing files. + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#spaces + + **UNNECESSARY_PARENTHESES** + Parentheses are not required in the following cases: + + 1. Function pointer uses:: + + (foo->bar)(); + + could be:: + + foo->bar(); + + 2. Comparisons in if:: + + if ((foo->bar) && (foo->baz)) + if ((foo == bar)) + + could be:: + + if (foo->bar && foo->baz) + if (foo == bar) + + 3. addressof/dereference single Lvalues:: + + &(foo->bar) + *(foo->bar) + + could be:: + + &foo->bar + *foo->bar + + **WHILE_AFTER_BRACE** + while should follow the closing bracket on the same line:: + + do { + ... + } while(something); + + See: https://www.kernel.org/doc/html/latest/process/coding-style.html#placing-braces-and-spaces + + +Others +------ + + **CONFIG_DESCRIPTION** + Kconfig symbols should have a help text which fully describes + it. + + **CORRUPTED_PATCH** + The patch seems to be corrupted or lines are wrapped. + Please regenerate the patch file before sending it to the maintainer. + + **CVS_KEYWORD** + Since linux moved to git, the CVS markers are no longer used. + So, CVS style keywords ($Id$, $Revision$, $Log$) should not be + added. + + **DEFAULT_NO_BREAK** + switch default case is sometimes written as "default:;". This can + cause new cases added below default to be defective. + + A "break;" should be added after empty default statement to avoid + unwanted fallthrough. + + **DOS_LINE_ENDINGS** + For DOS-formatted patches, there are extra ^M symbols at the end of + the line. These should be removed. + + **DT_SCHEMA_BINDING_PATCH** + DT bindings moved to a json-schema based format instead of + freeform text. + + See: https://www.kernel.org/doc/html/latest/devicetree/bindings/writing-schema.html + + **DT_SPLIT_BINDING_PATCH** + Devicetree bindings should be their own patch. This is because + bindings are logically independent from a driver implementation, + they have a different maintainer (even though they often + are applied via the same tree), and it makes for a cleaner history in the + DT only tree created with git-filter-branch. + + See: https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters + + **EMBEDDED_FILENAME** + Embedding the complete filename path inside the file isn't particularly + useful as often the path is moved around and becomes incorrect. + + **FILE_PATH_CHANGES** + Whenever files are added, moved, or deleted, the MAINTAINERS file + patterns can be out of sync or outdated. + + So MAINTAINERS might need updating in these cases. + + **MEMSET** + The memset use appears to be incorrect. This may be caused due to + badly ordered parameters. Please recheck the usage. + + **NOT_UNIFIED_DIFF** + The patch file does not appear to be in unified-diff format. Please + regenerate the patch file before sending it to the maintainer. + + **PRINTF_0XDECIMAL** + Prefixing 0x with decimal output is defective and should be corrected. + + **SPDX_LICENSE_TAG** + The source file is missing or has an improper SPDX identifier tag. + The Linux kernel requires the precise SPDX identifier in all source files, + and it is thoroughly documented in the kernel docs. + + See: https://www.kernel.org/doc/html/latest/process/license-rules.html + + **TYPO_SPELLING** + Some words may have been misspelled. Consider reviewing them. diff --git a/doc/manual/endianness.txt b/doc/manual/endianness.txt new file mode 100644 index 0000000000..bba2116b5f --- /dev/null +++ b/doc/manual/endianness.txt @@ -0,0 +1,197 @@ +/** @page endianness About endianness + +OpenOCD has to potentially deal with different endianness between: +- the host PC endianness; +- the data endianness during communication between host and adapter; +- the target CPU endianness. + +The whole OpenOCD code should be written to handle any endianness +mismatch and should run on either little and big endian hosts. + +Big-endian host PC are becoming less and less common since Apple™ has +switched away from big-endian PowerPC™ in favor of little-endian intel +X86™. + +The lack of commercial big-endian hosts makes hard testing OpenOCD correctness +on big-endian hosts. Running OpenOCD on low-cost commercial routers based on +big-endian MIPS is possible, but it's tricky to properly setup the system and +the cross-compiling environment. + +In next sections there are two example on how to compile and test OpenOCD in an +emulated big-endian environment. + + +@section endianness_helpers OpenOCD API for handling endianness + +Use the following OpenOCD API to handle endianness conversions: +- host endianness to/from little endian: + - le_to_h_u64(), le_to_h_u32(), le_to_h_u16(); + - h_u64_to_le(), h_u32_to_le(), h_u16_to_le(); + - buf_get_u32(), buf_get_u64(); + - buf_set_u32(), buf_set_u64(); +- host endianness to/from big endian: + - be_to_h_u64(), be_to_h_u32(), be_to_h_u16(); + - h_u64_to_be(), h_u32_to_be(), h_u16_to_be(); +- host endianness to/from target endianness: + - target_read_u64(), target_read_u32(), target_read_u16(); + - target_write_u64(), target_write_u32(), target_write_u16(); + - target_write_phys_u64(), target_write_phys_u32(), target_write_phys_u16(); + - target_buffer_get_u64(), target_buffer_get_u32(), target_buffer_get_u24(), target_buffer_get_u16(); + - target_buffer_set_u64(), target_buffer_set_u32(), target_buffer_set_u24(), target_buffer_set_u16(); +- byte swap: + - buf_bswap32(), buf_bswap16(). + + +@section endianness_docker Use dockers to run different endianness + + +Docker can run a full Linux image that includes the toolchain through QEMU +emulator. +By selecting a big-endian image, it's possible to compile and execute OpenOCD +in big-endian. +There are, so far, not many options for big-endian images; s390x is one of the +few available. + +To be expanded. + +User should: +- install docker; +- download the big-endian image; +- run the image in docker; +- download, in the image, the OpenOCD code to test; +- recompile OpenOCD code in the image; +- run OpenOCD binary in the image. + +From https://github.com/multiarch/qemu-user-static + + @code{.unparsed} + docker run --rm -t s390x/ubuntu bash + @endcode + + +@section endianness_qemu Use buildroot and QEMU to run different endianness + +QEMU User Mode Emulation is an efficient method to launch, on host's CPU, +applications compiled for another CPU and/or for different endianness. +It works either on Linux and BSD. More info available on +https://www.qemu.org/docs/master/user/index.html + +With QEMU User Mode Emulation is thus possible running, on a commonly available +little-endian X86 Linux host, OpenOCD compiled for a big-endian host. + +The following example will show how to use buildroot to: +- build big-endian toolchain and libraries; +- compile OpenOCD for big-endian; +- run the big-endian OpenOCD on little-endian Linux PC. + +The example will use ARM Cortex-A7 big-endian only because I personally feel +comfortable reading ARM assembly during debug. User can select other CPU +architectures, as this does not impact the result. + +A similar method can be used to test OpenOCD compiled for 32 vs 64 bit host. + +@note +- the version of autotools locally installer in your Linux host can be + incompatible with the version of autotools used by buildroot. This can cause + the build to fail if buildroot has to run its autotools on a partially + configured OpenOCD folder. Use either a clean copy of OpenOCD code in 2., or + run "./bootstrap" in OpenOCD folder to prevent buildroot from using its own + autotools; +- the configuration tool in 4. and 5. matches the version of OpenOCD used by + buildroot. Some new driver could be not listed in. OpenOCD will build every + driver that is not disabled and with satisfied dependencies. If the driver + you plan to use is not listed, try a first build and check OpenOCD with + command "adapter list", then try to hack the buildroot files Config.in and + openocd.mk in folder package/openocd/ and use "make openocd-reconfigure" to + rerun the build starting with configuration; +- using pre-built toolchains, you need 2GB of disk space for buildroot build. + To also rebuild the toolchains you will need ~5GB and much longer time for + the first build (it takes ~2 hour on my crap 10+ years old laptop); +- you need to install few tools for buildroot dependency, listed in + https://buildroot.org/downloads/manual/manual.html#requirement ; +- you need to install qemu-armeb. On Arch Linux it's in package qemu-arch-extra; + on Ubuntu/debian it's packaged in qemu-user. + Buildroot can also be configured to build qemu for the host, if you prefer, + by enabling BR2_PACKAGE_HOST_QEMU_LINUX_USER_MODE, but this takes longer + compile time; +- don't use qemu-system-arm, as it emulates a complete system and requires a + fully bootable ARM image; +- while QEMU User Mode Emulation is available for both Linux and BSD, buildroot + only builds binaries for Linux target. This example can only be used with + Linux hosts emulating the Linux target. + + +Steps to run big-endian OpenOCD on little-endian host Linux PC: + +1. Get buildroot source. Today's latest version is "2022.02": + @code{.unparsed} + wget https://buildroot.org/downloads/buildroot-2022.02.tar.xz + tar xf buildroot-2022.02.tar.xz + cd buildroot-2022.02 + @endcode + +2. Override the source repo for OpenOCD in order to build your own code version + in place of the default OpenOCD release version: + @code{.unparsed} + echo OPENOCD_OVERRIDE_SRCDIR=/home/me/openocd.git >> local.mk + @endcode + +3. Copy default config for OpenOCD big-endian. This used: + - ARM Cortex-A7 big-endian target, + - external Linaro armeb toolchain (to speed up first build), + - OpenOCD all configure options enabled. + + @code{.unparsed} + cp $OPENOCD_OVERRIDE_SRCDIR/contrib/buildroot/openocd_be_defconfig configs/ + @endcode + +4. Configure buildroot with default config for OpenOCD big-endian: + @code{.unparsed} + make openocd_be_defconfig + @endcode + +5. Optional, change buildroot configuration: + @code{.unparsed} + make menuconfig + @endcode + These are the options selected with default config for OpenOCD big-endian: + @code{.unparsed} + Target options ---> + Target Architecture ---> + ARM (big endian) + Target Architecture Variant ---> + cortex-A7 + Toolchain ---> + Toolchain type ---> + External toolchain + Toolchain ---> + Linaro armeb 2018.05 + Toolchain origin ---> + Toolchain to be downloaded and installed + Target packages ---> + Hardware handling ---> + openocd + All adapters selected + @endcode + Save and exit + +6. Build (and take a long coffee break ...): + @code{.unparsed} + make openocd + @endcode + +7. Execute big-endian OpenOCD: + @code{.unparsed} + cd output/target + qemu-armeb -cpu cortex-a7 -L . usr/bin/openocd -s usr/share/openocd/scripts/ -f board/st_nucleo_f4.cfg + @endcode + +8. Optional, to rebuild after any source code modification in ${OPENOCD_OVERRIDE_SRCDIR}: + @code{.unparsed} + make openocd-rebuild + @endcode + + */ +/** @file +This file contains the @ref endianness page. + */ diff --git a/doc/manual/helper.txt b/doc/manual/helper.txt index d5710ddde8..b59fd664fb 100644 --- a/doc/manual/helper.txt +++ b/doc/manual/helper.txt @@ -79,6 +79,8 @@ command handlers and helpers: - @c CMD_NAME - invoked command name - @c CMD_ARGC - the number of command arguments - @c CMD_ARGV - array of command argument strings +- @c CMD_JIMTCL_ARGV - array containing the Jim_Obj equivalent of command + argument in @c CMD_ARGV. @section helpercmdregister Command Registration diff --git a/doc/manual/jtag/drivers/remote_bitbang.txt b/doc/manual/jtag/drivers/remote_bitbang.txt index f394d736af..94d6038163 100644 --- a/doc/manual/jtag/drivers/remote_bitbang.txt +++ b/doc/manual/jtag/drivers/remote_bitbang.txt @@ -1,15 +1,19 @@ /** @remote_bitbangpage OpenOCD Developer's Guide -The remote_bitbang JTAG driver is used to drive JTAG from a remote process. The -remote_bitbang driver communicates via TCP or UNIX sockets with some remote -process using an ASCII encoding of the bitbang interface. The remote process -presumably then drives the JTAG however it pleases. The remote process should -act as a server, listening for connections from the openocd remote_bitbang -driver. +The remote_bitbang JTAG+SWD driver is used to drive JTAG and/or SWD from a +remote process. The remote_bitbang driver communicates via TCP or UNIX +sockets with some remote process using an ASCII encoding of the bitbang +interface. The remote process presumably then drives the JTAG/SWD however +it pleases. The remote process should act as a server, listening for +connections from the openocd remote_bitbang driver. The remote bitbang driver is useful for debugging software running on processors which are being simulated. +There also is an implementation of the server-side protocol for the +Glasgow Debug Tool (https://github.com/glasgowEmbedded/Glasgow) through +the jtag-openocd applet. + The bitbang interface consists of the following functions. blink on @@ -24,12 +28,25 @@ write tck tms tdi reset trst srst Set the value of trst, srst. +swdio_drive + Set the output enable of the bidirectional swdio (tms) pin + +swdio_read + Sample the value of swdio (tms). + +swd_write + Set the value of swclk (tck) and swdio (tms). + +(optional) sleep + Instructs the remote host to sleep/idle for some period of time before + executing the next request + An additional function, quit, is added to the remote_bitbang interface to indicate there will be no more requests and the connection with the remote driver should be closed. -These five functions are encoded in ASCII by assigning a single character to -each possible request. The assignments are: +The eight mandatory functions are encoded in ASCII by assigning a single +character to each possible request. The assignments are: B - Blink on b - Blink off @@ -47,7 +64,20 @@ each possible request. The assignments are: s - Reset 0 1 t - Reset 1 0 u - Reset 1 1 + O - SWDIO drive 1 + o - SWDIO drive 0 + c - SWDIO read request + d - SWD write 0 0 + e - SWD write 0 1 + f - SWD write 1 0 + g - SWD write 1 1 + +The read responses are encoded in ASCII as either digit 0 or 1. + +If the use_remote_sleep option is set to 'yes', two additional requests may +be sent: -The read response is encoded in ASCII as either digit 0 or 1. + D - Sleep for 1 millisecond + d - Sleep for 1 microsecond */ diff --git a/doc/manual/main.txt b/doc/manual/main.txt index 14c64c2e76..c28fbe2288 100644 --- a/doc/manual/main.txt +++ b/doc/manual/main.txt @@ -19,6 +19,8 @@ check the mailing list archives to find the status of your feature (or bug). - The @subpage bugs page contains the content of the BUGS file, which provides instructions for submitting bug reports to the maintainers. - The @subpage releases page describes the project's release process. +- The @subpage endianness provides hints about writing and testing + endianness independent code for OpenOCD. @ref primer provide introductory materials for new developers on various specific topics. diff --git a/doc/manual/style.txt b/doc/manual/style.txt index 58f39807e2..1d3ec6748d 100644 --- a/doc/manual/style.txt +++ b/doc/manual/style.txt @@ -111,8 +111,8 @@ Finally, try to avoid lines of code that are longer than 72-80 columns: @section stylenames Naming Rules - most identifiers must use lower-case letters (and digits) only. - - macros must use upper-case letters (and digits) only. - - OpenOCD identifiers should NEVER use @c MixedCaps. + - macros and enumerators must use upper-case letters (and digits) only. + - OpenOCD identifiers should NEVER use @c MixedCaps, aka @c CamelCase. - @c typedef names must end with the '_t' suffix. - This should be reserved for types that should be passed by value. - Do @b not mix the typedef keyword with @c struct. diff --git a/doc/openocd.texi b/doc/openocd.texi index e671b80b52..384f6d2b7a 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -19,7 +19,7 @@ dated @value{UPDATED}, of the Open On-Chip Debugger (OpenOCD). @itemize @bullet -@item Copyright @copyright{} 2008 The OpenOCD Project +@item Copyright @copyright{} 2008-2022 The OpenOCD Project @item Copyright @copyright{} 2007-2008 Spencer Oliver @email{spen@@spen-soft.co.uk} @item Copyright @copyright{} 2008-2010 Oyvind Harboe @email{oyvind.harboe@@zylin.com} @item Copyright @copyright{} 2008 Duane Ellis @email{openocd@@duaneellis.com} @@ -463,6 +463,12 @@ They only work with STMicroelectronics chips, notably STM32 and STM8. @item @b{STLINK-V3} @* This is available standalone and as part of some kits. @* Link: @url{http://www.st.com/stlink-v3} +@item @b{STLINK-V3PWR} +@* This is available standalone. +Beside the debugger functionality, the probe includes a SMU (source +measurement unit) aimed at analyzing power consumption during code +execution. The SMU is not supported by OpenOCD. +@* Link: @url{http://www.st.com/stlink-v3pwr} @end itemize For info the original ST-LINK enumerates using the mass storage usb class; however, @@ -502,6 +508,9 @@ debuggers to ARM Cortex based targets @url{http://www.keil.com/support/man/docs/ @item @b{ARM-JTAG-EW} @* Link: @url{http://www.olimex.com/dev/arm-jtag-ew.html} +@item @b{angie} +@* Link: @url{https://nanoxplore.org/} + @item @b{Buspirate} @* Link: @url{http://dangerousprototypes.com/bus-pirate-manual/} @@ -584,6 +593,9 @@ produced, PDF schematics are easily found and it is easy to make. @item @b{imx_gpio} @* A NXP i.MX-based board (e.g. Wandboard) using the GPIO pins (should work on any i.MX processor). +@item @b{am335xgpio} +@* A Texas Instruments AM335x-based board (e.g. BeagleBone Black) using the GPIO pins of the expansion headers. + @item @b{jtag_vpi} @* A JTAG driver acting as a client for the JTAG VPI server interface. @* Link: @url{http://github.com/fjullien/jtag_vpi} @@ -591,8 +603,8 @@ produced, PDF schematics are easily found and it is easy to make. @item @b{vdebug} @* A driver for Cadence virtual Debug Interface to emulated or simulated targets. It implements a client connecting to the vdebug server, which in turn communicates -with the emulated or simulated RTL model through a transactor. The current version -supports only JTAG as a transport, but other virtual transports, like DAP are planned. +with the emulated or simulated RTL model through a transactor. The driver supports +JTAG and DAP-level transports. @item @b{jtag_dpi} @* A JTAG driver acting as a client for the SystemVerilog Direct Programming @@ -610,6 +622,9 @@ emulation model of target hardware. @* A bitbang JTAG driver using Linux legacy sysfs GPIO. This is deprecated from Linux v5.3; prefer using @b{linuxgpiod}. +@item @b{esp_usb_jtag} +@* A JTAG driver to communicate with builtin debug modules of Espressif ESP32-C3 and ESP32-S3 chips using OpenOCD. + @end itemize @node About Jim-Tcl @@ -1779,7 +1794,6 @@ $_TARGETNAME configure -work-area-phys 0x00200000 \ -work-area-size 0x4000 -work-area-backup 0 @end example -@anchor{definecputargetsworkinginsmp} @subsection Define CPU targets working in SMP @cindex SMP After setting targets, you can define a list of targets working in SMP. @@ -1933,7 +1947,6 @@ For an example of this scheme see LPC2000 target config files. The @code{init_boards} procedure is a similar concept concerning board config files (@xref{theinitboardprocedure,,The init_board procedure}.) -@anchor{theinittargeteventsprocedure} @subsection The init_target_events procedure @cindex init_target_events procedure @@ -2120,6 +2133,15 @@ corresponding subsystems: @deffnx {Config Command} {pld init} @deffnx {Command} {tpiu init} @end deffn + +At last, @command{init} executes all the commands that are specified in +the TCL list @var{post_init_commands}. The commands are executed in the +same order they occupy in the list. If one of the commands fails, then +the error is propagated and OpenOCD fails too. +@example +lappend post_init_commands @{echo "OpenOCD successfully initialized."@} +lappend post_init_commands @{echo "Have fun with OpenOCD !"@} +@end example @end deffn @deffn {Config Command} {noinit} @@ -2161,6 +2183,9 @@ In such cases, just specify the relevant port number as "disabled". If you disable all access through TCP/IP, you will need to use the command line @option{-pipe} option. +You can request the operating system to select one of the available +ports for the server by specifying the relevant port number as "0". + @anchor{gdb_port} @deffn {Config Command} {gdb_port} [number] @cindex GDB server @@ -2397,13 +2422,62 @@ when external configuration (such as jumpering) changes what the hardware can support. @end deffn +@anchor{adapter gpio} +@deffn {Config Command} {adapter gpio [ @ + @option{tdo} | @option{tdi} | @option{tms} | @option{tck} | @option{trst} | @ + @option{swdio} | @option{swdio_dir} | @option{swclk} | @option{srst} | @ + @option{led} @ + [ @ + gpio_number | @option{-chip} chip_number | @ + @option{-active-high} | @option{-active-low} | @ + @option{-push-pull} | @option{-open-drain} | @option{-open-source} | @ + @option{-pull-none} | @option{-pull-up} | @option{-pull-down} | @ + @option{-init-inactive} | @option{-init-active} | @option{-init-input} @ + ] ]} +Define the GPIO mapping that the adapter will use. The following signals can be +defined: + +@itemize @minus +@item @option{tdo}, @option{tdi}, @option{tms}, @option{tck}, @option{trst}: +JTAG transport signals +@item @option{swdio}, @option{swclk}: SWD transport signals +@item @option{swdio_dir}: optional swdio buffer control signal +@item @option{srst}: system reset signal +@item @option{led}: optional activity led + +@end itemize + +Some adapters require that the GPIO chip number is set in addition to the GPIO +number. The configuration options enable signals to be defined as active-high or +active-low. The output drive mode can be set to push-pull, open-drain or +open-source. Most adapters will have to emulate open-drain or open-source drive +modes by switching between an input and output. Input and output signals can be +instructed to use a pull-up or pull-down resistor, assuming it is supported by +the adaptor driver and hardware. The initial state of outputs may also be set, +"active" state means 1 for active-high outputs and 0 for active-low outputs. +Bidirectional signals may also be initialized as an input. If the swdio signal +is buffered the buffer direction can be controlled with the swdio_dir signal; +the active state means that the buffer should be set as an output with respect +to the adapter. The command options are cumulative with later commands able to +override settings defined by earlier ones. The two commands @command{gpio led 7 +-active-high} and @command{gpio led -chip 1 -active-low} sent sequentially are +equivalent to issuing the single command @command{gpio led 7 -chip 1 +-active-low}. It is not permissible to set the drive mode or initial state for +signals which are inputs. The drive mode for the srst and trst signals must be +set with the @command{adapter reset_config} command. It is not permissible to +set the initial state of swdio_dir as it is derived from the initial state of +swdio. The command @command{adapter gpio} prints the current configuration for +all GPIOs while the command @command{adapter gpio gpio_name} prints the current +configuration for gpio_name. Not all adapters support this generic GPIO mapping, +some require their own commands to define the GPIOs used. Adapters that support +the generic mapping may not support all of the listed options. +@end deffn @deffn {Command} {adapter name} Returns the name of the debug adapter driver being used. @end deffn -@anchor{adapter_usb_location} @deffn {Config Command} {adapter usb location} [<bus>-<port>[.<port>]...] Displays or specifies the physical USB port of the adapter to use. The path roots at @var{bus} and walks down the physical ports, with each @@ -2418,7 +2492,7 @@ This command is only available if your libusb1 is at least version 1.0.16. Specifies the @var{serial_string} of the adapter to use. If this command is not specified, serial strings are not checked. Only the following adapter drivers use the serial string from this command: -aice (aice_usb), arm-jtag-ew, cmsis_dap, ft232r, ftdi, hla (stlink, ti-icdi), jlink, kitprog, opendus, +arm-jtag-ew, cmsis_dap, esp_usb_jtag, ft232r, ftdi, hla (stlink, ti-icdi), jlink, kitprog, opendus, openjtag, osbdm, presto, rlink, st-link, usb_blaster (ublast2), usbprog, vsllink, xds110. @end deffn @@ -2444,6 +2518,10 @@ Optionally sets that option first. @end deffn @end deffn +@deffn {Interface Driver} {angie} +This is the NanoXplore's ANGIE USB-JTAG Adapter. +@end deffn + @deffn {Interface Driver} {arm-jtag-ew} Olimex ARM-JTAG-EW USB adapter This has one driver-specific command: @@ -2465,32 +2543,44 @@ and a specific set of GPIOs is used. ARM CMSIS-DAP compliant based adapter v1 (USB HID based) or v2 (USB bulk). -@deffn {Config Command} {cmsis_dap_vid_pid} [vid pid]+ +@deffn {Config Command} {cmsis-dap vid_pid} [vid pid]+ The vendor ID and product ID of the CMSIS-DAP device. If not specified the driver will attempt to auto detect the CMSIS-DAP device. Currently, up to eight [@var{vid}, @var{pid}] pairs may be given, e.g. @example -cmsis_dap_vid_pid 0xc251 0xf001 0x0d28 0x0204 +cmsis-dap vid_pid 0xc251 0xf001 0x0d28 0x0204 @end example @end deffn -@deffn {Config Command} {cmsis_dap_backend} [@option{auto}|@option{usb_bulk}|@option{hid}] +@deffn {Config Command} {cmsis-dap backend} [@option{auto}|@option{usb_bulk}|@option{hid}] Specifies how to communicate with the adapter: @itemize @minus @item @option{hid} Use HID generic reports - CMSIS-DAP v1 @item @option{usb_bulk} Use USB bulk - CMSIS-DAP v2 @item @option{auto} First try USB bulk CMSIS-DAP v2, if not found try HID CMSIS-DAP v1. -This is the default if @command{cmsis_dap_backend} is not specified. +This is the default if @command{cmsis-dap backend} is not specified. @end itemize @end deffn -@deffn {Config Command} {cmsis_dap_usb interface} [number] +@deffn {Config Command} {cmsis-dap usb interface} [number] Specifies the @var{number} of the USB interface to use in v2 mode (USB bulk). In most cases need not to be specified and interfaces are searched by interface string or for user class interface. @end deffn +@deffn {Command} {cmsis-dap quirk} [@option{enable}|@option{disable}] +Enables or disables the following workarounds of known CMSIS-DAP adapter +quirks: +@itemize @minus +@item disconnect and re-connect before sending a switch sequence +@item packets pipelining is suppressed, only one packet at a time is +submitted to the adapter +@end itemize +The quirk workarounds are disabled by default. +The command without a parameter displays current setting. +@end deffn + @deffn {Command} {cmsis-dap info} Display various device information, like hardware version, firmware version, current bus status. @end deffn @@ -2761,9 +2851,9 @@ If not specified, default 0xFFFF is used. @end deffn @deffn {Interface Driver} {remote_bitbang} -Drive JTAG from a remote process. This sets up a UNIX or TCP socket connection -with a remote process and sends ASCII encoded bitbang requests to that process -instead of directly driving JTAG. +Drive JTAG and SWD from a remote process. This sets up a UNIX or TCP socket +connection with a remote process and sends ASCII encoded bitbang requests to +that process instead of directly driving JTAG and SWD. The remote_bitbang driver is useful for debugging software running on processors which are being simulated. @@ -2778,6 +2868,15 @@ Specifies the hostname of the remote process to connect to using TCP, or the name of the UNIX socket to use if remote_bitbang port is 0. @end deffn +@deffn {Config Command} {remote_bitbang use_remote_sleep} (on|off) +If this option is enabled, delays will not be executed locally but instead +forwarded to the remote host. This is useful if the remote host performs its +own request queuing rather than executing requests immediately. + +This is disabled by default. This option must only be enabled if the given +remote_bitbang host supports receiving the delay information. +@end deffn + For example, to connect remotely via TCP to the host foobar you might have something like: @@ -2787,6 +2886,15 @@ remote_bitbang port 3335 remote_bitbang host foobar @end example +And if you also wished to enable remote sleeping: + +@example +adapter driver remote_bitbang +remote_bitbang port 3335 +remote_bitbang host foobar +remote_bitbang use_remote_sleep on +@end example + To connect to another process running locally via UNIX sockets with socket named mysocket: @@ -2942,7 +3050,7 @@ This driver is for Cypress Semiconductor's KitProg adapters. The KitProg is an SWD-only adapter that is designed to be used with Cypress's PSoC and PRoC device families, but it is possible to use it with some other devices. If you are using this adapter with a PSoC or a PRoC, you may need to add -@command{kitprog_init_acquire_psoc} or @command{kitprog acquire_psoc} to your +@command{kitprog init_acquire_psoc} or @command{kitprog acquire_psoc} to your configuration script. Note that this driver is for the proprietary KitProg protocol, not the CMSIS-DAP @@ -2963,14 +3071,14 @@ versions only implement "SWD line reset". Second, due to a firmware quirk, an SWD sequence must be sent after every target reset in order to re-establish communications with the target. @item Due in part to the limitation above, KitProg devices with firmware below -version 2.14 will need to use @command{kitprog_init_acquire_psoc} in order to +version 2.14 will need to use @command{kitprog init_acquire_psoc} in order to communicate with PSoC 5LP devices. This is because, assuming debug is not disabled on the PSoC, the PSoC 5LP needs its JTAG interface switched to SWD mode before communication can begin, but prior to firmware 2.14, "JTAG to SWD" could only be sent with an acquisition sequence. @end itemize -@deffn {Config Command} {kitprog_init_acquire_psoc} +@deffn {Config Command} {kitprog init_acquire_psoc} Indicate that a PSoC acquisition sequence needs to be run during adapter init. Please be aware that the acquisition sequence hard-resets the target. @end deffn @@ -3151,7 +3259,7 @@ passed as is to the underlying adapter layout handler. @anchor{st_link_dap_interface} @deffn {Interface Driver} {st-link} This is a driver that supports STMicroelectronics adapters ST-LINK/V2 -(from firmware V2J24) and STLINK-V3, thanks to a new API that provides +(from firmware V2J24), STLINK-V3 and STLINK-V3PWR, thanks to a new API that provides directly access the arm ADIv5 DAP. The new API provide access to multiple AP on the same DAP, but the @@ -3256,73 +3364,36 @@ able to coexist nicely with both sysfs bitbanging and various peripherals' kernel drivers. The driver restores the previous configuration on exit. -GPIO numbers >= 32 can't be used for performance reasons. +GPIO numbers >= 32 can't be used for performance reasons. GPIO configuration is +handled by the generic command @ref{adapter gpio, @command{adapter gpio}}. See @file{interface/raspberrypi-native.cfg} for a sample config and -pinout. - -@deffn {Config Command} {bcm2835gpio jtag_nums} @var{tck} @var{tms} @var{tdi} @var{tdo} -Set JTAG transport GPIO numbers for TCK, TMS, TDI, and TDO (in that order). -Must be specified to enable JTAG transport. These pins can also be specified -individually. -@end deffn - -@deffn {Config Command} {bcm2835gpio tck_num} @var{tck} -Set TCK GPIO number. Must be specified to enable JTAG transport. Can also be -specified using the configuration command @command{bcm2835gpio jtag_nums}. -@end deffn - -@deffn {Config Command} {bcm2835gpio tms_num} @var{tms} -Set TMS GPIO number. Must be specified to enable JTAG transport. Can also be -specified using the configuration command @command{bcm2835gpio jtag_nums}. -@end deffn - -@deffn {Config Command} {bcm2835gpio tdo_num} @var{tdo} -Set TDO GPIO number. Must be specified to enable JTAG transport. Can also be -specified using the configuration command @command{bcm2835gpio jtag_nums}. -@end deffn - -@deffn {Config Command} {bcm2835gpio tdi_num} @var{tdi} -Set TDI GPIO number. Must be specified to enable JTAG transport. Can also be -specified using the configuration command @command{bcm2835gpio jtag_nums}. -@end deffn - -@deffn {Config Command} {bcm2835gpio swd_nums} @var{swclk} @var{swdio} -Set SWD transport GPIO numbers for SWCLK and SWDIO (in that order). Must be -specified to enable SWD transport. These pins can also be specified individually. -@end deffn - -@deffn {Config Command} {bcm2835gpio swclk_num} @var{swclk} -Set SWCLK GPIO number. Must be specified to enable SWD transport. Can also be -specified using the configuration command @command{bcm2835gpio swd_nums}. -@end deffn - -@deffn {Config Command} {bcm2835gpio swdio_num} @var{swdio} -Set SWDIO GPIO number. Must be specified to enable SWD transport. Can also be -specified using the configuration command @command{bcm2835gpio swd_nums}. -@end deffn - -@deffn {Config Command} {bcm2835gpio swdio_dir_num} @var{swdio} @var{dir} -Set SWDIO direction control pin GPIO number. If specified, this pin can be used -to control the direction of an external buffer on the SWDIO pin (set=output -mode, clear=input mode). If not specified, this feature is disabled. -@end deffn - -@deffn {Config Command} {bcm2835gpio srst_num} @var{srst} -Set SRST GPIO number. Must be specified to enable SRST. -@end deffn - -@deffn {Config Command} {bcm2835gpio trst_num} @var{trst} -Set TRST GPIO number. Must be specified to enable TRST. -@end deffn +@file{interface/raspberrypi-gpio-connector.cfg} for pinout. @deffn {Config Command} {bcm2835gpio speed_coeffs} @var{speed_coeff} @var{speed_offset} Set SPEED_COEFF and SPEED_OFFSET for delay calculations. If unspecified, speed_coeff defaults to 113714, and speed_offset defaults to 28. @end deffn +@deffn {Config Command} {bcm2835gpio peripheral_mem_dev} @var{device} +Set the device path for access to the memory mapped GPIO control registers. +Uses @file{/dev/gpiomem} by default, this is also the preferred option with +respect to system security. +If overridden to @file{/dev/mem}: +@itemize @minus +@item OpenOCD needs @code{cap_sys_rawio} or run as root to open @file{/dev/mem}. +Please be aware of security issues imposed by running OpenOCD with +elevated user rights and by @file{/dev/mem} itself. +@item correct @command{peripheral_base} must be configured. +@item GPIO 0-27 pads are set to the limited slew rate +and drive strength is reduced to 4 mA (2 mA on RPi 4). +@end itemize + +@end deffn + @deffn {Config Command} {bcm2835gpio peripheral_base} @var{base} -Set the peripheral base register address to access GPIOs. For the RPi1, use +Set the peripheral base register address to access GPIOs. +Ignored if @file{/dev/gpiomem} is used. For the RPi1, use 0x20000000. For RPi2 and RPi3, use 0x3F000000. For RPi4, use 0xFE000000. A full list can be found in the @uref{https://www.raspberrypi.org/documentation/hardware/raspberrypi/peripheral_addresses.md, official guide}. @@ -3342,11 +3413,37 @@ pinout. @end deffn +@deffn {Interface Driver} {am335xgpio} The AM335x SoC is present in BeagleBone +Black and BeagleBone Green single-board computers which expose some of the GPIOs +on the two expansion headers. + +For maximum performance the driver accesses memory-mapped GPIO peripheral +registers directly. The memory mapping requires read and write permission to +kernel memory; if /dev/gpiomem exists it will be used, otherwise /dev/mem will +be used. The driver restores the GPIO state on exit. + +All four GPIO ports are available. GPIO configuration is handled by the generic +command @ref{adapter gpio, @command{adapter gpio}}. + +@deffn {Config Command} {am335xgpio speed_coeffs} @var{speed_coeff} @var{speed_offset} +Set SPEED_COEFF and SPEED_OFFSET for delay calculations. If unspecified +speed_coeff defaults to 600000 and speed_offset defaults to 575. +@end deffn + +See @file{interface/beaglebone-swd-native.cfg} for a sample configuration file. + +@end deffn + + @deffn {Interface Driver} {linuxgpiod} -Linux provides userspace access to GPIO through libgpiod since Linux kernel version v4.6. -The driver emulates either JTAG and SWD transport through bitbanging. +Linux provides userspace access to GPIO through libgpiod since Linux kernel +version v4.6. The driver emulates either JTAG or SWD transport through +bitbanging. There are no driver-specific commands, all GPIO configuration is +handled by the generic command @ref{adapter gpio, @command{adapter gpio}}. This +driver supports the resistor pull options provided by the @command{adapter gpio} +command but the underlying hardware may not be able to support them. -See @file{interface/dln-2-gpiod.cfg} for a sample config. +See @file{interface/dln-2-gpiod.cfg} for a sample configuration file. @end deffn @@ -3377,6 +3474,15 @@ Currently valid @var{variant} values include: The USB device description string of the adapter. This value is only used with the standard variant. @end deffn + +@deffn {Config Command} {openjtag vid_pid} vid pid +The USB vendor ID and product ID of the adapter. If not specified, default +0x0403:0x6001 is used. +This value is only used with the standard variant. +@example +openjtag vid_pid 0x403 0x6014 +@end example +@end deffn @end deffn @@ -3491,6 +3597,117 @@ buspirate led 1 @end deffn +@deffn {Interface Driver} {esp_usb_jtag} +Espressif JTAG driver to communicate with ESP32-C3, ESP32-S3 chips and ESP USB Bridge board using OpenOCD. +These chips have built-in JTAG circuitry and can be debugged without any additional hardware. +Only an USB cable connected to the D+/D- pins is necessary. + +@deffn {Command} {espusbjtag tdo} +Returns the current state of the TDO line +@end deffn + +@deffn {Command} {espusbjtag setio} setio +Manually set the status of the output lines with the order of (tdi tms tck trst srst) +@example +espusbjtag setio 0 1 0 1 0 +@end example +@end deffn + +@deffn {Config Command} {espusbjtag vid_pid} vid_pid +Set vendor ID and product ID for the ESP usb jtag driver +@example +espusbjtag vid_pid 0x303a 0x1001 +@end example +@end deffn + +@deffn {Config Command} {espusbjtag caps_descriptor} caps_descriptor +Set the jtag descriptor to read capabilities of ESP usb jtag driver +@example +espusbjtag caps_descriptor 0x2000 +@end example +@end deffn + +@deffn {Config Command} {espusbjtag chip_id} chip_id +Set chip id to transfer to the ESP USB bridge board +@example +espusbjtag chip_id 1 +@end example +@end deffn + +@end deffn + +@deffn {Interface Driver} {dmem} Direct Memory access debug interface + +The Texas Instruments K3 SoC family provides memory access to DAP +and coresight control registers. This allows control over the +microcontrollers directly from one of the processors on the SOC +itself. + +For maximum performance, the driver accesses the debug registers +directly over the SoC memory map. The memory mapping requires read +and write permission to kernel memory via "/dev/mem" and assumes that +the system firewall configurations permit direct access to the debug +memory space. + +@verbatim ++-----------+ +| OpenOCD | SoC mem map (/dev/mem) +| on +--------------+ +| Cortex-A53| | ++-----------+ | + | ++-----------+ +-----v-----+ +|Cortex-M4F <--------+ | ++-----------+ | | + | DebugSS | ++-----------+ | | +|Cortex-M4F <--------+ | ++-----------+ +-----------+ +@end verbatim + +NOTE: Firewalls are configurable in K3 SoC and depending on various types of +device configuration, this function may be blocked out. Typical behavior +observed in such cases is a firewall exception report on the security +controller and armv8 processor reporting a system error. + +See @file{tcl/interface/ti_k3_am625-swd-native.cfg} for a sample configuration +file. + +@deffn {Command} {dmem info} +Print the DAPBUS dmem configuration. +@end deffn + +@deffn {Config Command} {dmem device} device_path +Set the DAPBUS memory access device (default: /dev/mem). +@end deffn + +@deffn {Config Command} {dmem base_address} base_address +Set the DAPBUS base address which is used to access CoreSight +compliant Access Ports (APs) directly. +@end deffn + +@deffn {Config Command} {dmem ap_address_offset} offset_address +Set the address offset between Access Ports (APs). +@end deffn + +@deffn {Config Command} {dmem max_aps} n +Set the maximum number of valid access ports on the SoC. +@end deffn + +@deffn {Config Command} {dmem emu_ap_list} n +Set the list of Access Ports (APs) that need to be emulated. This +emulation mode supports software translation of an AP request into an +address mapped transaction that does not rely on physical AP hardware. +This maybe needed if the AP is either denied access via memory map or +protected using other SoC mechanisms. +@end deffn + +@deffn {Config Command} {dmem emu_base_address_range} base_address address_window_size +Set the emulated address and address window size. Both of these +parameters must be aligned to page size. +@end deffn + +@end deffn @section Transport Configuration @cindex Transport @@ -4245,6 +4462,10 @@ there seems to be no problems with JTAG scan chain operations. register during initial examination and when checking the sticky error bit. This bit is normally checked after setting the CSYSPWRUPREQ bit, but some devices do not set the ack bit until sometime later. +@item @code{-ir-bypass} @var{NUMBER} +@*Vendor specific bypass instruction, required by some hierarchical JTAG +routers where the normal BYPASS instruction bypasses the whole router and +a vendor specific bypass instruction is required to access child nodes. @end itemize @end deffn @@ -4494,8 +4715,12 @@ There can only be one DAP for each JTAG tap in the system. A DAP may also provide optional @var{configparams}: @itemize @bullet +@item @code{-adiv5} +Specify that it's an ADIv5 DAP. This is the default if not specified. +@item @code{-adiv6} +Specify that it's an ADIv6 DAP. @item @code{-ignore-syspwrupack} -@*Specify this to ignore the CSYSPWRUPACK bit in the ARM DAP DP CTRL/STAT +Specify this to ignore the CSYSPWRUPACK bit in the ARM DAP DP CTRL/STAT register during initial examination and when checking the sticky error bit. This bit is normally checked after setting the CSYSPWRUPREQ bit, but some devices do not set the ack bit until sometime later. @@ -4521,9 +4746,12 @@ This command returns a list of all registered DAP objects. It it useful mainly for TCL scripting. @end deffn -@deffn {Command} {dap info} [num] +@deffn {Command} {dap info} [@var{num}|@option{root}] Displays the ROM table for MEM-AP @var{num}, defaulting to the currently selected AP of the currently selected target. +On ADIv5 DAP @var{num} is the numeric index of the AP. +On ADIv6 DAP @var{num} is the base address of the AP. +With ADIv6 only, @option{root} specifies the root ROM table. @end deffn @deffn {Command} {dap init} @@ -4534,24 +4762,33 @@ initialization, too. The following commands exist as subcommands of DAP instances: -@deffn {Command} {$dap_name info} [num] +@deffn {Command} {$dap_name info} [@var{num}|@option{root}] Displays the ROM table for MEM-AP @var{num}, defaulting to the currently selected AP. +On ADIv5 DAP @var{num} is the numeric index of the AP. +On ADIv6 DAP @var{num} is the base address of the AP. +With ADIv6 only, @option{root} specifies the root ROM table. @end deffn @deffn {Command} {$dap_name apid} [num] Displays ID register from AP @var{num}, defaulting to the currently selected AP. +On ADIv5 DAP @var{num} is the numeric index of the AP. +On ADIv6 DAP @var{num} is the base address of the AP. @end deffn @anchor{DAP subcommand apreg} @deffn {Command} {$dap_name apreg} ap_num reg [value] Displays content of a register @var{reg} from AP @var{ap_num} or set a new value @var{value}. +On ADIv5 DAP @var{ap_num} is the numeric index of the AP. +On ADIv6 DAP @var{ap_num} is the base address of the AP. @var{reg} is byte address of a word register, 0, 4, 8 ... 0xfc. @end deffn @deffn {Command} {$dap_name apsel} [num] Select AP @var{num}, defaulting to 0. +On ADIv5 DAP @var{num} is the numeric index of the AP. +On ADIv6 DAP @var{num} is the base address of the AP. @end deffn @deffn {Command} {$dap_name dpreg} reg [value] @@ -4569,6 +4806,8 @@ background activity by OpenOCD while you are operating at such low-level. @deffn {Command} {$dap_name baseaddr} [num] Displays debug base address from MEM-AP @var{num}, defaulting to the currently selected AP. +On ADIv5 DAP @var{num} is the numeric index of the AP. +On ADIv6 DAP @var{num} is the base address of the AP. @end deffn @deffn {Command} {$dap_name memaccess} [value] @@ -4625,6 +4864,10 @@ Set/get quirks mode for TI TMS450/TMS570 processors Disabled by default @end deffn +@deffn {Config Command} {$dap_name nu_npcx_quirks} [@option{enable}] +Set/get quirks mode for Nuvoton NPCX/NPCD MCU families +Disabled by default +@end deffn @node CPU Configuration @chapter CPU Configuration @@ -4743,8 +4986,9 @@ compact Thumb2 instruction set. Supports also ARMv6-M and ARMv8-M cores @item @code{dsp5680xx} -- implements Freescale's 5680x DSP. @item @code{esirisc} -- this is an EnSilica eSi-RISC core. The current implementation supports eSi-32xx cores. -@item @code{esp32c2} -- this is an Espressif SoC with single RISC-V core. -@item @code{esp32c3} -- this is an Espressif SoC with single RISC-V core. +@item @code{esp32} -- this is an Espressif SoC with dual Xtensa cores. +@item @code{esp32s2} -- this is an Espressif SoC with single Xtensa core. +@item @code{esp32s3} -- this is an Espressif SoC with dual Xtensa cores. @item @code{fa526} -- resembles arm920 (w/o Thumb). @item @code{feroceon} -- resembles arm926. @item @code{hla_target} -- a Cortex-M alternative to work with HL adapters like ST-Link. @@ -4759,9 +5003,6 @@ specified, @xref{gdbportoverride,,option -gdb-port}.), and a fake ARM core will be emulated to comply to GDB remote protocol. @item @code{mips_m4k} -- a MIPS core. @item @code{mips_mips64} -- a MIPS64 core. -@item @code{nds32_v2} -- this is an Andes NDS32 v2 core (deprecated; would be removed in v0.13.0). -@item @code{nds32_v3} -- this is an Andes NDS32 v3 core (deprecated; would be removed in v0.13.0). -@item @code{nds32_v3m} -- this is an Andes NDS32 v3m core (deprecated; would be removed in v0.13.0). @item @code{or1k} -- this is an OpenRISC 1000 core. The current implementation supports three JTAG TAP cores: @itemize @minus @@ -4783,6 +5024,7 @@ And two debug interfaces cores: @item @code{testee} -- a dummy target for cases without a real CPU, e.g. CPLD. @item @code{xscale} -- this is actually an architecture, not a CPU type. It is based on the ARMv5 architecture. +@item @code{xtensa} -- this is a generic Cadence/Tensilica Xtensa core. @end itemize @end deffn @@ -4933,18 +5175,19 @@ The value should normally correspond to a static mapping for the @anchor{rtostype} @item @code{-rtos} @var{rtos_type} -- enable rtos support for target, -@var{rtos_type} can be one of @option{auto}, @option{eCos}, +@var{rtos_type} can be one of @option{auto}, @option{none}, @option{eCos}, @option{ThreadX}, @option{FreeRTOS}, @option{linux}, @option{ChibiOS}, @option{embKernel}, @option{mqx}, @option{uCOS-III}, @option{nuttx}, -@option{RIOT}, @option{Zephyr} +@option{RIOT}, @option{Zephyr}, @option{rtkernel} @xref{gdbrtossupport,,RTOS Support}. @item @code{-defer-examine} -- skip target examination at initial JTAG chain scan and after a reset. A manual call to arp_examine is required to access the target for debugging. -@item @code{-ap-num} @var{ap_number} -- set DAP access port for target, -@var{ap_number} is the numeric index of the DAP AP the target is connected to. +@item @code{-ap-num} @var{ap_number} -- set DAP access port for target. +On ADIv5 DAP @var{ap_number} is the numeric index of the DAP AP the target is connected to. +On ADIv6 DAP @var{ap_number} is the base address of the DAP AP the target is connected to. Use this option with systems where multiple, independent cores are connected to separate access ports of the same DAP. @@ -5125,6 +5368,18 @@ Displays the current target state: (Also, @pxref{eventpolling,,Event Polling}.) @end deffn +@deffn {Command} {$target_name debug_reason} +Displays the current debug reason: +@code{debug-request}, +@code{breakpoint}, +@code{watchpoint}, +@code{watchpoint-and-breakpoint}, +@code{single-step}, +@code{target-not-halted}, +@code{program-exit}, +@code{exception-catch} or @code{undefined}. +@end deffn + @deffn {Command} {$target_name eventlist} Displays a table listing all event handlers currently associated with this target. @@ -5729,24 +5984,42 @@ flash bank $_FLASHNAME cfi 0x00000000 0x02000000 2 4 $_TARGETNAME @c "cfi part_id" disabled @end deffn +@anchor{jtagspi} @deffn {Flash Driver} {jtagspi} @cindex Generic JTAG2SPI driver @cindex SPI @cindex jtagspi @cindex bscan_spi Several FPGAs and CPLDs can retrieve their configuration (bitstream) from a -SPI flash connected to them. To access this flash from the host, the device -is first programmed with a special proxy bitstream that -exposes the SPI flash on the device's JTAG interface. The flash can then be -accessed through JTAG. +SPI flash connected to them. To access this flash from the host, some FPGA +device provides dedicated JTAG instructions, while other FPGA devices should +be programmed with a special proxy bitstream that exposes the SPI flash on +the device's JTAG interface. The flash can then be accessed through JTAG. -Since signaling between JTAG and SPI is compatible, all that is required for +Since signalling between JTAG and SPI is compatible, all that is required for a proxy bitstream is to connect TDI-MOSI, TDO-MISO, TCK-CLK and activate -the flash chip select when the JTAG state machine is in SHIFT-DR. Such -a bitstream for several Xilinx FPGAs can be found in +the flash chip select when the JTAG state machine is in SHIFT-DR. + +Such a bitstream for several Xilinx FPGAs can be found in @file{contrib/loaders/flash/fpga/xilinx_bscan_spi.py}. It requires @uref{https://github.com/m-labs/migen, migen} and a Xilinx toolchain to build. +This mechanism with a proxy bitstream can also be used for FPGAs from Intel and +Efinix. FPGAs from Lattice and Cologne Chip have dedicated JTAG instructions +and procedure to connect the JTAG to the SPI signals and don't need a proxy +bitstream. Support for these devices with dedicated procedure is provided by +the pld drivers. For convenience the PLD drivers will provide the USERx code +for FPGAs with a proxy bitstream. Currently the following PLD drivers are able +to support jtagspi: +@itemize +@item Efinix: proxy-bitstream +@item Gatemate: dedicated procedure +@item Intel/Altera: proxy-bitstream +@item Lattice: dedicated procedure supporting ECP2, ECP3, ECP5, Certus and Certus Pro devices +@item AMD/Xilinx: proxy-bitstream +@end itemize + + This flash bank driver requires a target on a JTAG tap and will access that tap directly. Since no support from the target is needed, the target can be a "testee" dummy. Since the target does not expose the flash memory @@ -5764,14 +6037,25 @@ command, see below. @item @var{ir} ... is loaded into the JTAG IR to map the flash as the JTAG DR. For the bitstreams generated from @file{xilinx_bscan_spi.py} this is the @var{USER1} instruction. -@end itemize +@example +target create $_TARGETNAME testee -chain-position $_CHIPNAME.tap +set _USER1_INSTR_CODE 0x02 +flash bank $_FLASHNAME jtagspi 0x0 0 0 0 \ + $_TARGETNAME $_USER1_INSTR_CODE +@end example + +@item The option @option{-pld} @var{name} is used to have support from the +PLD driver of pld device @var{name}. The name is the name of the pld device +given during creation of the pld device. +Pld device names are shown by the @command{pld devices} command. @example -target create $_TARGETNAME testee -chain-position $_CHIPNAME.fpga -set _XILINX_USER1 0x02 -flash bank $_FLASHNAME spi 0x0 0 0 0 \ - $_TARGETNAME $_XILINX_USER1 +target create $_TARGETNAME testee -chain-position $_CHIPNAME.tap +set _JTAGSPI_CHAIN_ID $_CHIPNAME.pld +flash bank $_FLASHNAME jtagspi 0x0 0 0 0 \ + $_TARGETNAME -pld $_JTAGSPI_CHAIN_ID @end example +@end itemize @deffn Command {jtagspi set} bank_id name total_size page_size read_cmd unused pprg_cmd mass_erase_cmd sector_size sector_erase_cmd Sets flash parameters: @var{name} human readable string, @var{total_size} @@ -6134,7 +6418,6 @@ the flash. @end deffn @end deffn -@anchor{at91samd} @deffn {Flash Driver} {at91samd} @cindex at91samd All members of the ATSAM D2x, D1x, D0x, ATSAMR, ATSAML and ATSAMC microcontroller @@ -6449,7 +6732,7 @@ The AVR 8-bit microcontrollers from Atmel integrate flash memory. @end deffn @deffn {Flash Driver} {bluenrg-x} -STMicroelectronics BlueNRG-1, BlueNRG-2 and BlueNRG-LP Bluetooth low energy wireless system-on-chip. They include ARM Cortex-M0/M0+ core and internal flash memory. +STMicroelectronics BlueNRG-1, BlueNRG-2 and BlueNRG-LP/LPS Bluetooth low energy wireless system-on-chip. They include ARM Cortex-M0/M0+ core and internal flash memory. The driver automatically recognizes these chips using the chip identification registers, and autoconfigures itself. @@ -6579,16 +6862,23 @@ nor is Chip Erase (only Sector Erase is implemented).} @deffn {Flash Driver} {kinetis} @cindex kinetis -Kx, KLx, KVx and KE1x members of the Kinetis microcontroller family -from NXP (former Freescale) include -internal flash and use ARM Cortex-M0+ or M4 cores. The driver automatically +Several microcontrollers from NXP (former Freescale), including +Kx, KLx, KVx and KE1x members of the Kinetis family, +and S32K11x/S32K14x microcontrollers, include +internal flash and use ARM Cortex-M0+ or M4 cores. +Kinetis and S32K1 families use incompatible +identification registers, so the driver assumes Kinetis and requires +a driver option to indicate S32K1 is to be used. +Within the familiy, the driver automatically recognizes flash size and a number of flash banks (1-4) using the chip identification register, and autoconfigures itself. Use kinetis_ke driver for KE0x and KEAx devices. The @var{kinetis} driver defines option: @itemize -@item -sim-base @var{addr} ... base of System Integration Module where chip identification resides. Driver tries two known locations if option is omitted. +@item -s32k select S32K11x/S32K14x microcontroller flash support. + +@item -sim-base @var{addr} ... base of System Integration Module where chip identification resides. Driver tries known locations if option is omitted. @end itemize @example @@ -6637,6 +6927,7 @@ command completes. @deffn {Command} {kinetis nvm_partition} For FlexNVM devices only (KxxDX and KxxFX). +Not supported (yet) on S32K1 devices. Command shows or sets data flash or EEPROM backup size in kilobytes, sets two EEPROM blocks sizes in bytes and enables/disables loading of EEPROM contents to FlexRAM during reset. @@ -7023,10 +7314,16 @@ Show information about flash driver. All versions of the NPCX microcontroller families from Nuvoton include internal flash. The NPCX flash driver supports the NPCX family of devices. The driver automatically recognizes the specific version's flash parameters and -autoconfigures itself. The flash bank starts at address 0x64000000. +autoconfigures itself. The flash bank starts at address 0x64000000. An optional additional +parameter sets the FIU version for the bank, with the default FIU is @var{npcx.fiu}. @example + +flash bank $_FLASHNAME npcx 0x64000000 0 0 0 $_TARGETNAME npcx_v2.fiu + +# FIU defaults to npcx.fiu flash bank $_FLASHNAME npcx 0x64000000 0 0 0 $_TARGETNAME + @end example @end deffn @@ -7260,6 +7557,116 @@ Note: only Main and Work flash regions support Erase operation. @end deffn @end deffn +@deffn {Flash Driver} {qn908x} +The NXP QN908x microcontrollers feature a Cortex-M4F with integrated Bluetooth +LE 5 support and an internal flash of up to 512 KiB. These chips only support +the SWD interface. + +The @var{qn908x} driver uses the internal "Flash Memory Controller" block via +SWD to erase, program and read the internal flash. This driver does not +support the ISP (In-System Programming) mode which is an alternate way to +program the flash via UART, SPI or USB. + +The internal flash is 512 KiB in size in all released chips and it starts at +the address 0x01000000, although it can be mapped to address 0 and it is +aliased to other addresses. This driver only recognizes the bank starting at +address 0x01000000. + +The internal bootloader stored in ROM is in charge of loading and verifying +the image from flash, or enter ISP mode. The programmed image must start at +the beginning of the flash and contain a valid header and a matching CRC32 +checksum. Additionally, the image header contains a "Code Read Protection" +(CRP) word which indicates whether SWD access is enabled, as well as whether +ISP mode is enabled. Therefore, it is possible to program an image that +disables SWD and ISP making it impossible to program another image in the +future through these interfaces, or even debug the current image. While this is +a valid use case for production deployments where the chips are locked down, by +default this driver doesn't allow such images that disable the SWD interface. +To program such images see the @command{qn908x allow_brick} command. + +Apart from the CRP field which is located in the image header, the last page +of the flash memory contains a "Flash lock and protect" descriptor which allows +to individually protect each 2 KiB page, as well as disabling SWD access to the +flash and RAM. If this access is disabled it is not possible to read, erase or +program individual pages from the SWD interface or even access the read-only +"Flash information page" with information about the bootloader version and +flash size. However when this protection is in place, it is still possible to +mass erase the whole chip and then program a new image, for which you can use +the @command{qn908x mass_erase}. + +Example: +@example +flash bank $FLASHNAME qn908x 0x01000000 0 0 0 $TARGETNAME calc_checksum +@end example + +Parameters: +@itemize +@item @option{calc_checksum} optional parameter to compute the required +checksum of the first bytes in the vector table. +@quotation Note +If the checksum in the header of your image is invalid and you don't provide the +@option{calc_checksum} option the boot ROM will not boot your image and it may +render the flash inaccessible. On the other hand, if you use this option to +compute the checksum keep in mind that @command{verify_image} will fail on +those four bytes of the checksum since those bytes in the flash will have the +updated checksum. +@end quotation +@end itemize + +@deffn {Command} {qn908x allow_brick} +Allow the qn908x driver to program images with a "Code Read Protection" byte +that disables the SWD access. Programming such image will cause OpenOCD to +not be able to reach the target over SWD anymore after the new image is +programmed and its configuration takes effect, e.g. after a reboot. After +executing @command{qn908x allow_brick} these images will be allowed to be +programmed when writing to the flash. +@end deffn + +@deffn {Command} {qn908x disable_wdog} +Disable the watchdog timer (WDT) by resetting its CTRL field. The WDT starts +enabled after a @command{reset halt} and it doesn't run while the target is +halted. However, the verification process in this driver uses the generic +Cortex-M verification process which executes a payload in RAM and thus +requires the watchdog to be disabled before running @command{verify_image} +after a reset halt or any other condition where the watchdog is running. +Note that this is not done automatically and you must run this command in +those scenarios. +@end deffn + +@deffn {Command} {qn908x mass_erase} +Erases the complete flash using the mass_erase method. Mass erase is only +allowed if enabled in the Lock Status Register 8 (LOCK_STAT_8) which is read +from the last sector of the flash on boot. However, this mass_erase lock +protection can be bypassed and this command does so automatically. + +In the same LOCK_STAT_8 the flash and RAM access from SWD can be disabled by +setting two bits in this register. After a mass_erase, all the bits of the +flash would be set, making it the default to restrict SWD access to the flash +and RAM regions. This new after erase LOCK_STAT_8 value only takes effect after +being read from flash on the next reboot for example. After a mass_erase the +LOCK_STAT_8 register is changed by the hardware to allow access to flash and +RAM regardless of the value on flash, but only right after a mass_erase and +until the next boot. Therefore it is possible to perform a mass_erase, program +a new image, verify it and then reboot to a valid image that's locked from the +SWD access. + +The @command{qn908x mass_erase} command clears the bits that would be loaded +from the flash into LOCK_STAT_8 after erasing the whole chip to allow SWD +access for debugging or re-flashing an image without a mass_erase by default. +If the image being programmed also programs the last page of the flash with its +own settings, this mass_erase behavior will interfere with that write since a +new erase of at least the last page would need to be performed before writing +to it again. For this reason the optional @option{keep_lock} argument can be +used to leave the flash and RAM lock set. For development environments, the +default behavior is desired. + +The mass erase locking mechanism is independent from the individual page +locking bits, so it is possible that you can't erase a given page that is +locked and you can't unprotect that page because the locking bits are also +locked, but can still mass erase the whole flash. +@end deffn +@end deffn + @deffn {Flash Driver} {rp2040} Supports RP2040 "Raspberry Pi Pico" microcontroller. RP2040 is a dual-core device with two CM0+ cores. Both cores share the same @@ -7271,6 +7678,31 @@ flash bank $_FLASHNAME rp2040_flash $_FLASHBASE $_FLASHSIZE 1 32 $_TARGETNAME @end example @end deffn +@deffn {Flash Driver} {rsl10} +Supports Onsemi RSL10 microcontroller flash memory. Uses functions +stored in ROM to control flash memory interface. + +@example +flash bank $_FLASHNAME rsl10 $_FLASHBASE $_FLASHSIZE 0 0 $_TARGETNAME +@end example + +@deffn {Command} {rsl10 lock} key1 key2 key3 key4 +Writes @var{key1 key2 key3 key4} words to @var{0x81044 0x81048 0x8104c +0x8050}. Locks debug port by writing @var{0x4C6F634B} to @var{0x81040}. + +To unlock use the @command{rsl10 unlock key1 key2 key3 key4} command. +@end deffn + +@deffn {Command} {rsl10 unlock} key1 key2 key3 key4 +Unlocks debug port, by writing @var{key1 key2 key3 key4} words to +registers through DAP, and clears @var{0x81040} address in flash to 0x1. +@end deffn + +@deffn {Command} {rsl10 mass_erase} +Erases all unprotected flash sectors. +@end deffn +@end deffn + @deffn {Flash Driver} {sim3x} All members of the SiM3 microcontroller family from Silicon Laboratories include internal flash and use ARM Cortex-M3 cores. It supports both JTAG @@ -7321,12 +7753,10 @@ applied to all of them. @end deffn @deffn {Flash Driver} {stm32f1x} -All members of the STM32F0, STM32F1 and STM32F3 microcontroller families -from STMicroelectronics and all members of the GD32F1x0, GD32F3x0 and GD32E23x microcontroller -families from GigaDevice include internal flash and use ARM Cortex-M0/M3/M4/M23 cores. -The driver also works with GD32VF103 powered by RISC-V core. -The driver automatically recognizes a number of these chips using -the chip identification register, and autoconfigures itself. +This driver supports the STM32F0, STM32F1 and STM32F3 microcontroller series from STMicroelectronics. +The driver is also compatible with the GD32F1, GD32VF103 (RISC-V core), GD32F3 and GD32E23 microcontroller series from GigaDevice. +The driver also supports the APM32F0 and APM32F1 series from Geehy Semiconductor. +The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @example flash bank $_FLASHNAME stm32f1x 0 0 0 0 $_TARGETNAME @@ -7387,6 +7817,7 @@ The @var{num} parameter is a value shown by @command{flash banks}. @deffn {Flash Driver} {stm32f2x} All members of the STM32F2, STM32F4 and STM32F7 microcontroller families from STMicroelectronics include internal flash and use ARM Cortex-M3/M4/M7 cores. +The driver also works for the APM32F4 series from Geehy Semiconductor. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @@ -8357,24 +8788,27 @@ Accordingly, both are called PLDs here. As it does for JTAG TAPs, debug targets, and flash chips (both NOR and NAND), OpenOCD maintains a list of PLDs available for use in various commands. -Also, each such PLD requires a driver. +Also, each such PLD requires a driver. PLD drivers may also be needed to program +SPI flash connected to the FPGA to store the bitstream (@xref{jtagspi} for details). -They are referenced by the number shown by the @command{pld devices} command, -and new PLDs are defined by @command{pld device driver_name}. +They are referenced by the name which was given when the pld was created or +the number shown by the @command{pld devices} command. +New PLDs are defined by @command{pld create pld_name driver_name -chain-position tap_name [driver_options]}. -@deffn {Config Command} {pld device} driver_name tap_name [driver_options] -Defines a new PLD device, supported by driver @var{driver_name}, -using the TAP named @var{tap_name}. -The driver may make use of any @var{driver_options} to configure its -behavior. +@deffn {Config Command} {pld create} pld_name driver_name -chain-position tap_name [driver_options] +Creates a new PLD device, supported by driver @var{driver_name}, +assigning @var{pld_name} for further reference. +@code{-chain-position} @var{tap_name} names the TAP +used to access this target. +The driver may make use of any @var{driver_options} to configure its behavior. @end deffn @deffn {Command} {pld devices} -Lists the PLDs and their numbers. +List the known PLDs with their name. @end deffn -@deffn {Command} {pld load} num filename -Loads the file @file{filename} into the PLD identified by @var{num}. +@deffn {Command} {pld load} pld_name filename +Loads the file @file{filename} into the PLD identified by @var{pld_name}. The file format must be inferred by the driver. @end deffn @@ -8384,20 +8818,146 @@ Drivers may support PLD-specific options to the @command{pld device} definition command, and may also define commands usable only with that particular type of PLD. -@deffn {FPGA Driver} {virtex2} [no_jstart] +@deffn {FPGA Driver} {virtex2} [@option{-no_jstart}] Virtex-II is a family of FPGAs sold by Xilinx. +This driver can also be used to load Series3, Series6, Series7 and Zynq 7000 devices. It supports the IEEE 1532 standard for In-System Configuration (ISC). -If @var{no_jstart} is non-zero, the JSTART instruction is not used after +If @var{-no_jstart} is given, the JSTART instruction is not used after loading the bitstream. While required for Series2, Series3, and Series6, it breaks bitstream loading on Series7. -@deffn {Command} {virtex2 read_stat} num +@example +openocd -f board/digilent_zedboard.cfg -c "init" \ + -c "pld load 0 zedboard_bitstream.bit" +@end example + + +@deffn {Command} {virtex2 read_stat} pld_name Reads and displays the Virtex-II status register (STAT) -for FPGA @var{num}. +for FPGA @var{pld_name}. +@end deffn + +@deffn {Command} {virtex2 set_instr_codes} pld_name cfg_out cfg_in jprogb jstart jshutdown [user1 [user2 [user3 [user4]]]] +Change values for boundary scan instructions. Default are values for Virtex 2, devices Virtex 4/5/6 and +SSI devices are using different values. +@var{pld_name} is the name of the pld device. +@var{cfg_out} is the value used to select CFG_OUT instruction. +@var{cfg_in} is the value used to select CFG_IN instruction. +@var{jprogb} is the value used to select JPROGRAM instruction. +@var{jstart} is the value used to select JSTART instruction. +@var{jshutdown} is the value used to select JSHUTDOWN instruction. +@var{user1} to @var{user4} are the intruction used to select the user registers USER1 to USER4. +@end deffn + +@deffn {Command} {virtex2 set_user_codes} pld_name user1 [user2 [user3 [user4]]] +Change values for boundary scan instructions selecting the registers USER1 to USER4. +Description of the arguments can be found at command @command{virtex2 set_instr_codes}. +@end deffn + +@deffn {Command} {virtex2 refresh} pld_name +Load the bitstream from external memory for FPGA @var{pld_name}. A.k.a. program. +@end deffn +@end deffn + + + +@deffn {FPGA Driver} {lattice} [@option{-family} <name>] +The FGPA families ECP2, ECP3, ECP5, Certus and CertusPro by Lattice are supported. +This driver can be used to load the bitstream into the FPGA or read the status register and read/write the usercode register. + +For the option @option{-family} @var{name} is one of @var{ecp2 ecp3 ecp5 certus}. This is needed when the JTAG ID of the device is not known by openocd (newer NX devices). + +@deffn {Command} {lattice read_status} pld_name +Reads and displays the status register +for FPGA @var{pld_name}. +@end deffn + +@deffn {Command} {lattice read_user} pld_name +Reads and displays the user register +for FPGA @var{pld_name}. +@end deffn + +@deffn {Command} {lattice write_user} pld_name val +Writes the user register. +for FPGA @var{pld_name} with value @var{val}. +@end deffn + +@deffn {Command} {lattice set_preload} pld_name length +Set the length of the register for the preload. This is needed when the JTAG ID of the device is not known by openocd (newer NX devices). +The load command for the FPGA @var{pld_name} will use a length for the preload of @var{length}. +@end deffn + +@deffn {Command} {lattice refresh} pld_name +Load the bitstream from external memory for FPGA @var{pld_name}. A.k.a program. +@end deffn +@end deffn + + +@deffn {FPGA Driver} {efinix} [@option{-family} <name>] +Both families (Trion and Titanium) sold by Efinix are supported as both use the same protocol for In-System Configuration. +This driver can be used to load the bitstream into the FPGA. +For the option @option{-family} @var{name} is one of @var{trion|titanium}. +@end deffn + + +@deffn {FPGA Driver} {intel} [@option{-family} <name>] +This driver can be used to load the bitstream into Intel (former Altera) FPGAs. +The families Cyclone III, Cyclone IV, Cyclone V, Cyclone 10, Arria II are supported. +@c Arria V and Arria 10, MAX II, MAX V, MAX10) + +For the option @option{-family} @var{name} is one of @var{cycloneiii cycloneiv cyclonev cyclone10 arriaii}. +This is needed when the JTAG ID of the device is ambiguous (same ID is used for chips in different families). + +As input file format the driver supports a '.rbf' (raw bitstream file) file. The '.rbf' file can be generated +from a '.sof' file with @verb{|quartus_cpf -c blinker.sof blinker.rbf|} + +Creates a new PLD device, an FPGA of the Cyclone III family, using the TAP named @verb{|cycloneiii.tap|}: +@example +pld create cycloneiii.pld intel -chain-position cycloneiii.tap -family cycloneiii +@end example + +@deffn {Command} {intel set_bscan} pld_name len +Set boundary scan register length of FPGA @var{pld_name} to @var{len}. This is needed because the +length can vary between chips with the same JTAG ID. +@end deffn + +@deffn {Command} {intel set_check_pos} pld_name pos +Selects the position @var{pos} in the boundary-scan register. The bit at this +position is checked after loading the bitstream and must be '1', which is the case when no error occurred. +With a value of -1 for @var{pos} the check will be omitted. @end deffn @end deffn + +@deffn {FPGA Driver} {gowin} +This driver can be used to load the bitstream into FPGAs from Gowin. +It is possible to program the SRAM. Programming the flash is not supported. +The files @verb{|.fs|} and @verb{|.bin|} generated by Gowin FPGA Designer are supported. + +@deffn {Command} {gowin read_status} pld_name +Reads and displays the status register +for FPGA @var{pld_name}. +@end deffn + +@deffn {Command} {gowin read_user} pld_name +Reads and displays the user register +for FPGA @var{pld_name}. +@end deffn + +@deffn {Command} {gowin refresh} pld_name +Load the bitstream from external memory for +FPGA @var{pld_name}. A.k.a. reload. +@end deffn +@end deffn + + +@deffn {FPGA Driver} {gatemate} +This driver can be used to load the bitstream into GateMate FPGAs form CologneChip. +The files @verb{|.bit|} and @verb{|.cfg|} both generated by p_r tool from CologneChip are supported. +@end deffn + + @node General Commands @chapter General Commands @cindex commands @@ -8423,7 +8983,7 @@ command. All output is relayed through the GDB session. @item @b{Machine Interface} The Tcl interface's intent is to be a machine interface. The default Tcl -port is 5555. +port is 6666. @end itemize @@ -8464,18 +9024,19 @@ Close the OpenOCD server, disconnecting all clients (GDB, telnet, other). If option @option{error} is used, OpenOCD will return a non-zero exit code to the parent process. -Like any TCL commands, also @command{shutdown} can be redefined, e.g.: +If user types CTRL-C or kills OpenOCD, the command @command{shutdown} +will be automatically executed to cause OpenOCD to exit. + +It is possible to specify, in the TCL list @var{pre_shutdown_commands} , a +set of commands to be automatically executed before @command{shutdown} , e.g.: @example -# redefine shutdown -rename shutdown original_shutdown -proc shutdown @{@} @{ - puts "This is my implementation of shutdown" - # my own stuff before exit OpenOCD - original_shutdown -@} +lappend pre_shutdown_commands @{echo "Goodbye, my friend ..."@} +lappend pre_shutdown_commands @{echo "see you soon !"@} @end example -If user types CTRL-C or kills OpenOCD, either the command @command{shutdown} -or its replacement will be automatically executed before OpenOCD exits. +The commands in the list will be executed (in the same order they occupy +in the list) before OpenOCD exits. If one of the commands in the list +fails, then the remaining commands are not executed anymore while OpenOCD +will proceed to quit. @end deffn @anchor{debuglevel} @@ -8503,9 +9064,10 @@ echo "Downloading kernel -- please wait" @end example @end deffn -@deffn {Command} {log_output} [filename | "default"] -Redirect logging to @var{filename} or set it back to default output; -the default log output channel is stderr. +@deffn {Command} {log_output} [filename | 'default'] +Redirect logging to @var{filename}. If used without an argument or +@var{filename} is set to 'default' log output channel is set to +stderr. @end deffn @deffn {Command} {add_script_search_dir} [directory] @@ -8682,7 +9244,6 @@ power consumption (because the CPU is needlessly clocked). @deffn {Command} {resume} [address] Resume the target at its current code position, or the optional @var{address} if it is provided. -OpenOCD will wait 5 seconds for the target to resume. @end deffn @deffn {Command} {step} [address] @@ -8814,7 +9375,7 @@ Loads an image stored in memory by @command{fast_load_image} to the current target. Must be preceded by fast_load_image. @end deffn -@deffn {Command} {fast_load_image} filename address [@option{bin}|@option{ihex}|@option{elf}|@option{s19}] +@deffn {Command} {fast_load_image} filename [address [@option{bin}|@option{ihex}|@option{elf}|@option{s19} [@option{min_addr} [@option{max_length}]]]]]] Normally you should be using @command{load_image} or GDB load. However, for testing purposes or when I/O overhead is significant(OpenOCD running on an embedded host), storing the image in memory and uploading the image to the target @@ -8825,8 +9386,10 @@ target programming performance as I/O and target programming can easily be profi separately. @end deffn -@deffn {Command} {load_image} filename address [[@option{bin}|@option{ihex}|@option{elf}|@option{s19}] @option{min_addr} @option{max_length}] -Load image from file @var{filename} to target memory offset by @var{address} from its load address. +@deffn {Command} {load_image} filename [address [@option{bin}|@option{ihex}|@option{elf}|@option{s19} [@option{min_addr} [@option{max_length}]]]] +Load image from file @var{filename} to target memory. +If an @var{address} is specified, it is used as an offset to the file format +defined addressing (e.g. @option{bin} file is loaded at that address). The file format may optionally be specified (@option{bin}, @option{ihex}, @option{elf}, or @option{s19}). In addition the following arguments may be specified: @@ -8850,15 +9413,21 @@ The file format may optionally be specified (@option{bin}, @option{ihex}, or @option{elf}) @end deffn -@deffn {Command} {verify_image} filename address [@option{bin}|@option{ihex}|@option{elf}] -Verify @var{filename} against target memory starting at @var{address}. +@deffn {Command} {verify_image} filename [address [@option{bin}|@option{ihex}|@option{elf}]] +Verify @var{filename} against target memory. +If an @var{address} is specified, it is used as an offset to the file format +defined addressing (e.g. @option{bin} file is compared against memory starting +at that address). The file format may optionally be specified (@option{bin}, @option{ihex}, or @option{elf}) This will first attempt a comparison using a CRC checksum, if this fails it will try a binary compare. @end deffn -@deffn {Command} {verify_image_checksum} filename address [@option{bin}|@option{ihex}|@option{elf}] -Verify @var{filename} against target memory starting at @var{address}. +@deffn {Command} {verify_image_checksum} filename [address [@option{bin}|@option{ihex}|@option{elf}]] +Verify @var{filename} against target memory. +If an @var{address} is specified, it is used as an offset to the file format +defined addressing (e.g. @option{bin} file is compared against memory starting +at that address). The file format may optionally be specified (@option{bin}, @option{ihex}, or @option{elf}) This perform a comparison using a CRC checksum only @@ -8889,11 +9458,11 @@ for similar mechanisms that do not consume hardware breakpoints.) Remove the breakpoint at @var{address} or all breakpoints. @end deffn -@deffn {Command} {rwp} address -Remove data watchpoint on @var{address} +@deffn {Command} {rwp} @option{all} | address +Remove data watchpoint on @var{address} or all watchpoints. @end deffn -@deffn {Command} {wp} [address len [(@option{r}|@option{w}|@option{a}) [value [mask]]]] +@deffn {Command} {wp} [address length [(@option{r}|@option{w}|@option{a}) [value [mask]]]] With no parameters, lists all active watchpoints. Else sets a data watchpoint on data from @var{address} for @var{length} bytes. The watch point is an "access" watchpoint unless @@ -8967,8 +9536,9 @@ Return a list of all channels and their properties as Tcl list. The list can be manipulated easily from within scripts. @end deffn -@deffn {Command} {rtt server start} port channel -Start a TCP server on @var{port} for the channel @var{channel}. +@deffn {Command} {rtt server start} port channel [message] +Start a TCP server on @var{port} for the channel @var{channel}. When +@var{message} is not empty, it will be sent to a client when it connects. @end deffn @deffn {Command} {rtt server stop} port @@ -8998,13 +9568,15 @@ TCP/IP port 9090. @deffn {Command} {profile} seconds filename [start end] Profiling samples the CPU's program counter as quickly as possible, which is useful for non-intrusive stochastic profiling. -Saves up to 10000 samples in @file{filename} using ``gmon.out'' +Saves up to 1000000 samples in @file{filename} using ``gmon.out'' format. Optional @option{start} and @option{end} parameters allow to limit the address range. @end deffn -@deffn {Command} {version} -Displays a string identifying the version of this OpenOCD server. +@deffn {Command} {version} [git] +Returns a string identifying the version of this OpenOCD server. +With option @option{git}, it returns the git version obtained at compile time +through ``git describe''. @end deffn @deffn {Command} {virt2phys} virtual_address @@ -9293,7 +9865,10 @@ the @emph{cti} group of commands. @deffn {Command} {cti create} cti_name @option{-dap} dap_name @option{-ap-num} apn @option{-baseaddr} base_address Creates a CTI instance @var{cti_name} on the DAP instance @var{dap_name} on MEM-AP -@var{apn}. The @var{base_address} must match the base address of the CTI +@var{apn}. +On ADIv5 DAP @var{apn} is the numeric index of the DAP AP the CTI is connected to. +On ADIv6 DAP @var{apn} is the base address of the DAP AP the CTI is connected to. +The @var{base_address} must match the base address of the CTI on the respective MEM-AP. All arguments are mandatory. This creates a new command @command{$cti_name} which is used for various purposes including additional configuration. @@ -9402,14 +9977,14 @@ requests by using a special SVC instruction that is trapped at the Supervisor Call vector by OpenOCD. @end deffn -@deffn {Command} {arm semihosting_redirect} (@option{disable} | @option{tcp} <port> -[@option{debug}|@option{stdio}|@option{all}) +@deffn {Command} {arm semihosting_redirect} (@option{disable} | @option{tcp} <port> [@option{debug}|@option{stdio}|@option{all}]) @cindex ARM semihosting Redirect semihosting messages to a specified TCP port. This command redirects debug (READC, WRITEC and WRITE0) and stdio (READ, WRITE) semihosting operations to the specified TCP port. The command allows to select which type of operations to redirect (debug, stdio, all (default)). + Note: for stdio operations, only I/O from/to ':tt' file descriptors are redirected. @end deffn @@ -9473,6 +10048,12 @@ is valid during the run of the event handlers and is accessible with this command. @end deffn +@deffn {Command} {arm semihosting_basedir} [dir] +@cindex ARM semihosting +Set the base directory for semihosting I/O, either an absolute path or a path relative to OpenOCD working directory. +Use "." for the current directory. +@end deffn + @section ARMv4 and ARMv5 Architecture @cindex ARMv4 @cindex ARMv5 @@ -9952,8 +10533,9 @@ using the @command{$tpiu_name cget} command. @item @code{-dap} @var{dap_name} -- names the DAP used to access this TPIU. @xref{dapdeclaration,,DAP declaration}, on how to create and manage DAP instances. -@item @code{-ap-num} @var{ap_number} -- sets DAP access port for TPIU, -@var{ap_number} is the numeric index of the DAP AP the TPIU is connected to. +@item @code{-ap-num} @var{ap_number} -- sets DAP access port for TPIU. +On ADIv5 DAP @var{ap_number} is the numeric index of the DAP AP the TPIU is connected to. +On ADIv6 DAP @var{ap_number} is the base address of the DAP AP the TPIU is connected to. @item @code{-baseaddr} @var{base_address} -- sets the TPIU @var{base_address} where to access the TPIU in the DAP AP memory space. @@ -10189,6 +10771,16 @@ the target, the exception catch must be disabled again with @command{$target_nam Issuing the command without options prints the current configuration. @end deffn +@deffn {Command} {$target_name pauth} [@option{off}|@option{on}] +Enable or disable pointer authentication features. +When pointer authentication is used on ARM cores, GDB asks GDB servers for an 8-bytes mask to remove signature bits added by pointer authentication. +If this feature is enabled, OpenOCD provides GDB with an 8-bytes mask. +Pointer authentication feature is broken until gdb 12.1, going to be fixed. +Consider using a newer version of gdb if you want to enable pauth feature. +The default configuration is @option{off}. +@end deffn + + @section EnSilica eSi-RISC Architecture eSi-RISC is a highly configurable microprocessor architecture for embedded systems @@ -10444,14 +11036,79 @@ addreg rtest 0x1234 org.gnu.gdb.or1k.group0 system @end deffn +@section MIPS Architecture +@cindex microMIPS +@cindex MIPS32 +@cindex MIPS64 + +@uref{http://mips.com/, MIPS} is a simple, streamlined, highly scalable RISC +architecture. The architecture is evolving over time, from MIPS I~V to +MIPS release 1~6 iterations, the architecture is now able to handle various tasks +with different ASEs, including SIMD(MSA), DSP, VZ, MT and more. +MIPS32 supports 32-bit programs while MIPS64 can support both 32-bit and 64-bit programs. + +@subsection MIPS Terminology + +The term ASE means Application-Specific Extension, ASEs provide features that +improve the efficiency and performance of certain workloads, such as +digital signal processing(DSP), Virtualization(VZ), Multi-Threading(MT), +SIMD(MSA) and more. + +MIPS Cores use Coprocessors(CPx) to configure their behaviour or to let software +know the capabilities of current CPU, the main Coprocessor is CP0, containing 32 +registers with a maximum select number of 7. + +@subsection MIPS FPU & Vector Registers + +MIPS processors does not all comes with FPU co-processor, and when it does, the FPU +appears as Coprocessor 1 whereas the Coprocessor 0 is for the main processor. + +Most of MIPS FPUs are 64 bits, IEEE 754 standard, and they provides both 32-bit +single precision and 64-bit double precision calculations. Fixed point format +calculations are also provided with both 32 and 64-bit modes. + +The MIPS SIMD Architecture(MSA) operates on 32 128-bit wide vector registers. +If both MSA and the scalar floating-point unit (FPU) are present, the 128-bit MSA +vector registers extend and share the 64-bit FPU registers. MSA and FPU can not be +both present, unless the FPU has 64-bit floating-point register. + +@subsection MIPS Configuration Commands + +@deffn {Command} {mips32 cpuinfo} +Displays detailed information about current CPU core. This includes core type, +vendor, instruction set, cache size, and other relevant details. +@end deffn + +@deffn {Config Command} {mips32 scan_delay} [nanoseconds] +Display or set scan delay in nano seconds. A value below 2_000_000 will set the +scan delay into legacy mode. +@end deffn + +@deffn {Config Command} {mips32 cp0} [[reg_name|regnum select] [value]] +Displays or sets coprocessor 0 register by register number and select or their name. +This command shows all available cp0 register if no arguments are provided. + +For common MIPS Coprocessor 0 registers, you can find the definitions of them +on MIPS Privileged Resource Architecture Documents(MIPS Document MD00090). + +For core specific cp0 registers, you can find the definitions of them on Core +Specific Software User's Manual(SUM), for example, MIPS M5150 Software User Manual +(MD00980). +@end deffn + +@deffn {Command} {mips32 ejtag_reg} +Reads EJTAG Registers for inspection. + +EJTAG Register Specification could be found in MIPS Document MD00047F, for +core specific EJTAG Register definition, please check Core Specific SUM manual. +@end deffn + @section RISC-V Architecture @uref{http://riscv.org/, RISC-V} is a free and open ISA. OpenOCD supports JTAG -debug of RV32 and RV64 cores in heterogeneous multicore systems of up to 32 -harts. (It's possible to increase this limit to 1024 by changing -RISCV_MAX_HARTS in riscv.h.) OpenOCD primarily supports 0.13 of the RISC-V -Debug Specification, but there is also support for legacy targets that -implement version 0.11. +debug of RV32 and RV64 cores in heterogeneous multicore systems of up to 2^20 +harts. OpenOCD primarily supports 0.13 of the RISC-V Debug Specification, +but there is also support for legacy targets that implement version 0.11. @subsection RISC-V Terminology @@ -10519,13 +11176,13 @@ CSRs. @example # Expose a single RISC-V CSR number 128 under the name "csr128": -$_TARGETNAME expose_csrs 128 +riscv expose_csrs 128 # Expose multiple RISC-V CSRs 128..132 under names "csr128" through "csr132": -$_TARGETNAME expose_csrs 128-132 +riscv expose_csrs 128-132 # Expose a single RISC-V CSR number 1996 under custom name "csr_myregister": -$_TARGETNAME expose_csrs 1996=myregister +riscv expose_csrs 1996=myregister @end example @end deffn @@ -10553,6 +11210,23 @@ $_TARGETNAME expose_custom 32=myregister @end example @end deffn +@deffn {Config Command} {riscv hide_csrs} n[-m] [,n1[-m1]] [...] +The RISC-V Specification defines many CSRs, and we may want to avoid showing +each CSR to the user, as they may not be relevant to the task at hand. For +example, we may choose not to show trigger or PMU registers for simple +debugging scenarios. This command allows to mark individual registers or +register ranges (inclusive) as "hidden". Such hidden registers won't be +displayed in GDB or @code{reg} command output. + +@example + +# Hide range of RISC-V CSRs +# CSR_TSELECT - 1952 and CSR_TDATA1 - 1953 +$_TARGETNAME riscv hide_csrs 1952-1953 + +@end example +@end deffn + @deffn {Command} {riscv memory_sample} bucket address|clear [size=4] Configure OpenOCD to frequently read size bytes at the given addresses. Execute the command with no arguments to see the current configuration. Use @@ -10569,6 +11243,18 @@ to read out a buffer that's memory-mapped to be accessed through a single address, or to sample a changing value in a memory-mapped device. @end deffn +@deffn {Command} {riscv info} +Displays some information OpenOCD detected about the target. Output's format +allows to use it directly with TCL's `array set` function. In case obtaining an +info point failed, the corresponding value is displayed as "unavailable". +@end deffn + +@deffn {Command} {riscv reset_delays} [wait] +OpenOCD learns how many Run-Test/Idle cycles are required between scans to avoid +encountering the target being busy. This command resets those learned values +after `wait` scans. It's only useful for testing OpenOCD itself. +@end deffn + @deffn {Command} {riscv set_command_timeout_sec} [seconds] Set the wall-clock timeout (in seconds) for individual commands. The default should work fine for all but the slowest targets (eg. simulators). @@ -10579,12 +11265,7 @@ Set the maximum time to wait for a hart to come out of reset after reset is deasserted. @end deffn -@deffn {Command} {riscv set_scratch_ram} none|[address] -Set the address of 16 bytes of scratch RAM the debugger can use, or 'none'. -This is used to access 64-bit floating point registers on 32-bit targets. -@end deffn - -@deffn Command {riscv set_mem_access} method1 [method2] [method3] +@deffn {Command} {riscv set_mem_access} method1 [method2] [method3] Specify which RISC-V memory access method(s) shall be used, and in which order of priority. At least one method must be specified. @@ -10636,6 +11317,18 @@ When utilizing version 0.11 of the RISC-V Debug Specification, and DBUS registers, respectively. @end deffn +@deffn {Command} {riscv smp} [on|off] +Display, enable or disable SMP handling mode. This command is needed only if +user wants to temporary @b{disable} SMP handling for an existing SMP group +(see @code{aarch64 smp} for additional information). To define an SMP +group the command @code{target smp} should be used. +@end deffn + +@deffn {Command} {riscv smp_gdb} [core_id] +Display/set the current core displayed in GDB. This is needed only if +@code{riscv smp} was used. +@end deffn + @deffn {Command} {riscv use_bscan_tunnel} value Enable or disable use of a BSCAN tunnel to reach the Debug Module. Supply the width of the DM transport TAP's instruction register to enable. Supply a @@ -10668,21 +11361,48 @@ Keep in mind, disabling the option does not guarantee that single stepping will To make that happen, dcsr.stepie would have to be written to 1 as well. @end deffn -@deffn {Command} {riscv set_ebreakm} on|off +@deffn {Command} {riscv set_ebreakm} [on|off] Control dcsr.ebreakm. When on (default), M-mode ebreak instructions trap to OpenOCD. When off, they generate a breakpoint exception handled internally. @end deffn -@deffn {Command} {riscv set_ebreaks} on|off +@deffn {Command} {riscv set_ebreaks} [on|off] Control dcsr.ebreaks. When on (default), S-mode ebreak instructions trap to OpenOCD. When off, they generate a breakpoint exception handled internally. @end deffn -@deffn {Command} {riscv set_ebreaku} on|off +@deffn {Command} {riscv set_ebreaku} [on|off] Control dcsr.ebreaku. When on (default), U-mode ebreak instructions trap to OpenOCD. When off, they generate a breakpoint exception handled internally. @end deffn +The commands below can be used to prevent OpenOCD from using certain RISC-V trigger features. +For example in cases when there are known issues in the target hardware. + +@deffn {Command} {riscv set_enable_trigger_feature} [(@option{eq}|@option{napot}|@option{ge_lt}|@option{all}) (@option{wp}|@option{none})] +Control which RISC-V trigger features can be used by OpenOCD placing watchpoints. +All trigger features are allowed by default. Only new watchpoints, inserted after this command, +are affected (watchpoints that were already placed before are not changed). + +The first argument selects one of the configurable RISC-V trigger features: + +@itemize @minus +@item @option{eq}: Equality match trigger +@item @option{napot}: NAPOT trigger +@item @option{ge_lt}: Chained pair of `greater-equal` and `less-than` triggers +@item @option{all}: All trigger features which were described above +@end itemize + +The second argument configures how OpenOCD should use the selected trigger feature: + +@itemize @minus +@item @option{wp}: Enable this trigger feature for watchpoints - allow OpenOCD to use it. (Default.) +@item @option{none}: Disable the use of this trigger feature. OpenOCD will not attempt to use it. +@end itemize + +With no parameters, prints current trigger features configuration. +@end deffn + @subsection RISC-V Authentication Commands The following commands can be used to authenticate to a RISC-V system. Eg. a @@ -10705,17 +11425,118 @@ Write the 32-bit value to authdata or authdata0 (index=0), or authdata1 @subsection RISC-V DMI Commands -The following commands allow direct access to the Debug Module Interface, which -can be used to interact with custom debug features. +The following commands allow for direct low-level access to the registers +of the Debug Module (DM). They can be useful to access custom features in the DM. + +@deffn {Command} {riscv dm_read} reg_address +Perform a 32-bit read from the register indicated by reg_address from the DM of the +current target. +@end deffn + +@deffn {Command} {riscv dm_write} reg_address value +Write the 32-bit value to the register indicated by reg_address from the DM of the +current target. +@end deffn + +The following commands allow for direct low-level access to the Debug Module +Interface (DMI). They can be useful to access any device that resides on the DMI. @deffn {Command} {riscv dmi_read} address -Perform a 32-bit DMI read at address, returning the value. +Perform a 32-bit read from the given DMI address, returning the value. @end deffn @deffn {Command} {riscv dmi_write} address value -Perform a 32-bit DMI write of value at address. +Perform a 32-bit write to the given DMI address. +@end deffn + +@subsection RISC-V Trigger Commands + +The RISC-V Debug Specification defines several optional trigger types that don't +map cleanly onto OpenOCD's notion of hardware breakpoints. For the types that +the target supports, these commands let you +set those triggers directly. (It's also possible to do so by writing the +appropriate CSRs.) + +@deffn {Command} {riscv etrigger set} [@option{m}] [@option{s}] [@option{u}] [@option{vs}] [@option{vu}] exception_codes +Set an exception trigger (type 5) on the current target, which halts the target when it +fires. @option{m}, @option{s}, @option{u}, @option{vs}, and @option{vu} control +which execution modes the trigger fires in. @var{exception_codes} is a bit +field, where each bit corresponds to an exception code in mcause (defined in the +RISC-V Privileged Spec). The etrigger will fire on the exceptions whose bits are +set in @var{exception_codes}. + +For details on this trigger type, see the RISC-V Debug Specification. +@end deffn + +@deffn {Command} {riscv etrigger clear} +Clear the type 5 trigger that was set using @command{riscv etrigger set}. +@end deffn + +@deffn {Command} {riscv icount set} [@option{m}] [@option{s}] [@option{u}] [@option{vs}] [@option{vu}] [@option{pending}] count +Set an instruction count +trigger (type 3) on the current target, which halts the target when it fires. +@option{m}, @option{s}, @option{u}, @option{vs}, and @option{vu} control which +execution modes the trigger fires in. If [@option{pending}] is passed then the +pending bit is set, which is unlikely to be useful unless you're debugging the +hardware implementation of this trigger. +@var{count} sets the number of instructions to execute before the trigger is +taken. + +For details on this trigger type, see the RISC-V Debug Specification. +@end deffn + +@deffn {Command} {riscv icount clear} +Clear the type 3 trigger that was set using @command{riscv icount set}. +@end deffn + +@deffn {Command} {riscv itrigger set} [@option{m}] [@option{s}] [@option{u}] [@option{vs}] [@option{vu}] [@option{nmi}] mie_bits +Set an interrupt trigger (type 4) on the current target, which halts the target when it +fires. @option{m}, @option{s}, @option{u}, @option{vs}, and @option{vu} control +which execution modes the trigger fires in. If [@option{nmi}] is passed then +the trigger will fire on non-maskable interrupts in those modes. @var{mie_bits} +controls which interrupts the trigger fires on, using the same bit assignments +as in the mie CSR (defined in the RISC-V Privileged Spec). + +For details on this trigger type, see the RISC-V Debug Specification. +@end deffn + +@deffn {Command} {riscv itrigger clear} +Clear the type 4 trigger that was set using @command{riscv itrigger set}. +@end deffn + +@subsection RISC-V Program Buffer Commands + +Program Buffer is an optional feature of RISC-V targets - it is a mechanism that debuggers +can use to execute sequences of arbitrary instructions (small programs) on the target. +For details on the Program Buffer, please refer to the RISC-V Debug Specification. + +@deffn {Command} {riscv exec_progbuf} inst1 [inst2 [... inst16]] +Execute the given sequence of instructions on the target using the Program Buffer. +The command can only be used on halted targets. + +The instructions @var{inst1} .. @var{inst16} shall be specified in their binary form +(as 32-bit integers). In case a pair of compressed (16-bit) instructions is used, +the first instruction should be placed to the lower 16-bits of the 32-bit value. +The terminating @var{ebreak} instruction needs not be specified - it is added +automatically if needed. @end deffn +Examples: + +@example +# Execute 32-bit instructions "fence rw,rw" (0x0330000f) +# and "fence.i" (0x0000100f) using the Program Buffer, +# in this order: + +riscv exec_progbuf 0x0330000f 0x0000100f + +# Execute 16-bit instructions "c.addi s0,s0,1" (0x0405) +# and "c.add s1,s1,s0" (0x94a2) using the Program Buffer, +# in this order: + +riscv exec_progbuf 0x94a20405 +@end example + @section ARC Architecture @cindex ARC @@ -10851,6 +11672,308 @@ STMicroelectronics, based on a proprietary 8-bit core architecture. OpenOCD supports debugging STM8 through the STMicroelectronics debug protocol SWIM, @pxref{swimtransport,,SWIM}. +@section Xtensa Architecture + +Xtensa is a highly-customizable, user-extensible microprocessor and DSP +architecture for complex embedded systems provided by Cadence Design +Systems, Inc. See the +@uref{https://www.cadence.com/en_US/home/tools/ip/tensilica-ip.html, Tensilica IP} +website for additional information and documentation. + +OpenOCD supports generic Xtensa processor implementations which can be customized by +providing a core-specific configuration file which describes every enabled +Xtensa architecture option, e.g. number of address registers, exceptions, reduced +size instructions support, memory banks configuration etc. OpenOCD also supports SMP +configurations for Xtensa processors with any number of cores and allows configuring +their debug interconnect (termed "break/stall networks"), which control how debug +signals are distributed among cores. Xtensa "break networks" are compatible with +ARM's Cross Trigger Interface (CTI). OpenOCD implements both generic Xtensa targets +as well as several Espressif Xtensa-based chips from the +@uref{https://www.espressif.com/en/products/socs, ESP32 family}. + +OCD sessions for Xtensa processor and DSP targets are accessed via the Xtensa +Debug Module (XDM), which provides external connectivity either through a +traditional JTAG interface or an ARM DAP interface. If used, the DAP interface +can control Xtensa targets through JTAG or SWD probes. + +@subsection Xtensa Core Configuration + +Due to the high level of configurability in Xtensa cores, the Xtensa target +configuration comprises two categories: + +@enumerate +@item Base Xtensa support common to all core configurations, and +@item Core-specific support as configured for individual cores. +@end enumerate + +All common Xtensa support is built into the OpenOCD Xtensa target layer and +is enabled through a combination of TCL scripts: the target-specific +@file{target/xtensa.cfg} and a board-specific @file{board/xtensa-*.cfg}, +similar to other target architectures. + +Importantly, core-specific configuration information must be provided by +the user, and takes the form of an @file{xtensa-core-XXX.cfg} TCL script that +defines the core's configurable features through a series of Xtensa +configuration commands (detailed below). + +This core-specific @file{xtensa-core-XXX.cfg} file is typically either: + +@itemize @bullet +@item Located within the Xtensa core configuration build as +@file{src/config/xtensa-core-openocd.cfg}, or +@item Generated by running the command @code{xt-gdb --dump-oocd-config} +from the Xtensa processor tool-chain's command-line tools. +@end itemize + +NOTE: @file{xtensa-core-XXX.cfg} must match the target Xtensa hardware +connected to OpenOCD. + +Some example Xtensa configurations are bundled with OpenOCD for reference: +@enumerate +@item Cadence Palladium VDebug emulation target. The user can combine their +@file{xtensa-core-XXX.cfg} with the provided +@file{board/xtensa-palladium-vdebug.cfg} to debug an emulated Xtensa RTL design. +@item NXP MIMXRT685-EVK evaluation kit. The relevant configuration files are: +@itemize @bullet +@item @file{board/xtensa-rt685-ext.cfg} +@item @file{target/xtensa-core-nxp_rt600.cfg} +@end itemize +Additional information is available by searching for "i.MX RT600 Evaluation Kit" +on @url{https://www.nxp.com}. +@end enumerate + +@subsection Xtensa Configuration Commands + +@deffn {Config Command} {xtensa xtdef} (@option{LX}|@option{NX}) +Configure the Xtensa target architecture. Currently, Xtensa support is limited +to LX6, LX7, and NX cores. +@end deffn + +@deffn {Config Command} {xtensa xtopt} option value +Configure Xtensa target options that are relevant to the debug subsystem. +@var{option} is one of: @option{arnum}, @option{windowed}, +@option{cpenable}, @option{exceptions}, @option{intnum}, @option{hipriints}, +@option{excmlevel}, @option{intlevels}, @option{debuglevel}, +@option{ibreaknum}, or @option{dbreaknum}. @var{value} is an integer with +the exact range determined by each particular option. + +NOTE: Some options are specific to Xtensa LX or Xtensa NX architecture, while +others may be common to both but have different valid ranges. +@end deffn + +@deffn {Config Command} {xtensa xtmem} (@option{iram}|@option{dram}|@option{sram}|@option{irom}|@option{drom}|@option{srom}) baseaddr bytes +Configure Xtensa target memory. Memory type determines access rights, +where RAMs are read/write while ROMs are read-only. @var{baseaddr} and +@var{bytes} are both integers, typically hexadecimal and decimal, respectively. + +NOTE: Some Xtensa memory types, such as system RAM/ROM or MMIO/device regions, +can be added or modified after the Xtensa core has been generated. Additional +@code{xtensa xtmem} definitions should be manually added to xtensa-core-XXX.cfg +to keep OpenOCD's target address map consistent with the Xtensa configuration. +@end deffn + +@deffn {Config Command} {xtensa xtmem} (@option{icache}|@option{dcache}) linebytes cachebytes ways [writeback] +Configure Xtensa processor cache. All parameters are required except for +the optional @option{writeback} parameter; all are integers. +@end deffn + +@deffn {Config Command} {xtensa xtmpu} numfgseg minsegsz lockable execonly +Configure an Xtensa Memory Protection Unit (MPU). MPUs can restrict access +and/or control cacheability of specific address ranges, but are lighter-weight +than a full traditional MMU. All parameters are required; all are integers. +@end deffn + +@deffn {Config Command} {xtensa xtmmu} numirefillentries numdrefillentries +(Xtensa-LX only) Configure an Xtensa Memory Management Unit (MMU). Both +parameters are required; both are integers. +@end deffn + +@deffn {Config Command} {xtensa xtregs} numregs +Configure the total number of registers for the Xtensa core. Configuration +logic expects to subsequently process this number of @code{xtensa xtreg} +definitions. @var{numregs} is an integer. +@end deffn + +@deffn {Config Command} {xtensa xtregfmt} (@option{sparse}|@option{contiguous}) [general] +Configure the type of register map used by GDB to access the Xtensa core. +Generic Xtensa tools (e.g. xt-gdb) require @option{sparse} mapping (default) while +Espressif tools expect @option{contiguous} mapping. Contiguous mapping takes an +additional, optional integer parameter @option{numgregs}, which specifies the number +of general registers used in handling g/G packets. +@end deffn + +@deffn {Config Command} {xtensa xtreg} name offset +Configure an Xtensa core register. All core registers are 32 bits wide, +while TIE and user registers may have variable widths. @var{name} is a +character string identifier while @var{offset} is a hexadecimal integer. +@end deffn + +@subsection Xtensa Operation Commands + +@deffn {Command} {xtensa maskisr} (@option{on}|@option{off}) +(Xtensa-LX only) Mask or unmask Xtensa interrupts during instruction step. +When masked, an interrupt that occurs during a step operation is handled and +its ISR is executed, with the user's debug session returning after potentially +executing many instructions. When unmasked, a triggered interrupt will result +in execution progressing the requested number of instructions into the relevant +vector/ISR code. +@end deffn + +@deffn {Command} {xtensa set_permissive} (0|1) +By default accessing memory beyond defined regions is forbidden. This commnd controls memory access address check. +When set to (1), skips access controls and address range check before read/write memory. +@end deffn + +@deffn {Command} {xtensa smpbreak} [none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut] +Configures debug signals connection ("break network") for currently selected core. +@itemize @bullet +@item @code{none} - Core's "break/stall network" is disconnected. Core is not affected by any debug +signal from other cores. +@item @code{breakinout} - Core's "break network" is fully connected (break inputs and outputs are enabled). +Core will receive debug break signals from other cores and send such signals to them. For example when another core +is stopped due to breakpoint hit this core will be stopped too and vice versa. +@item @code{runstall} - Core's "stall network" is fully connected (stall inputs and outputs are enabled). +This feature is not well implemented and tested yet. +@item @code{BreakIn} - Core's "break-in" signal is enabled. +Core will receive debug break signals from other cores. For example when another core is +stopped due to breakpoint hit this core will be stopped too. +@item @code{BreakOut} - Core's "break-out" signal is enabled. +Core will send debug break signal to other cores. For example when this core is +stopped due to breakpoint hit other cores with enabled break-in signals will be stopped too. +@item @code{RunStallIn} - Core's "runstall-in" signal is enabled. +This feature is not well implemented and tested yet. +@item @code{DebugModeOut} - Core's "debugmode-out" signal is enabled. +This feature is not well implemented and tested yet. +@end itemize +@end deffn + +@deffn {Command} {xtensa exe} <ascii-encoded hexadecimal instruction bytes> +Execute one arbitrary instruction provided as an ascii string. The string represents an integer +number of instruction bytes, thus its length must be even. The instruction can be of any width +that is valid for the Xtensa core configuration. +@end deffn + +@deffn {Command} {xtensa dm} (address) [value] +Read or write Xtensa Debug Module (DM) registers. @var{address} is required for both reads +and writes and is a 4-byte-aligned value typically between 0 and 0x3ffc. @var{value} is specified +only for write accesses. +@end deffn + +@subsection Xtensa Performance Monitor Configuration + +@deffn {Command} {xtensa perfmon_enable} <counter_id> <select> [mask] [kernelcnt] [tracelevel] +Enable and start performance counter. +@itemize @bullet +@item @code{counter_id} - Counter ID (0-1). +@item @code{select} - Selects performance metric to be counted by the counter, +e.g. 0 - CPU cycles, 2 - retired instructions. +@item @code{mask} - Selects input subsets to be counted (counter will +increment only once even if more than one condition corresponding to a mask bit occurs). +@item @code{kernelcnt} - 0 - count events with "CINTLEVEL <= tracelevel", +1 - count events with "CINTLEVEL > tracelevel". +@item @code{tracelevel} - Compares this value to "CINTLEVEL" when deciding +whether to count. +@end itemize +@end deffn + +@deffn {Command} {xtensa perfmon_dump} (counter_id) +Dump performance counter value. If no argument specified, dumps all counters. +@end deffn + +@subsection Xtensa Trace Configuration + +@deffn {Command} {xtensa tracestart} [pc <pcval>/[<maskbitcount>]] [after <n> [ins|words]] +Set up and start a HW trace. Optionally set PC address range to trigger tracing stop when reached during program execution. +This command also allows to specify the amount of data to capture after stop trigger activation. +@itemize @bullet +@item @code{pcval} - PC value which will trigger trace data collection stop. +@item @code{maskbitcount} - PC value mask. +@item @code{n} - Maximum number of instructions/words to capture after trace stop trigger. +@end itemize +@end deffn + +@deffn {Command} {xtensa tracestop} +Stop current trace as started by the tracestart command. +@end deffn + +@deffn {Command} {xtensa tracedump} <outfile> +Dump trace memory to a file. +@end deffn + +@section Espressif Specific Commands + +@deffn {Command} {esp apptrace} (start <destination> [<poll_period> [<trace_size> [<stop_tmo> [<wait4halt> [<skip_size>]]]]]) +Starts +@uref{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#application-level-tracing-library, application level tracing}. +Data will be stored to specified destination. Available destinations are: +@itemize @bullet +@item @code{file://<outfile>} - Save trace logs into file. +@item @code{tcp://<host>:<port>} - Send trace logs to tcp port on specified host. OpenOCD will act as a tcp client. +@item @code{con:} - Print trace logs to the stdout. +@end itemize +Other parameters will be same for each destination. +@itemize @bullet +@item @code{poll_period} - trace data polling period in ms. +@item @code{trace_size} - maximum trace data size. +Tracing will be stopped automatically when that amount is reached. +Use "-1" to disable the limitation. +@item @code{stop_tmo} - Data reception timeout in ms. +Tracing will be stopped automatically when no data is received within that period. +@item @code{wait4halt} - if non-zero then wait for target to be halted before tracing start. +@item @code{skip_size} - amount of tracing data to be skipped before writing it to destination. +@end itemize +@end deffn + +@deffn {Command} {esp apptrace} (stop) +Stops tracing started with above command. +@end deffn + +@deffn {Command} {esp apptrace} (status) +Requests ongoing tracing status. +@end deffn + +@deffn {Command} {esp apptrace} (dump file://<outfile>) +Dumps tracing data from target buffer. It can be useful to dump the latest data +buffered on target for post-mortem analysis. For example when target starts tracing automatically +w/o OpenOCD command and keeps only the latest data window which fit into the buffer. +@uref{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#application-level-tracing-library, application level tracing}. +Data will be stored to specified destination. +@end deffn + +@deffn {Command} {esp sysview} (start file://<outfile1> [file://<outfile2>] [<poll_period> [<trace_size> [<stop_tmo> [<wait4halt> [<skip_size>]]]]]) +Starts @uref{https://www.segger.com/products/development-tools/systemview/, SEGGER SystemView} +compatible tracing. Data will be stored to specified destination. +For dual-core chips traces from every core will be saved to separate files. +Resulting files can be open in "SEGGER SystemView" application. +@url{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#openocd-systemview-tracing-command-options} +The meaning of the arguments is identical to @command{esp apptrace start}. +@end deffn + +@deffn {Command} {esp sysview} (stop) +Stops SystremView compatible tracing started with above command. +@url{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#openocd-systemview-tracing-command-options} +@end deffn + +@deffn {Command} {esp sysview} (status) +Requests ongoing SystremView compatible tracing status. +@url{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#openocd-systemview-tracing-command-options} +@end deffn + +@deffn {Command} {esp sysview_mcore} (start file://<outfile> [<poll_period> [<trace_size> [<stop_tmo> [<wait4halt> [<skip_size>]]]]]) +This command is identical to @command{esp sysview start}, but uses Espressif multi-core extension to +@uref{https://www.segger.com/products/development-tools/systemview/, SEGGER SystemView} data format. +Data will be stored to specified destination. Tracing data from all cores are saved in the same file. +The meaning of the arguments is identical to @command{esp sysview start}. +@end deffn + +@deffn {Command} {esp sysview_mcore} (stop) +Stops Espressif multi-core SystremView tracing started with above command. +@end deffn + +@deffn {Command} {esp sysview_mcore} (status) +Requests ongoing Espressif multi-core SystremView tracing status. +@end deffn + @anchor{softwaredebugmessagesandtracing} @section Software Debug Messages and Tracing @cindex Linux-ARM DCC support @@ -11147,8 +12270,9 @@ way to represent JTAG test patterns in text files. In a debug session using JTAG for its transport protocol, OpenOCD supports running such test files. -@deffn {Command} {svf} @file{filename} [@option{-tap @var{tapname}}] [@option{[-]quiet}] @ - [@option{[-]nil}] [@option{[-]progress}] [@option{[-]ignore_error}] +@deffn {Command} {svf} @file{filename} [@option{-tap @var{tapname}}] [@option{-quiet}] @ + [@option{-nil}] [@option{-progress}] [@option{-ignore_error}] @ + [@option{-noreset}] [@option{-addcycles @var{cyclecount}}] This issues a JTAG reset (Test-Logic-Reset) and then runs the SVF script from @file{filename}. @@ -11161,12 +12285,16 @@ Command options: specified by the SVF file with HIR, TIR, HDR and TDR commands; instead, calculate them automatically according to the current JTAG chain configuration, targeting @var{tapname}; -@item @option{[-]quiet} do not log every command before execution; -@item @option{[-]nil} ``dry run'', i.e., do not perform any operations +@item @option{-quiet} do not log every command before execution; +@item @option{-nil} ``dry run'', i.e., do not perform any operations on the real interface; -@item @option{[-]progress} enable progress indication; -@item @option{[-]ignore_error} continue execution despite TDO check +@item @option{-progress} enable progress indication; +@item @option{-ignore_error} continue execution despite TDO check errors. +@item @option{-noreset} omit JTAG reset (Test-Logic-Reset) before executing +content of the SVF file; +@item @option{-addcycles @var{cyclecount}} inject @var{cyclecount} number of +additional TCLK cycles after each SDR scan instruction; @end itemize @end deffn @@ -11227,7 +12355,7 @@ In a session using JTAG for its transport protocol, OpenOCD supports the functio of a JTAG-Host. The JTAG-Host is needed to connect the circuit over JTAG to the control-software. For more details see @url{http://ipdbg.org}. -@deffn {Command} {ipdbg} [@option{-start|-stop}] @option{-tap @var{tapname}} @option{-hub @var{ir_value} [@var{dr_length}]} [@option{-port @var{number}}] [@option{-tool @var{number}}] [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}] +@deffn {Command} {ipdbg} [@option{-start|-stop}] @option{-tap @var{tapname}} @option{-hub @var{ir_value} [@var{dr_length}]} [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}] [@option{-port @var{number}}] [@option{-tool @var{number}}] Starts or stops a IPDBG JTAG-Host server. Arguments can be specified in any order. Command options: @@ -11236,15 +12364,28 @@ Command options: @item @option{-tap @var{tapname}} targeting the TAP @var{tapname}. @item @option{-hub @var{ir_value}} states that the JTAG hub is reachable with dr-scans while the JTAG instruction register has the value @var{ir_value}. -@item @option{-port @var{number}} tcp port number where the JTAG-Host is listening. -@item @option{-tool @var{number}} number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. -@item @option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]} On some devices, the user data-register is only reachable if there is a +@item @option{-port @var{number}} tcp port number where the JTAG-Host will listen. The default is 4242 which is used when the option is not given. +@item @option{-tool @var{number}} number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. The default is 1 which is used when the option is not given. +@item @option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]} On some devices, the user data-register is reachable if there is a specific value in a second dr. This second dr is called vir (virtual ir). With this parameter given, the IPDBG satisfies this condition prior an access to the IPDBG-Hub. The value shifted into the vir is given by the first parameter @var{vir_value} (default: 0x11). The second parameter @var{length} is the length of the vir data register (default: 5). With the @var{instr_code} (default: 0x00e) parameter the ir value to shift data through vir can be configured. @end itemize @end deffn +or +@deffn {Command} {ipdbg} [@option{-start|-stop}] @option{-pld @var{name} [@var{user}]} [@option{-port @var{number}}] [@option{-tool @var{number}}] +Also starts or stops a IPDBG JTAG-Host server. The pld drivers are able to provide the tap and hub/IR for the IPDBG JTAG-Host server. +With the @option{-pld @var{name} [@var{user}]} the information from the pld-driver is used and the options @option{-tap} and @option{-hub} are not required. +The defined driver for the pld @var{name} gets selected. (The pld devices names can be shown by the command @command{pld devices}). + +The @verb{|USERx|} instructions are vendor specific and don't change between families of the same vendor. +So if there's a pld driver for your vendor it should work with your FPGA even when the driver is not compatible with your device for the remaining features. If your device/vendor is not supported you have to use the previous command. + +With [@var{user}] one can select a different @verb{|USERx|}-Instruction. If the IPDBG JTAG-Hub is used without modification the default value of 1 which selects the first @verb{|USERx|} instruction is adequate. + +The remaining options are described in the previous command. +@end deffn Examples: @example @@ -11259,6 +12400,13 @@ ipdbg -start -tap 10m50.tap -hub 0x00C -vir -port 60000 -tool 1 Starts a server listening on tcp-port 60000 which connects to tool 1 (data_up_1/data_down_1). The connection is through the TAP of a Intel MAX10 virtual jtag component (sld_instance_index is 0; sld_ir_width is smaller than 5). +@example +ipdbg -start -pld xc7.pld -port 5555 -tool 0 +@end example +Starts a server listening on tcp-port 5555 which connects to tool 0 (data_up_0/data_down_0). +The TAP and ir value used to reach the JTAG Hub is given by the pld driver. + + @node Utility Commands @chapter Utility Commands @cindex Utility Commands @@ -11582,8 +12730,14 @@ Currently supported rtos's include: @item @option{RIOT} @item @option{hwthread} (This is not an actual RTOS. @xref{usingopenocdsmpwithgdb,,Using OpenOCD SMP with GDB}.) @item @option{Zephyr} +@item @option{rtkernel} @end itemize +At any time, it's possible to drop the selected RTOS using: +@example +$_TARGETNAME configure -rtos none +@end example + Before an RTOS can be detected, it must export certain symbols; otherwise, it cannot be used by OpenOCD. Below is a list of the required symbols for each supported RTOS. @@ -11596,7 +12750,7 @@ _tx_thread_current_ptr, _tx_thread_created_ptr, _tx_thread_created_count. @raggedright pxCurrentTCB, pxReadyTasksLists, xDelayedTaskList1, xDelayedTaskList2, pxDelayedTaskList, pxOverflowDelayedTaskList, xPendingReadyList, -uxCurrentNumberOfTasks, uxTopUsedPriority. +uxCurrentNumberOfTasks, uxTopUsedPriority, xSchedulerRunning. @end raggedright @item linux symbols init_task. @@ -11618,6 +12772,8 @@ _tcb_name_offset. @end raggedright @item Zephyr symbols _kernel, _kernel_openocd_offsets, _kernel_openocd_size_t_size +@item rtkernel symbols +Multiple struct offsets. @end table For most RTOS supported the above symbols will be exported by default. However for @@ -11636,6 +12792,14 @@ contrib/rtos-helpers/FreeRTOS-openocd.c contrib/rtos-helpers/uCOS-III-openocd.c @end table +@section RTOS Commands +@cindex RTOS Commands + +@deffn {Config Command} {freertos_ticktype_size} (2|4|8) +Pass the size (in bytes) of FreeRTOS TickType_t to OpenOCD. To make sure the +calculation of offsets and sizes is correct. Defaults to 4. +@end deffn + @anchor{usingopenocdsmpwithgdb} @section Using OpenOCD SMP with GDB @cindex SMP @@ -11651,57 +12815,6 @@ The @command{step} and @command{stepi} commands can be used to step a specific c while other cores are free-running or remain halted, depending on the scheduler-locking mode configured in GDB. -@section Legacy SMP core switching support -@quotation Note -This method is deprecated in favor of the @emph{hwthread} pseudo RTOS. -@end quotation - -For SMP support following GDB serial protocol packet have been defined : -@itemize @bullet -@item j - smp status request -@item J - smp set request -@end itemize - -OpenOCD implements : -@itemize @bullet -@item @option{jc} packet for reading core id displayed by -GDB connection. Reply is @option{XXXXXXXX} (8 hex digits giving core id) or - @option{E01} for target not smp. -@item @option{JcXXXXXXXX} (8 hex digits) packet for setting core id displayed at next GDB continue -(core id -1 is reserved for returning to normal resume mode). Reply @option{E01} -for target not smp or @option{OK} on success. -@end itemize - -Handling of this packet within GDB can be done : -@itemize @bullet -@item by the creation of an internal variable (i.e @option{_core}) by mean -of function allocate_computed_value allowing following GDB command. -@example -set $_core 1 -#Jc01 packet is sent -print $_core -#jc packet is sent and result is affected in $ -@end example - -@item by the usage of GDB maintenance command as described in following example (2 cpus in SMP with -core id 0 and 1 @pxref{definecputargetsworkinginsmp,,Define CPU targets working in SMP}). - -@example -# toggle0 : force display of coreid 0 -define toggle0 -maint packet Jc0 -continue -main packet Jc-1 -end -# toggle1 : force display of coreid 1 -define toggle1 -maint packet Jc1 -continue -main packet Jc-1 -end -@end example -@end itemize - @node Tcl Scripting API @chapter Tcl Scripting API @cindex Tcl Scripting API @@ -11761,7 +12874,7 @@ Return information about the flash banks @item @b{capture} <@var{command}> Run <@var{command}> and return full log output that was produced during -its execution. Example: +its execution together with the command output. Example: @example > capture "reset init" @@ -12269,7 +13382,7 @@ It sort of works like this: When the command ``proc'' is parsed (which creates a procedure function) it gets 3 parameters on the command line. @b{1} the name of the proc (function), @b{2} the list of parameters, and @b{3} the body -of the function. Not the choice of words: LIST and BODY. The PROC +of the function. Note the choice of words: LIST and BODY. The PROC command stores these items in a table somewhere so it can be found by ``LookupCommand()'' diff --git a/doc/usb_adapters/angie/584e_414f_angie.txt b/doc/usb_adapters/angie/584e_414f_angie.txt new file mode 100644 index 0000000000..6c25f43b3f --- /dev/null +++ b/doc/usb_adapters/angie/584e_414f_angie.txt @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +Bus 002 Device 105: ID 584e:414f NanoXplore, SAS. ANGIE Adapter +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x584e + idProduct 0x414f + bcdDevice 0.00 + iManufacturer 1 NanoXplore, SAS. + iProduct 2 ANGIE Adapter + iSerial 3 000001 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0047 + bNumInterfaces 2 + bConfigurationValue 1 + iConfiguration 1 NanoXplore, SAS. + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 3 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 4 JTAG Adapter + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x06 EP 6 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x88 EP 8 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 diff --git a/doc/usb_adapters/cmsis_dap/03eb_2111_atmel_edbg.txt b/doc/usb_adapters/cmsis_dap/03eb_2111_atmel_edbg.txt new file mode 100644 index 0000000000..e4dd6cee0d --- /dev/null +++ b/doc/usb_adapters/cmsis_dap/03eb_2111_atmel_edbg.txt @@ -0,0 +1,211 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Optional comment + +Bus 001 Device 006: ID 03eb:2111 Atmel Corp. Xplained Pro board debugger and programmer +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x03eb Atmel Corp. + idProduct 0x2111 Xplained Pro board debugger and programmer + bcdDevice 1.01 + iManufacturer 1 Atmel Corp. + iProduct 2 EDBG CMSIS-DAP + iSerial 3 ATMLxxxxxxxxxxxxxxxx + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0082 + bNumInterfaces 4 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 4 EDBG CMSIS-DAP + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.11 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 35 + Report Descriptor: (length is 35) + Item(Global): Usage Page, data= [ 0x00 0xff ] 65280 + (null) + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Collection, data= [ 0x01 ] 1 + Application + Item(Global): Logical Minimum, data= [ 0x00 ] 0 + Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 + Item(Global): Report Size, data= [ 0x08 ] 8 + Item(Global): Report Count, data= [ 0x00 0x02 ] 512 + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Input, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Global): Report Count, data= [ 0x00 0x02 ] 512 + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Output, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Global): Report Count, data= [ 0x04 ] 4 + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Feature, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Main ): End Collection, data=none + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 1 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 1 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 6 EDBG Virtual COM Port + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 0 + CDC Header: + bcdCDC 1.10 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 1 + bSlaveInterface 2 + CDC Call Management: + bmCapabilities 0x03 + call management + use DataInterface + bDataInterface 2 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 8 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x05 EP 5 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 5 EDBG Data Gateway + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x87 EP 7 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 255 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x06 EP 6 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 255 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/cmsis_dap/03eb_2169_atmel_edbg.txt b/doc/usb_adapters/cmsis_dap/03eb_2169_atmel_edbg.txt new file mode 100644 index 0000000000..1f7f26efd9 --- /dev/null +++ b/doc/usb_adapters/cmsis_dap/03eb_2169_atmel_edbg.txt @@ -0,0 +1,211 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Optional comment + +Bus 001 Device 005: ID 03eb:2169 Atmel Corp. EDBG CMSIS-DAP +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x03eb Atmel Corp. + idProduct 0x2169 + bcdDevice 1.01 + iManufacturer 1 Atmel Corp. + iProduct 2 EDBG CMSIS-DAP + iSerial 3 ATMLxxxxxxxxxxxxxxxx + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0082 + bNumInterfaces 4 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 4 EDBG CMSIS-DAP + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.11 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 35 + Report Descriptor: (length is 35) + Item(Global): Usage Page, data= [ 0x00 0xff ] 65280 + (null) + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Collection, data= [ 0x01 ] 1 + Application + Item(Global): Logical Minimum, data= [ 0x00 ] 0 + Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 + Item(Global): Report Size, data= [ 0x08 ] 8 + Item(Global): Report Count, data= [ 0x00 0x02 ] 512 + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Input, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Global): Report Count, data= [ 0x00 0x02 ] 512 + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Output, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Global): Report Count, data= [ 0x04 ] 4 + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Feature, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Main ): End Collection, data=none + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 1 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 1 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 6 EDBG Virtual COM Port + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 0 + CDC Header: + bcdCDC 1.10 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 1 + bSlaveInterface 2 + CDC Call Management: + bmCapabilities 0x03 + call management + use DataInterface + bDataInterface 2 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 8 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x05 EP 5 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 8 Mass Storage + bInterfaceSubClass 6 SCSI + bInterfaceProtocol 80 Bulk-Only + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x87 EP 7 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x06 EP 6 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/cmsis_dap/04b4_f155_cypress_kitprog3.txt b/doc/usb_adapters/cmsis_dap/04b4_f155_cypress_kitprog3.txt new file mode 100644 index 0000000000..3109c6912a --- /dev/null +++ b/doc/usb_adapters/cmsis_dap/04b4_f155_cypress_kitprog3.txt @@ -0,0 +1,173 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# KitProg3 Firmware 1.01 +# Has inconsistent class code 0 for CMSIS-DAP interface + +Bus 002 Device 017: ID 04b4:f155 Cypress Semiconductor Corp. +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 ? + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 8 + idVendor 0x04b4 Cypress Semiconductor Corp. + idProduct 0xf155 + bcdDevice 1.01 + iManufacturer 1 Cypress Semiconductor + iProduct 6 KitProg3 CMSIS-DAP + iSerial 128 102015B003137400 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 130 + bNumInterfaces 4 + bConfigurationValue 1 + iConfiguration 11 KitProg3 CMSIS-DAP + bmAttributes 0x80 + (Bus Powered) + MaxPower 400mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 0 (Defined at Interface level) + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 6 KitProg3 CMSIS-DAP + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 No Subclass + bInterfaceProtocol 0 None + iInterface 12 KitProg3 bridge + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.11 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 43 + Report Descriptors: + ** UNAVAILABLE ** + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x86 EP 6 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x07 EP 7 OUT + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 2 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 0 None + iFunction 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 15 KitProg3 USBUART + CDC Header: + bcdCDC 1.10 + CDC ACM: + bmCapabilities 0x02 + line coding and serial state + CDC Union: + bMasterInterface 2 + bSlaveInterface 3 + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 3 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0008 1x 8 bytes + bInterval 2 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 Unused + bInterfaceProtocol 0 + iInterface 4 KitProg3 USBUART + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x05 EP 5 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/cmsis_dap/0d28_0204_nxp_daplink.txt b/doc/usb_adapters/cmsis_dap/0d28_0204_nxp_daplink.txt new file mode 100644 index 0000000000..5141a1b6b8 --- /dev/null +++ b/doc/usb_adapters/cmsis_dap/0d28_0204_nxp_daplink.txt @@ -0,0 +1,202 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Board: NXP FRDM-K64F + +Bus 001 Device 006: ID 0d28:0204 NXP ARM mbed +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x0d28 NXP + idProduct 0x0204 ARM mbed + bcdDevice 10.00 + iManufacturer 1 ARM + iProduct 2 DAPLink CMSIS-DAP + iSerial 3 0240000031754e45002f00199485002b6461000097969900 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0082 + bNumInterfaces 4 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 8 Mass Storage + bInterfaceSubClass 6 SCSI + bInterfaceProtocol 80 Bulk-Only + iInterface 7 USB_MSC + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 6 CMSIS-DAP + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.00 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 33 + Report Descriptor: (length is 33) + Item(Global): Usage Page, data= [ 0x00 0xff ] 65280 + (null) + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Collection, data= [ 0x01 ] 1 + Application + Item(Global): Logical Minimum, data= [ 0x00 ] 0 + Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 + Item(Global): Report Size, data= [ 0x08 ] 8 + Item(Global): Report Count, data= [ 0x40 ] 64 + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Input, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Global): Report Count, data= [ 0x40 ] 64 + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Output, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Global): Report Count, data= [ 0x01 ] 1 + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Feature, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Main ): End Collection, data=none + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 1 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 4 mbed Serial Port + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 4 mbed Serial Port + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x03 + call management + use DataInterface + bDataInterface 2 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 1 + bSlaveInterface 2 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 32 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 5 mbed Serial Port + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x04 EP 4 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/cmsis_dap/1a6a_2000_spansion_sk_fm4.txt b/doc/usb_adapters/cmsis_dap/1a6a_2000_spansion_sk_fm4.txt new file mode 100644 index 0000000000..368ec2a2b8 --- /dev/null +++ b/doc/usb_adapters/cmsis_dap/1a6a_2000_spansion_sk_fm4.txt @@ -0,0 +1,143 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Reported in https://en.opensuse.org/User:A_faerber/SK-FM4-176L-S6E2CC + +Bus 002 Device 009: ID 1a6a:2000 Spansion Inc. +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.01 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x1a6a Spansion Inc. + idProduct 0x2000 + bcdDevice 1.60 + iManufacturer 1 Spansion + iProduct 2 Spansion CMSIS-DAP + COM Port + iSerial 0 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 107 + bNumInterfaces 3 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x00 + (Missing must-be-set bit!) + (Bus Powered) + MaxPower 62mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 No Subclass + bInterfaceProtocol 0 None + iInterface 4 Spansion CMSIS-DAP + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.11 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 29 + Report Descriptors: + ** UNAVAILABLE ** + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 1 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 5 Spansion USB Serial Port + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 0 + CDC Header: + bcdCDC 10.01 + CDC ACM: + bmCapabilities 0x00 + CDC Union: + bMasterInterface 1 + bSlaveInterface 2 + CDC Call Management: + bmCapabilities 0x01 + call management + bDataInterface 2 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 255 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 Unused + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x04 EP 4 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/cmsis_dap/2a86_8011_wch_link.txt b/doc/usb_adapters/cmsis_dap/2a86_8011_wch_link.txt new file mode 100644 index 0000000000..f27d9932fa --- /dev/null +++ b/doc/usb_adapters/cmsis_dap/2a86_8011_wch_link.txt @@ -0,0 +1,143 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Reported in https://github.com/pyocd/pyOCD/issues/1395 + +Bus 003 Device 118: ID 2a86:8011 wch.cn WCH-Link +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 8 + idVendor 0x2a86 + idProduct 0x8011 + bcdDevice 1.00 + iManufacturer 1 wch.cn + iProduct 2 WCH-Link + iSerial 3 0001A0000001 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x006b + bNumInterfaces 3 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 0 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 4 QYF CMSIS-DAP + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 0 + iInterface 4 QYF CMSIS-DAP + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x01 + call management + bDataInterface 1 + CDC ACM: + bmCapabilities 0x02 + line coding and serial state + CDC Union: + bMasterInterface 0 + bSlaveInterface 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 2 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 5 (error) + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 6 QYF CMSIS-DAP + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.00 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 33 + Report Descriptors: + ** UNAVAILABLE ** + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/cmsis_dap/c251_2722_keil_ulink2.txt b/doc/usb_adapters/cmsis_dap/c251_2722_keil_ulink2.txt new file mode 100644 index 0000000000..65903b3533 --- /dev/null +++ b/doc/usb_adapters/cmsis_dap/c251_2722_keil_ulink2.txt @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Standalone adapter + +Bus 001 Device 010: ID c251:2722 Keil Software, Inc. Keil ULINK2 CMSIS-DAP +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0xc251 Keil Software, Inc. + idProduct 0x2722 + bcdDevice 1.00 + iManufacturer 1 Keil Software + iProduct 2 Keil ULINK2 CMSIS-DAP + iSerial 3 V0022U9E + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0029 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 4 CMSIS-DAP + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.00 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 33 + Report Descriptor: (length is 33) + Item(Global): Usage Page, data= [ 0x00 0xff ] 65280 + (null) + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Collection, data= [ 0x01 ] 1 + Application + Item(Global): Logical Minimum, data= [ 0x00 ] 0 + Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 + Item(Global): Report Size, data= [ 0x08 ] 8 + Item(Global): Report Count, data= [ 0x40 ] 64 + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Input, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Global): Report Count, data= [ 0x40 ] 64 + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Output, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Global): Report Count, data= [ 0x01 ] 1 + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Feature, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Main ): End Collection, data=none + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/cmsis_dap/c251_2723_keil_ulink_me.txt b/doc/usb_adapters/cmsis_dap/c251_2723_keil_ulink_me.txt new file mode 100644 index 0000000000..df2b9243ef --- /dev/null +++ b/doc/usb_adapters/cmsis_dap/c251_2723_keil_ulink_me.txt @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Reported in https://stackoverflow.com/questions/27087281/jtag-adapter-ulink-me-and-openocd-on-archlinux + +Bus 005 Device 026: ID c251:2723 Keil Software, Inc. +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0xc251 Keil Software, Inc. + idProduct 0x2723 + bcdDevice 1.00 + iManufacturer 1 Keil Software + iProduct 2 Keil ULINK-ME CMSIS-DAP + iSerial 3 M0489MAE + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 41 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 No Subclass + bInterfaceProtocol 0 None + iInterface 4 CMSIS-DAP + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.00 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 33 + Report Descriptors: + ** UNAVAILABLE ** + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/cmsis_dap/c251_2750_keil_ulinkplus.txt b/doc/usb_adapters/cmsis_dap/c251_2750_keil_ulinkplus.txt new file mode 100644 index 0000000000..4504ef0eb5 --- /dev/null +++ b/doc/usb_adapters/cmsis_dap/c251_2750_keil_ulinkplus.txt @@ -0,0 +1,161 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# firmware 2.0.11 + +Bus 001 Device 005: ID c251:2750 Keil Software, Inc. +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0xc251 Keil Software, Inc. + idProduct 0x2750 + bcdDevice 1.00 + iManufacturer 1 KEIL - Tools By ARM + iProduct 2 Keil ULINKplus + iSerial 3 L78440715A + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 101 + bNumInterfaces 4 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 3 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 4 ULINKplus CMSIS-DAP + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 5 ULINKplus Digital I/O + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 6 ULINKplus Analog I/O + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 7 ULINKplus Power Probe + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/cmsis_dap/c251_f001_jixin.pro.txt b/doc/usb_adapters/cmsis_dap/c251_f001_jixin.pro.txt new file mode 100644 index 0000000000..c08f679a6a --- /dev/null +++ b/doc/usb_adapters/cmsis_dap/c251_f001_jixin.pro.txt @@ -0,0 +1,143 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Reported in https://sourceforge.net/p/openocd/tickets/368/ + +Bus 001 Device 008: ID c251:f001 Keil Software, Inc. +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 ? + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0xc251 Keil Software, Inc. + idProduct 0xf001 + bcdDevice 1.00 + iManufacturer 1 jixin.pro + iProduct 2 CMSIS-DAP_LU + iSerial 3 LU_2022_8888 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 107 + bNumInterfaces 3 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 0 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 4 CMSIS-DAP CDC + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 0 None + iInterface 4 CMSIS-DAP CDC + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x01 + call management + bDataInterface 1 + CDC ACM: + bmCapabilities 0x02 + line coding and serial state + CDC Union: + bMasterInterface 0 + bSlaveInterface 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 2 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 Unused + bInterfaceProtocol 0 + iInterface 5 CMSIS-DAP DCI + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 No Subclass + bInterfaceProtocol 0 None + iInterface 6 CMSIS-DAP_LU + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.00 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 33 + Report Descriptors: + ** UNAVAILABLE ** + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/dump.sh b/doc/usb_adapters/dump.sh new file mode 100755 index 0000000000..557ef7f4c9 --- /dev/null +++ b/doc/usb_adapters/dump.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later + +hid_unavailable_report() { + a=$(echo $1 | tr '[:lower:]' '[:upper:]') + b=$(basename $(dirname $(ls -d /sys/bus/usb/drivers/usbhid/*/*:$a.*))) + + echo "" + echo "ATTENTION!" + echo "Unable to read completely the USB descriptors." + echo "Please run the following command(s) and then run this script again" + for i in $b; do + echo " sudo sh -c \"echo -n $i > /sys/bus/usb/drivers/usbhid/unbind\"" + done + echo "" + echo "Please notice that the USB device will not function after the above" + echo "operations; you should unplug and replug it to get it working again." +} + +devs=$(lsusb -d $1:$2 | wc -l) +case "$devs" in + 0 ) + echo "Error: USB device $1:$2 not found" > /dev/stderr + exit 1 + ;; + 1 ) + echo "Dumping $(lsusb -d $1:$2)" > /dev/stderr + ;; + * ) + echo "Error: Multiple matches for 'lsusb -d $1:$2'" > /dev/stderr + exit 1 + ;; +esac + +# break SPDX tag to hide it to checkpatch +echo '# SPDX-''License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later' +echo '' +echo '# Optional comment' + +lsusb -v -d $1:$2 | sed 's/ *$//' + +lsusb -v -d $1:$2 2>&1 | grep -Fq '** UNAVAILABLE **' && (hid_unavailable_report $1:$2 > /dev/stderr) diff --git a/doc/usb_adapters/esp_usb_jtag/303a_1001_esp_usb_jtag.txt b/doc/usb_adapters/esp_usb_jtag/303a_1001_esp_usb_jtag.txt new file mode 100644 index 0000000000..8da58e5812 --- /dev/null +++ b/doc/usb_adapters/esp_usb_jtag/303a_1001_esp_usb_jtag.txt @@ -0,0 +1,134 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Optional comment + +Bus 002 Device 035: ID 303a:1001 +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x303a + idProduct 0x1001 + bcdDevice 1.01 + iManufacturer 1 Espressif + iProduct 2 USB JTAG/serial debug unit + iSerial 3 7C:DF:A1:A2:8F:38 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0062 + bNumInterfaces 3 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0xc0 + Self Powered + MaxPower 500mA + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 0 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 0 + iFunction 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 0 + iInterface 0 + CDC Header: + bcdCDC 1.10 + CDC ACM: + bmCapabilities 0x02 + line coding and serial state + CDC Union: + bMasterInterface 0 + bSlaveInterface 1 + CDC Call Management: + bmCapabilities 0x03 + call management + use DataInterface + bDataInterface 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 2 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 1 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 +Device Status: 0x0001 + Self Powered diff --git a/doc/usb_adapters/ft232r/0403_6001_ft232r.txt b/doc/usb_adapters/ft232r/0403_6001_ft232r.txt new file mode 100644 index 0000000000..8bfb058fde --- /dev/null +++ b/doc/usb_adapters/ft232r/0403_6001_ft232r.txt @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Board: FT232RL +# Chip: FT232RL + +Bus 001 Device 005: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 8 + idVendor 0x0403 Future Technology Devices International, Ltd + idProduct 0x6001 FT232 Serial (UART) IC + bcdDevice 6.00 + iManufacturer 1 FTDI + iProduct 2 FT232R USB UART + iSerial 3 A50285BI + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0020 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0xa0 + (Bus Powered) + Remote Wakeup + MaxPower 90mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 2 FT232R USB UART + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/ftdi/0403_6010_ft2232h.txt b/doc/usb_adapters/ftdi/0403_6010_ft2232h.txt new file mode 100644 index 0000000000..8bb33e6e52 --- /dev/null +++ b/doc/usb_adapters/ftdi/0403_6010_ft2232h.txt @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Board: Steppenprobe +# Link: https://github.com/diegoherranz/steppenprobe +# Chip: FT2232HL + +Bus 001 Device 012: ID 0403:6010 Future Technology Devices International, Ltd FT2232C/D/H Dual UART/FIFO IC +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x0403 Future Technology Devices International, Ltd + idProduct 0x6010 FT2232C/D/H Dual UART/FIFO IC + bcdDevice 7.00 + iManufacturer 1 FTDI + iProduct 2 Dual RS232-HS + iSerial 0 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0037 + bNumInterfaces 2 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 2 Dual RS232-HS + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 2 Dual RS232-HS + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x04 EP 4 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/ftdi/0403_6014_digilent_hs2.txt b/doc/usb_adapters/ftdi/0403_6014_digilent_hs2.txt new file mode 100644 index 0000000000..68fc119e18 --- /dev/null +++ b/doc/usb_adapters/ftdi/0403_6014_digilent_hs2.txt @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Reported in https://sourceforge.net/p/openocd/tickets/357/ + +Bus 001 Device 084: ID 0403:6014 Future Technology Devices International, Ltd FT232H Single HS USB-UART/FIFO IC +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x0403 Future Technology Devices International, Ltd + idProduct 0x6014 FT232H Single HS USB-UART/FIFO IC + bcdDevice 9.00 + iManufacturer 1 Digilent + iProduct 2 Digilent USB Device + iSerial 3 210249AFCD0B + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0020 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 2 Digilent USB Device + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/ftdi/0403_cff8_amontec_jtagkey2.txt b/doc/usb_adapters/ftdi/0403_cff8_amontec_jtagkey2.txt new file mode 100644 index 0000000000..f056502ad5 --- /dev/null +++ b/doc/usb_adapters/ftdi/0403_cff8_amontec_jtagkey2.txt @@ -0,0 +1,104 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Link: http://www.amontec.com +# Casing: Hi-Speed JTAGkey-2 (c) 2009, Amontec +# PCB: Amontec JTAGkey2 v5.3 +# Chip: FT2232HQ + +Bus 001 Device 017: ID 0403:cff8 Future Technology Devices International, Ltd Amontec JTAGkey +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x0403 Future Technology Devices International, Ltd + idProduct 0xcff8 Amontec JTAGkey + bcdDevice 7.00 + iManufacturer 1 Amontec + iProduct 2 Amontec JTAGkey-2 + iSerial 3 53U2ML49 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0037 + bNumInterfaces 2 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 2 Amontec JTAGkey-2 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 2 Amontec JTAGkey-2 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x04 EP 4 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/ftdi/09fb_6001_altera_blaster.txt b/doc/usb_adapters/ftdi/09fb_6001_altera_blaster.txt new file mode 100644 index 0000000000..25f43a416d --- /dev/null +++ b/doc/usb_adapters/ftdi/09fb_6001_altera_blaster.txt @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Clone www.terasic.com "USB Blaster" +# PCB reports: "USB Blaster-B", "FOR ALTERA ONLY" +# Chip: FT245BL + +Bus 001 Device 005: ID 09fb:6001 Altera Blaster +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.10 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 8 + idVendor 0x09fb Altera + idProduct 0x6001 Blaster + bcdDevice 4.00 + iManufacturer 1 Altera + iProduct 2 USB-Blaster + iSerial 3 91f28492 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0020 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 150mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 2 USB-Blaster + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/ftdi/9e88_9e8f_sheevaplug_jtagkey.txt b/doc/usb_adapters/ftdi/9e88_9e8f_sheevaplug_jtagkey.txt new file mode 100644 index 0000000000..c610443356 --- /dev/null +++ b/doc/usb_adapters/ftdi/9e88_9e8f_sheevaplug_jtagkey.txt @@ -0,0 +1,92 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Reported in https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=837989 + +Bus 003 Device 002: ID 9e88:9e8f +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 8 + idVendor 0x9e88 + idProduct 0x9e8f + bcdDevice 5.00 + iManufacturer 1 FTDI + iProduct 2 SheevaPlug JTAGKey FT2232D B + iSerial 3 FTU85Z4Y + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 55 + bNumInterfaces 2 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0xc0 + Self Powered + MaxPower 0mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 2 SheevaPlug JTAGKey FT2232D B + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 2 SheevaPlug JTAGKey FT2232D B + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x04 EP 4 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/icdi/1cbe_00fd_ti_icdi.txt b/doc/usb_adapters/icdi/1cbe_00fd_ti_icdi.txt new file mode 100644 index 0000000000..14fc86fd63 --- /dev/null +++ b/doc/usb_adapters/icdi/1cbe_00fd_ti_icdi.txt @@ -0,0 +1,156 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Board: TI Tiva C Series TM4C1294 Connected LaunchPad +# ICDI firmware update to add OpenOCD support + +Bus 001 Device 016: ID 1cbe:00fd Luminary Micro Inc. In-Circuit Debug Interface +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.10 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x1cbe Luminary Micro Inc. + idProduct 0x00fd In-Circuit Debug Interface + bcdDevice 1.00 + iManufacturer 1 Texas Instruments + iProduct 2 In-Circuit Debug Interface + iSerial 3 0F00CAC2 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0074 + bNumInterfaces 4 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 250mA + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 0 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 0 + CDC Header: + bcdCDC 1.10 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 0 + bSlaveInterface 1 + CDC Call Management: + bmCapabilities 0x01 + call management + bDataInterface 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 1 + iInterface 0 + Device Firmware Upgrade Interface Descriptor: + bLength 9 + bDescriptorType 33 + bmAttributes 15 + Will Detach + Manifestation Tolerant + Upload Supported + Download Supported + wDetachTimeout 65535 milliseconds + wTransferSize 1024 bytes + bcdDFUVersion 1.10 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/jlink/1366_0101_segger_jlink.txt b/doc/usb_adapters/jlink/1366_0101_segger_jlink.txt new file mode 100644 index 0000000000..8fa4e7d29a --- /dev/null +++ b/doc/usb_adapters/jlink/1366_0101_segger_jlink.txt @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Reported in https://forums.gentoo.org/viewtopic-t-781442-start-0.html + +Bus 002 Device 002: ID 1366:0101 +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.10 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 8 + idVendor 0x1366 + idProduct 0x0101 + bcdDevice 0.01 + iManufacturer 1 SEGGER + iProduct 2 J-Link + iSerial 3 123456 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 32 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0xc0 + Self Powered + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 +Device Status: 0x0001 + Self Powered diff --git a/doc/usb_adapters/jlink/1366_0101_segger_jlink_plus_10_1.txt b/doc/usb_adapters/jlink/1366_0101_segger_jlink_plus_10_1.txt new file mode 100644 index 0000000000..fd31e9c789 --- /dev/null +++ b/doc/usb_adapters/jlink/1366_0101_segger_jlink_plus_10_1.txt @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Standalone adapter, original Segger, HW version 10.1 + +Bus 001 Device 005: ID 1366:0101 SEGGER J-Link PLUS +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x1366 SEGGER + idProduct 0x0101 J-Link PLUS + bcdDevice 1.00 + iManufacturer 1 SEGGER + iProduct 2 J-Link + iSerial 3 123456 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0020 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 4 Configuration + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 5 BULK interface + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 1 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/kitprog/04b4_f139_cypress_kitprog.txt b/doc/usb_adapters/kitprog/04b4_f139_cypress_kitprog.txt new file mode 100644 index 0000000000..e3430d87e2 --- /dev/null +++ b/doc/usb_adapters/kitprog/04b4_f139_cypress_kitprog.txt @@ -0,0 +1,172 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Reported in http://false.ekta.is/tag/unboxing/ + +Bus 003 Device 011: ID 04b4:f139 Cypress Semiconductor Corp. +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 ? + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 8 + idVendor 0x04b4 Cypress Semiconductor Corp. + idProduct 0xf139 + bcdDevice 2.0b + iManufacturer 1 Cypress Semiconductor + iProduct 2 Cypress KitProg + iSerial 128 1C210338012E4400 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 130 + bNumInterfaces 4 + bConfigurationValue 1 + iConfiguration 2 Cypress KitProg + bmAttributes 0x80 + (Bus Powered) + MaxPower 400mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 No Subclass + bInterfaceProtocol 0 None + iInterface 3 KitBridge + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.11 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 43 + Report Descriptors: + ** UNAVAILABLE ** + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x04 EP 4 OUT + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 5 KitProg Programmer + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 2 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 0 + bFunctionProtocol 0 + iFunction 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 0 None + iInterface 4 KitProg USBUART + CDC Header: + bcdCDC 1.10 + CDC ACM: + bmCapabilities 0x02 + line coding and serial state + CDC Union: + bMasterInterface 2 + bSlaveInterface 1 + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0008 1x 8 bytes + bInterval 2 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 Unused + bInterfaceProtocol 0 + iInterface 4 KitProg USBUART + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x86 EP 6 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x07 EP 7 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/nulink/0416_511d_nuvoton_nulink.txt b/doc/usb_adapters/nulink/0416_511d_nuvoton_nulink.txt new file mode 100644 index 0000000000..2ac9a44a0d --- /dev/null +++ b/doc/usb_adapters/nulink/0416_511d_nuvoton_nulink.txt @@ -0,0 +1,166 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Board: nuvoTon NuMaker-PFM-M2351 +# Adapter: ICE V3.0 + +Bus 001 Device 013: ID 0416:511d Winbond Electronics Corp. Nuvoton Nu-Link1 ICE/VCOM +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.10 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x0416 Winbond Electronics Corp. + idProduct 0x511d Nuvoton Nu-Link1 ICE/VCOM + bcdDevice 1.00 + iManufacturer 1 Nuvoton + iProduct 2 Nu-Link + iSerial 0 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x006b + bNumInterfaces 3 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.10 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 28 + Report Descriptor: (length is 28) + Item(Global): Usage Page, data= [ 0x01 ] 1 + Generic Desktop Controls + Item(Local ): Usage, data= [ 0x00 ] 0 + Undefined + Item(Main ): Collection, data= [ 0x01 ] 1 + Application + Item(Global): Logical Minimum, data= [ 0x00 ] 0 + Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 + Item(Local ): Usage Minimum, data= [ 0x00 ] 0 + Undefined + Item(Local ): Usage Maximum, data= [ 0x00 ] 0 + Undefined + Item(Global): Report Size, data= [ 0x08 ] 8 + Item(Global): Report Count, data= [ 0x40 ] 64 + Item(Main ): Input, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Local ): Usage Minimum, data= [ 0x00 ] 0 + Undefined + Item(Local ): Usage Maximum, data= [ 0x00 ] 0 + Undefined + Item(Main ): Output, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Main ): End Collection, data=none + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 1 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 2 Nu-Link + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 0 + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 1 + CDC ACM: + bmCapabilities 0x00 + CDC Union: + bMasterInterface 1 + bSlaveInterface 2 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0008 1x 8 bytes + bInterval 255 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x04 EP 4 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/nulink/0416_5200_nuvoton_nulink.txt b/doc/usb_adapters/nulink/0416_5200_nuvoton_nulink.txt new file mode 100644 index 0000000000..5735d3bd2f --- /dev/null +++ b/doc/usb_adapters/nulink/0416_5200_nuvoton_nulink.txt @@ -0,0 +1,238 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Board: nuvoTon NuMaker-M483KG V1.1 +# Adapter: Nu-Link2-Me V1.0 + +Bus 001 Device 014: ID 0416:5200 Winbond Electronics Corp. Nuvoton Nu-Link2-ME ICE/MSC/VCOM +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x0416 Winbond Electronics Corp. + idProduct 0x5200 Nuvoton Nu-Link2-ME ICE/MSC/VCOM + bcdDevice 0.00 + iManufacturer 1 Nuvoton + iProduct 9 Nu-Link2 + iSerial 6 13010000AAAAAAAAAAAAAAAAAAAAAAAA + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0099 + bNumInterfaces 5 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 2 Nu-Link2 Bulk + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 1 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 3 Nu-Link2 VCOM + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 1 + CDC ACM: + bmCapabilities 0x00 + CDC Union: + bMasterInterface 1 + bSlaveInterface 2 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0100 1x 256 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x04 EP 4 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0100 1x 256 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 4 Nu-Link2 HID + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.10 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 35 + Report Descriptor: (length is 35) + Item(Global): Usage Page, data= [ 0x06 0xff ] 65286 + (null) + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Collection, data= [ 0x01 ] 1 + Application + Item(Global): Logical Minimum, data= [ 0x00 ] 0 + Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 + Item(Global): Report Size, data= [ 0x08 ] 8 + Item(Global): Report Count, data= [ 0x00 0x04 ] 1024 + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Input, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Global): Report Count, data= [ 0x00 0x04 ] 1024 + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Output, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Global): Report Count, data= [ 0x08 ] 8 + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Feature, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Main ): End Collection, data=none + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x86 EP 6 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0400 1x 1024 bytes + bInterval 4 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x07 EP 7 OUT + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0400 1x 1024 bytes + bInterval 4 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 4 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 8 Mass Storage + bInterfaceSubClass 6 SCSI + bInterfaceProtocol 80 Bulk-Only + iInterface 5 Nu-Link2 MSC + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x88 EP 8 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x09 EP 9 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/readme.txt b/doc/usb_adapters/readme.txt new file mode 100644 index 0000000000..19df4cf70f --- /dev/null +++ b/doc/usb_adapters/readme.txt @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +This folder contains a collection of dumps of USB descriptors, obtained through +Linux lsusb command, of several USB adapters supported by OpenOCD. +This collection should help maintaining adapter drivers even if the developer +doesn't have access to all the devices supported by the driver. + +To add a new file, run: + + ./doc/usb_adapters/dump.sh ${vid} ${pid} \ + > doc/usb_adapters/${driver}/${vid}_${pid}_${short_description}.txt + +eventually edit the file to add some extra comment, then submit the file to +OpenOCD gerrit, as explained in HACKING. + +The dumps are organized in subfolders corresponding to OpenOCD drivers: +- cmsis_dap; +- esp_usb_jtag; +- ft232r; +- ftdi; +- icdi; +- jlink; +- kitprog; +- nulink; +- stlink; +- xds110. + +The script above assumes the user has granted access permissions to the USB +device file in + /dev/bus/usb/<n>/<m> +This is usually the case when the device is listed in + contrib/60-openocd.rules +and this udev rules file is properly installed in the host machine. +If the user has no proper access permissions, the script has to be run as +root or through 'sudo'. + +Old versions of 'lsusb -v' dump cryptic errors like: + can't get device qualifier: Resource temporarily unavailable + can't get debug descriptor: Resource temporarily unavailable +when some optional descriptor is not present. +This is fixed in usbutils v014. +If you get such messages simply ignore them. They are printed on stderr, so +will not be included in the generated file as the redirection '>' does only +redirects stdout. diff --git a/doc/usb_adapters/stlink/0483_3744_stlinkv1.txt b/doc/usb_adapters/stlink/0483_3744_stlinkv1.txt new file mode 100644 index 0000000000..b887f7971c --- /dev/null +++ b/doc/usb_adapters/stlink/0483_3744_stlinkv1.txt @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Standalone adapter + +Bus 001 Device 009: ID 0483:3744 STMicroelectronics ST-LINK/V1 +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x0483 STMicroelectronics + idProduct 0x3744 ST-LINK/V1 + bcdDevice 1.00 + iManufacturer 1 STMicroelectronics + iProduct 2 STM32 STLink + iSerial 3 0000001 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0020 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 8 Mass Storage + bInterfaceSubClass 6 SCSI + bInterfaceProtocol 80 Bulk-Only + iInterface 4 ST Link + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/stlink/0483_3748_stlinkv2.txt b/doc/usb_adapters/stlink/0483_3748_stlinkv2.txt new file mode 100644 index 0000000000..ac6dfc7f63 --- /dev/null +++ b/doc/usb_adapters/stlink/0483_3748_stlinkv2.txt @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# ST-Link/V2 standalone or ST-Link/V2 in firmware update mode + +Bus 001 Device 006: ID 0483:3748 STMicroelectronics ST-LINK/V2 +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x0483 STMicroelectronics + idProduct 0x3748 ST-LINK/V2 + bcdDevice 1.00 + iManufacturer 1 STMicroelectronics + iProduct 2 STM32 STLink + iSerial 3 0668FF323637414257071827 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0027 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 3 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 4 ST Link + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/stlink/0483_374b_stlinkv2.txt b/doc/usb_adapters/stlink/0483_374b_stlinkv2.txt new file mode 100644 index 0000000000..cc0156d74d --- /dev/null +++ b/doc/usb_adapters/stlink/0483_374b_stlinkv2.txt @@ -0,0 +1,173 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Board: ST Nucleo F411 + +Bus 001 Device 007: ID 0483:374b STMicroelectronics ST-LINK/V2.1 +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x0483 STMicroelectronics + idProduct 0x374b ST-LINK/V2.1 + bcdDevice 1.00 + iManufacturer 1 STMicroelectronics + iProduct 2 STM32 STLink + iSerial 3 066EFF373535503457062922 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0080 + bNumInterfaces 4 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 3 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 4 ST-Link Debug + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0020 1x 32 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 8 Mass Storage + bInterfaceSubClass 6 SCSI + bInterfaceProtocol 80 Bulk-Only + iInterface 5 ST-Link mass storage + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 2 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 6 ST-Link VCP Ctrl + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 6 ST-Link VCP Ctrl + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 3 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 2 + bSlaveInterface 3 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0002 1x 2 bytes + bInterval 255 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 7 ST-Link VCP Data + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x05 EP 5 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0008 1x 8 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/stlink/0483_374d_stlinkv3.txt b/doc/usb_adapters/stlink/0483_374d_stlinkv3.txt new file mode 100644 index 0000000000..e964872c34 --- /dev/null +++ b/doc/usb_adapters/stlink/0483_374d_stlinkv3.txt @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# ST-Link/V3 in firmware update mode + +Bus 001 Device 009: ID 0483:374d STMicroelectronics STLINK-V3 Loader +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x0483 STMicroelectronics + idProduct 0x374d STLINK-V3 Loader + bcdDevice 2.00 + iManufacturer 1 STMicroelectronics + iProduct 2 STM32 ST-LINK/V3 + iSerial 3 003500463137510239383538 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0020 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 4 DFU Config + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 5 ST-LINK/V3 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0001 + Self Powered diff --git a/doc/usb_adapters/stlink/0483_374e_stlinkv3.txt b/doc/usb_adapters/stlink/0483_374e_stlinkv3.txt new file mode 100644 index 0000000000..55c968ccee --- /dev/null +++ b/doc/usb_adapters/stlink/0483_374e_stlinkv3.txt @@ -0,0 +1,182 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Board: ST Nucleo-H745AI-Q + +Bus 001 Device 008: ID 0483:374e STMicroelectronics STLINK-V3 +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x0483 STMicroelectronics + idProduct 0x374e STLINK-V3 + bcdDevice 1.00 + iManufacturer 1 STMicroelectronics + iProduct 2 STLINK-V3 + iSerial 3 005100313137511039383538 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0080 + bNumInterfaces 4 + bConfigurationValue 1 + iConfiguration 4 Default Config + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 3 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 5 ST-Link Debug + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 8 Mass Storage + bInterfaceSubClass 6 SCSI + bInterfaceProtocol 80 Bulk-Only + iInterface 6 ST-Link mass storage + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 2 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 7 ST-Link VCP Ctrl + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 7 ST-Link VCP Ctrl + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 3 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 2 + bSlaveInterface 3 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x000a 1x 10 bytes + bInterval 16 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 8 ST-Link VCP Data + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x05 EP 5 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/stlink/0483_374f_stlinkv3.txt b/doc/usb_adapters/stlink/0483_374f_stlinkv3.txt new file mode 100644 index 0000000000..1974001c7c --- /dev/null +++ b/doc/usb_adapters/stlink/0483_374f_stlinkv3.txt @@ -0,0 +1,212 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Standalone adapter + +Bus 001 Device 008: ID 0483:374f STMicroelectronics STLINK-V3 +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x0483 STMicroelectronics + idProduct 0x374f STLINK-V3 + bcdDevice 1.00 + iManufacturer 1 STMicroelectronics + iProduct 2 STLINK-V3 + iSerial 3 003500463137510239383538 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0097 + bNumInterfaces 5 + bConfigurationValue 1 + iConfiguration 4 Default Config + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 3 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 5 ST-Link Debug + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 8 Mass Storage + bInterfaceSubClass 6 SCSI + bInterfaceProtocol 80 Bulk-Only + iInterface 6 ST-Link mass storage + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 2 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 7 ST-Link VCP Ctrl + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 7 ST-Link VCP Ctrl + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 3 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 2 + bSlaveInterface 3 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x000a 1x 10 bytes + bInterval 16 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 8 ST-Link VCP Data + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x05 EP 5 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 4 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 9 ST-Link Bridge + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x86 EP 6 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x06 EP 6 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/stlink/0483_3752_stlinkv2.txt b/doc/usb_adapters/stlink/0483_3752_stlinkv2.txt new file mode 100644 index 0000000000..798b5276e8 --- /dev/null +++ b/doc/usb_adapters/stlink/0483_3752_stlinkv2.txt @@ -0,0 +1,143 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Board: ST STM32MP157f-DK2 + +Bus 001 Device 005: ID 0483:3752 STMicroelectronics ST-LINK/V2.1 +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x0483 STMicroelectronics + idProduct 0x3752 ST-LINK/V2.1 + bcdDevice 1.00 + iManufacturer 1 STMicroelectronics + iProduct 2 STM32 STLink + iSerial 3 0668FF323637414257071827 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0069 + bNumInterfaces 3 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 300mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 3 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 4 ST-Link Debug + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0020 1x 32 bytes + bInterval 0 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 1 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 6 ST-Link VCP Ctrl + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 6 ST-Link VCP Ctrl + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 2 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 1 + bSlaveInterface 2 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0008 1x 8 bytes + bInterval 16 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 7 ST-Link VCP Data + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x05 EP 5 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/stlink/0483_3753_stlinkv3.txt b/doc/usb_adapters/stlink/0483_3753_stlinkv3.txt new file mode 100644 index 0000000000..e3a951f99e --- /dev/null +++ b/doc/usb_adapters/stlink/0483_3753_stlinkv3.txt @@ -0,0 +1,253 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Board STM32MP135F-DK + +Bus 001 Device 011: ID 0483:3753 STMicroelectronics STLINK-V3 +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x0483 STMicroelectronics + idProduct 0x3753 STLINK-V3 + bcdDevice 1.00 + iManufacturer 1 STMicroelectronics + iProduct 2 STLINK-V3 + iSerial 3 001000294741500120383733 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x00c2 + bNumInterfaces 6 + bConfigurationValue 1 + iConfiguration 4 Default Config + bmAttributes 0x80 + (Bus Powered) + MaxPower 300mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 3 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 5 ST-Link Debug + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 1 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 7 ST-Link VCP Ctrl + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 7 ST-Link VCP Ctrl + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 2 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 1 + bSlaveInterface 2 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x000a 1x 10 bytes + bInterval 16 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 8 ST-Link VCP Data + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x05 EP 5 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 9 ST-Link Bridge + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x86 EP 6 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x06 EP 6 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 4 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 10 ST-Link VCP2 Ctrl + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 4 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 10 ST-Link VCP2 Ctrl + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 5 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 4 + bSlaveInterface 5 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x000a 1x 10 bytes + bInterval 16 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 5 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 11 ST-Link VCP2 Data + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x07 EP 7 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x87 EP 7 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/stlink/0483_3755_stlinkv3pwr.txt b/doc/usb_adapters/stlink/0483_3755_stlinkv3pwr.txt new file mode 100644 index 0000000000..6c7cd6fbf3 --- /dev/null +++ b/doc/usb_adapters/stlink/0483_3755_stlinkv3pwr.txt @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# STLINK-V3PWR standalone in firmware update mode + +Bus 003 Device 054: ID 0483:3755 STMicroelectronics USB2.0 Hub +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x0483 STMicroelectronics + idProduct 0x3755 + bcdDevice 1.00 + iManufacturer 1 STMicroelectronics + iProduct 2 STLINK-V3PWR + iSerial 3 123456780000 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0020 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 4 DFU Config + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 5 ST-Link Usbloader + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/stlink/0483_3757_stlinkv3pwr.txt b/doc/usb_adapters/stlink/0483_3757_stlinkv3pwr.txt new file mode 100644 index 0000000000..0cfd6cf588 --- /dev/null +++ b/doc/usb_adapters/stlink/0483_3757_stlinkv3pwr.txt @@ -0,0 +1,253 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# STLINK-V3PWR standalone + +Bus 003 Device 053: ID 0483:3757 STMicroelectronics USB2.0 Hub +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x0483 STMicroelectronics + idProduct 0x3757 + bcdDevice 1.00 + iManufacturer 1 STMicroelectronics + iProduct 2 STLINK-V3PWR + iSerial 3 123456780000 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x00c2 + bNumInterfaces 6 + bConfigurationValue 1 + iConfiguration 4 Default Config + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 3 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 5 ST-Link Debug + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 1 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 6 ST-Link VCP Ctrl + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 6 ST-Link VCP Ctrl + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 2 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 1 + bSlaveInterface 2 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x000a 1x 10 bytes + bInterval 16 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 7 ST-Link VCP Data + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x05 EP 5 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 255 Vendor Specific Subclass + bInterfaceProtocol 255 Vendor Specific Protocol + iInterface 8 ST-Link Bridge + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x86 EP 6 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x06 EP 6 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 4 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 9 ST-Link VCP-PWR Ctrl + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 4 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 9 ST-Link VCP-PWR Ctrl + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 5 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 4 + bSlaveInterface 5 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x87 EP 7 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x000a 1x 10 bytes + bInterval 16 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 5 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 10 ST-Link VCP-PWR Data + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/doc/usb_adapters/xds110/0451_bef3_ti_xds110.txt b/doc/usb_adapters/xds110/0451_bef3_ti_xds110.txt new file mode 100644 index 0000000000..628b529e2a --- /dev/null +++ b/doc/usb_adapters/xds110/0451_bef3_ti_xds110.txt @@ -0,0 +1,296 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Board: TI CC2650 LaunchPad + +Bus 001 Device 005: ID 0451:bef3 Texas Instruments, Inc. CC1352R1 Launchpad +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.10 + bDeviceClass 239 Miscellaneous Device + bDeviceSubClass 2 + bDeviceProtocol 1 Interface Association + bMaxPacketSize0 64 + idVendor 0x0451 Texas Instruments, Inc. + idProduct 0xbef3 CC1352R1 Launchpad + bcdDevice 1.00 + iManufacturer 1 Texas Instruments + iProduct 2 XDS110 (03.00.00.13) Embed with CMSIS-DAP + iSerial 3 L1002566 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x00db + bNumInterfaces 7 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 0 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 0 + CDC Header: + bcdCDC 1.10 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 0 + bSlaveInterface 1 + CDC Call Management: + bmCapabilities 0x01 + call management + bDataInterface 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 3 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 3 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 0 + CDC Header: + bcdCDC 1.10 + CDC ACM: + bmCapabilities 0x06 + sends break + line coding and serial state + CDC Union: + bMasterInterface 3 + bSlaveInterface 4 + CDC Call Management: + bmCapabilities 0x01 + call management + bDataInterface 4 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 4 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x85 EP 5 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 5 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 3 Human Interface Device + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 6 XDS110 CMSIS-DAP + HID Device Descriptor: + bLength 9 + bDescriptorType 33 + bcdHID 1.11 + bCountryCode 0 Not supported + bNumDescriptors 1 + bDescriptorType 34 Report + wDescriptorLength 24 + Report Descriptor: (length is 24) + Item(Global): Usage Page, data= [ 0x00 0xff ] 65280 + (null) + Item(Local ): Usage, data= [ 0x01 ] 1 + (null) + Item(Main ): Collection, data= [ 0x01 ] 1 + Application + Item(Local ): Usage, data= [ 0x03 ] 3 + (null) + Item(Global): Report Size, data= [ 0x08 ] 8 + Item(Global): Report Count, data= [ 0x40 ] 64 + Item(Main ): Input, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Local ): Usage, data= [ 0x04 ] 4 + (null) + Item(Global): Report Size, data= [ 0x08 ] 8 + Item(Global): Report Count, data= [ 0x40 ] 64 + Item(Main ): Output, data= [ 0x02 ] 2 + Data Variable Absolute No_Wrap Linear + Preferred_State No_Null_Position Non_Volatile Bitfield + Item(Main ): End Collection, data=none + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x86 EP 6 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x04 EP 4 OUT + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 6 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x05 EP 5 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x87 EP 7 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/jimtcl b/jimtcl index 70b007b636..1933e5457b 160000 --- a/jimtcl +++ b/jimtcl @@ -1 +1 @@ -Subproject commit 70b007b63669a709b0e8aef34a22658047815cc2 +Subproject commit 1933e5457b9512d39ebbe11ed32578aada149f49 diff --git a/src/Makefile.am b/src/Makefile.am index fc64e3d57f..678b02c7f7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libopenocd.la bin_PROGRAMS += %D%/openocd diff --git a/src/flash/Makefile.am b/src/flash/Makefile.am index 4c70702b53..c5eb2482b2 100644 --- a/src/flash/Makefile.am +++ b/src/flash/Makefile.am @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libflash.la %C%_libflash_la_SOURCES = \ %D%/common.c %D%/common.h diff --git a/src/flash/common.c b/src/flash/common.c index 0e7fe13ab1..ebd9396eb0 100644 --- a/src/flash/common.c +++ b/src/flash/common.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/common.h b/src/flash/common.h index 69f60d9a34..15aea5b810 100644 --- a/src/flash/common.h +++ b/src/flash/common.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_COMMON_H diff --git a/src/flash/nand/Makefile.am b/src/flash/nand/Makefile.am index abe90f8bb8..6a1a9b1931 100644 --- a/src/flash/nand/Makefile.am +++ b/src/flash/nand/Makefile.am @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libocdflashnand.la %C%_libocdflashnand_la_SOURCES = \ diff --git a/src/flash/nand/arm_io.c b/src/flash/nand/arm_io.c index 2b0c081bdf..80bd0cf25b 100644 --- a/src/flash/nand/arm_io.c +++ b/src/flash/nand/arm_io.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright (C) 2009 by Marvell Semiconductors, Inc. * Written by Nicolas Pitre <nico at marvell.com> * * Copyright (C) 2009 by David Brownell - * - * 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/>. */ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nand/arm_io.h b/src/flash/nand/arm_io.h index 8bb3114585..10f0e661c1 100644 --- a/src/flash/nand/arm_io.h +++ b/src/flash/nand/arm_io.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Copyright (C) 2009 by David Brownell - * - * 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/>. */ #ifndef OPENOCD_FLASH_NAND_ARM_IO_H #define OPENOCD_FLASH_NAND_ARM_IO_H diff --git a/src/flash/nand/at91sam9.c b/src/flash/nand/at91sam9.c index c8886d17af..bfbba67c4c 100644 --- a/src/flash/nand/at91sam9.c +++ b/src/flash/nand/at91sam9.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright (C) 2009 by Dean Glazeski * dnglaze@gmail.com - * - * 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/>. */ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nand/core.c b/src/flash/nand/core.c index c1f1bc4b8b..37e1d12e03 100644 --- a/src/flash/nand/core.c +++ b/src/flash/nand/core.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2002 Thomas Gleixner <tglx@linutronix.de> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * * * * Partially based on drivers/mtd/nand_ids.c from Linux. * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nand/core.h b/src/flash/nand/core.h index 12fc2b7681..137298cbc8 100644 --- a/src/flash/nand/core.h +++ b/src/flash/nand/core.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * @@ -6,19 +8,6 @@ * Copyright (C) 2000 David Woodhouse <dwmw2@mvhi.com> * * Copyright (C) 2000 Steven J. Hill <sjhill@realitydiluted.com> * * Copyright (C) 2000 Thomas Gleixner <tglx@linutronix.de> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_CORE_H @@ -190,6 +179,7 @@ enum oob_formats { NAND_OOB_YAFFS2 = 0x100,/* when writing, use YAFFS2 OOB layout */ }; +extern struct nand_device *nand_devices; struct nand_device *get_nand_device_by_num(int num); @@ -213,6 +203,8 @@ int nand_calculate_ecc(struct nand_device *nand, const uint8_t *dat, uint8_t *ecc_code); int nand_calculate_ecc_kw(struct nand_device *nand, const uint8_t *dat, uint8_t *ecc_code); +int nand_correct_data(struct nand_device *nand, u_char *dat, + u_char *read_ecc, u_char *calc_ecc); int nand_register_commands(struct command_context *cmd_ctx); diff --git a/src/flash/nand/davinci.c b/src/flash/nand/davinci.c index 84f8e34806..b7169feeba 100644 --- a/src/flash/nand/davinci.c +++ b/src/flash/nand/davinci.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 by David Brownell * - * * - * 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/>. * ***************************************************************************/ /* @@ -605,8 +594,6 @@ static int davinci_write_page_ecc4infix(struct nand_device *nand, uint32_t page, /* write this "out-of-band" data -- infix */ davinci_write_block_data(nand, oob, 16); oob += 16; - oob_size -= 16; - } while (data_size); /* the last data and OOB writes included the spare area */ diff --git a/src/flash/nand/driver.c b/src/flash/nand/driver.c index b525f3d0a3..ce79e1382b 100644 --- a/src/flash/nand/driver.c +++ b/src/flash/nand/driver.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -24,25 +13,6 @@ #include "core.h" #include "driver.h" -/* NAND flash controller - */ -extern struct nand_flash_controller nonce_nand_controller; -extern struct nand_flash_controller davinci_nand_controller; -extern struct nand_flash_controller lpc3180_nand_controller; -extern struct nand_flash_controller lpc32xx_nand_controller; -extern struct nand_flash_controller orion_nand_controller; -extern struct nand_flash_controller s3c2410_nand_controller; -extern struct nand_flash_controller s3c2412_nand_controller; -extern struct nand_flash_controller s3c2440_nand_controller; -extern struct nand_flash_controller s3c2443_nand_controller; -extern struct nand_flash_controller s3c6400_nand_controller; -extern struct nand_flash_controller mxc_nand_flash_controller; -extern struct nand_flash_controller imx31_nand_flash_controller; -extern struct nand_flash_controller at91sam9_nand_controller; -extern struct nand_flash_controller nuc910_nand_controller; - -/* extern struct nand_flash_controller boundary_scan_nand_controller; */ - static struct nand_flash_controller *nand_flash_controllers[] = { &nonce_nand_controller, &davinci_nand_controller, @@ -58,7 +28,6 @@ static struct nand_flash_controller *nand_flash_controllers[] = { &imx31_nand_flash_controller, &at91sam9_nand_controller, &nuc910_nand_controller, -/* &boundary_scan_nand_controller, */ NULL }; diff --git a/src/flash/nand/driver.h b/src/flash/nand/driver.h index 690ee91ec8..4e84f10fbd 100644 --- a/src/flash/nand/driver.h +++ b/src/flash/nand/driver.h @@ -1,21 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_DRIVER_H @@ -100,4 +89,19 @@ typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void *); */ int nand_driver_walk(nand_driver_walker_t f, void *x); +extern struct nand_flash_controller at91sam9_nand_controller; +extern struct nand_flash_controller davinci_nand_controller; +extern struct nand_flash_controller imx31_nand_flash_controller; +extern struct nand_flash_controller lpc3180_nand_controller; +extern struct nand_flash_controller lpc32xx_nand_controller; +extern struct nand_flash_controller mxc_nand_flash_controller; +extern struct nand_flash_controller nonce_nand_controller; +extern struct nand_flash_controller nuc910_nand_controller; +extern struct nand_flash_controller orion_nand_controller; +extern struct nand_flash_controller s3c2410_nand_controller; +extern struct nand_flash_controller s3c2412_nand_controller; +extern struct nand_flash_controller s3c2440_nand_controller; +extern struct nand_flash_controller s3c2443_nand_controller; +extern struct nand_flash_controller s3c6400_nand_controller; + #endif /* OPENOCD_FLASH_NAND_DRIVER_H */ diff --git a/src/flash/nand/ecc.c b/src/flash/nand/ecc.c index 25b2eb10e3..20b8ba85dc 100644 --- a/src/flash/nand/ecc.c +++ b/src/flash/nand/ecc.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later WITH eCos-exception-2.0 + /* * This file contains an ECC algorithm from Toshiba that allows for detection * and correction of 1-bit errors in a 256 byte block of data. @@ -10,30 +12,6 @@ * Toshiba America Electronics Components, Inc. * * Copyright (C) 2006 Thomas Gleixner <tglx at linutronix.de> - * - * This file 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 or (at your option) any - * later version. - * - * This file 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/>. - * - * As a special exception, if other files instantiate templates or use - * macros or inline functions from these files, or you compile these - * files and link them with other works to produce a work based on these - * files, these files do not by themselves cause the resulting work to be - * covered by the GNU General Public License. However the source code for - * these files must still be made available in accordance with section (3) - * of the GNU General Public License. - * - * This exception does not invalidate any other reasons why a work based on - * this file might be covered by the GNU General Public License. */ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nand/ecc_kw.c b/src/flash/nand/ecc_kw.c index fb3481d000..cea1a5a0ab 100644 --- a/src/flash/nand/ecc_kw.c +++ b/src/flash/nand/ecc_kw.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Reed-Solomon ECC handling for the Marvell Kirkwood SOC * Copyright (C) 2009 Marvell Semiconductor, Inc. * * Authors: Lennert Buytenhek <buytenh@wantstofly.org> * Nicolas Pitre <nico@fluxnic.net> - * - * This file 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 or (at your option) any - * later version. - * - * This file 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/>. */ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nand/fileio.c b/src/flash/nand/fileio.c index b9c7f79f7f..ca618b3756 100644 --- a/src/flash/nand/fileio.c +++ b/src/flash/nand/fileio.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2002 Thomas Gleixner <tglx@linutronix.de> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * * * * Partially based on drivers/mtd/nand_ids.c from Linux. * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nand/fileio.h b/src/flash/nand/fileio.h index 6a094c2f2c..a8d2524c73 100644 --- a/src/flash/nand/fileio.h +++ b/src/flash/nand/fileio.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_FILEIO_H diff --git a/src/flash/nand/imp.h b/src/flash/nand/imp.h index c8a4ed9c55..7b4f38e964 100644 --- a/src/flash/nand/imp.h +++ b/src/flash/nand/imp.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_IMP_H diff --git a/src/flash/nand/lpc3180.c b/src/flash/nand/lpc3180.c index bda7b87c32..c1af1d7372 100644 --- a/src/flash/nand/lpc3180.c +++ b/src/flash/nand/lpc3180.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * Copyright (C) 2010 richard vegh <vegh.ricsi@gmail.com> * * Copyright (C) 2010 Oyvind Harboe <oyvind.harboe@zylin.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nand/lpc3180.h b/src/flash/nand/lpc3180.h index c02ee5b27a..519be7e7fd 100644 --- a/src/flash/nand/lpc3180.h +++ b/src/flash/nand/lpc3180.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_LPC3180_H diff --git a/src/flash/nand/lpc32xx.c b/src/flash/nand/lpc32xx.c index 49890c2abb..1fdae9fe53 100644 --- a/src/flash/nand/lpc32xx.c +++ b/src/flash/nand/lpc32xx.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -9,19 +11,6 @@ * Based on a combination of the lpc3180 driver and code from * * uboot-2009.03-lpc32xx by Kevin Wells. * * Any bugs are mine. --BSt * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -35,8 +24,6 @@ static int lpc32xx_reset(struct nand_device *nand); static int lpc32xx_controller_ready(struct nand_device *nand, int timeout); static int lpc32xx_tc_ready(struct nand_device *nand, int timeout); -extern int nand_correct_data(struct nand_device *nand, u_char *dat, - u_char *read_ecc, u_char *calc_ecc); /* These are offset with the working area in IRAM when using DMA to * read/write data to the SLC controller. @@ -1040,7 +1027,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand, LOG_DEBUG("SLC write page %" PRIx32 " data=%d, oob=%d, " "data_size=%" PRIu32 ", oob_size=%" PRIu32, - page, data != 0, oob != 0, data_size, oob_size); + page, !!data, !!oob, data_size, oob_size); target_mem_base = pworking_area->address; /* diff --git a/src/flash/nand/lpc32xx.h b/src/flash/nand/lpc32xx.h index 12c8f48e67..f399142a9f 100644 --- a/src/flash/nand/lpc32xx.h +++ b/src/flash/nand/lpc32xx.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_LPC32XX_H diff --git a/src/flash/nand/mx3.c b/src/flash/nand/mx3.c index dc8d619a06..86e94685b7 100644 --- a/src/flash/nand/mx3.c +++ b/src/flash/nand/mx3.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 by Alexei Babich * * Rezonans plc., Chelyabinsk, Russia * * impatt@mail.ru * - * * - * 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/>. * ***************************************************************************/ /* diff --git a/src/flash/nand/mx3.h b/src/flash/nand/mx3.h index 00664d866a..b272962b4c 100644 --- a/src/flash/nand/mx3.h +++ b/src/flash/nand/mx3.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 by Alexei Babich * * Rezonans plc., Chelyabinsk, Russia * * impatt@mail.ru * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_MX3_H diff --git a/src/flash/nand/mxc.c b/src/flash/nand/mxc.c index 7aac721638..845a3bb9a6 100644 --- a/src/flash/nand/mxc.c +++ b/src/flash/nand/mxc.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 by Alexei Babich * * Rezonans plc., Chelyabinsk, Russia * @@ -8,19 +10,6 @@ * * * Copyright (C) 2011 by Erik Ahlen * * Avalon Innovation, Sweden * - * * - * 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/>. * ***************************************************************************/ /* diff --git a/src/flash/nand/mxc.h b/src/flash/nand/mxc.h index a1887288bf..ae2c03a758 100644 --- a/src/flash/nand/mxc.h +++ b/src/flash/nand/mxc.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 by Alexei Babich * * Rezonans plc., Chelyabinsk, Russia * @@ -5,19 +7,6 @@ * * * Copyright (C) 2011 by Erik Ahlen * * Avalon Innovation, Sweden * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_MXC_H diff --git a/src/flash/nand/nonce.c b/src/flash/nand/nonce.c index 6fda2618e9..bce4ed0f99 100644 --- a/src/flash/nand/nonce.c +++ b/src/flash/nand/nonce.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nand/nuc910.c b/src/flash/nand/nuc910.c index 9546f2ff27..d7f69e6ae0 100644 --- a/src/flash/nand/nuc910.c +++ b/src/flash/nand/nuc910.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ /* diff --git a/src/flash/nand/nuc910.h b/src/flash/nand/nuc910.h index 8877cf6331..3d633dc3ba 100644 --- a/src/flash/nand/nuc910.h +++ b/src/flash/nand/nuc910.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ /* diff --git a/src/flash/nand/orion.c b/src/flash/nand/orion.c index 69814eca35..7b19cbd241 100644 --- a/src/flash/nand/orion.c +++ b/src/flash/nand/orion.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 by Marvell Semiconductors, Inc. * * Written by Nicolas Pitre <nico at marvell.com> * - * * - * 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/>. * ***************************************************************************/ /* diff --git a/src/flash/nand/s3c2410.c b/src/flash/nand/s3c2410.c index 57b51b48ca..98268ebcc4 100644 --- a/src/flash/nand/s3c2410.c +++ b/src/flash/nand/s3c2410.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * - * * - * 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/>. * ***************************************************************************/ /* diff --git a/src/flash/nand/s3c2412.c b/src/flash/nand/s3c2412.c index 002378a16b..0eec35f509 100644 --- a/src/flash/nand/s3c2412.c +++ b/src/flash/nand/s3c2412.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * - * * - * 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/>. * ***************************************************************************/ /* diff --git a/src/flash/nand/s3c2440.c b/src/flash/nand/s3c2440.c index 44670e6f2d..789144cbda 100644 --- a/src/flash/nand/s3c2440.c +++ b/src/flash/nand/s3c2440.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * - * * - * 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/>. * ***************************************************************************/ /* diff --git a/src/flash/nand/s3c2443.c b/src/flash/nand/s3c2443.c index ffd3864bf3..7166702ab1 100644 --- a/src/flash/nand/s3c2443.c +++ b/src/flash/nand/s3c2443.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * - * * - * 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/>. * ***************************************************************************/ /* diff --git a/src/flash/nand/s3c24xx.c b/src/flash/nand/s3c24xx.c index c0471eddfd..5c2f2bc3fc 100644 --- a/src/flash/nand/s3c24xx.c +++ b/src/flash/nand/s3c24xx.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * - * * - * 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/>. * ***************************************************************************/ /* diff --git a/src/flash/nand/s3c24xx.h b/src/flash/nand/s3c24xx.h index 4b0c02fc41..6b196a1ab5 100644 --- a/src/flash/nand/s3c24xx.h +++ b/src/flash/nand/s3c24xx.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NAND_S3C24XX_H diff --git a/src/flash/nand/s3c24xx_regs.h b/src/flash/nand/s3c24xx_regs.h index 46bda6bfe9..3960cb36ac 100644 --- a/src/flash/nand/s3c24xx_regs.h +++ b/src/flash/nand/s3c24xx_regs.h @@ -1,19 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + /*************************************************************************** * Copyright (C) 2004, 2005 by Simtec Electronics * * linux@simtec.co.uk * * http://www.simtec.co.uk/products/SWLINUX/ * - * * - * 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; version 2 of the License. * - * * - * 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/>. * ***************************************************************************/ /* diff --git a/src/flash/nand/s3c6400.c b/src/flash/nand/s3c6400.c index 7058133bcc..aebe0443b5 100644 --- a/src/flash/nand/s3c6400.c +++ b/src/flash/nand/s3c6400.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2010 by Peter Korsgaard <jacmet@sunsite.dk> * * Heavily based on s3c2412.c by Ben Dooks <ben@fluff.org> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nand/tcl.c b/src/flash/nand/tcl.c index b796fb7cec..67a62770fb 100644 --- a/src/flash/nand/tcl.c +++ b/src/flash/nand/tcl.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2002 Thomas Gleixner <tglx@linutronix.de> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * * * * Partially based on drivers/mtd/nand_ids.c from Linux. * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -28,9 +17,6 @@ #include "fileio.h" #include <target/target.h> -/* to be removed */ -extern struct nand_device *nand_devices; - COMMAND_HANDLER(handle_nand_list_command) { struct nand_device *p; diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 1c96f64c03..2b7c947d5e 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libocdflashnor.la %C%_libocdflashnor_la_SOURCES = \ %D%/core.c \ @@ -52,8 +54,10 @@ NOR_DRIVERS = \ %D%/psoc4.c \ %D%/psoc5lp.c \ %D%/psoc6.c \ + %D%/qn908x.c \ %D%/renesas_rpchf.c \ %D%/rp2040.c \ + %D%/rsl10.c \ %D%/sfdp.c \ %D%/sh_qspi.c \ %D%/sim3x.c \ diff --git a/src/flash/nor/aduc702x.c b/src/flash/nor/aduc702x.c index 492b658134..ea7f5e3730 100644 --- a/src/flash/nor/aduc702x.c +++ b/src/flash/nor/aduc702x.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2008 by Kevin McGuire * * Copyright (C) 2008 by Marcel Wijlaars * * Copyright (C) 2009 by Michael Ashton * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/aducm360.c b/src/flash/nor/aducm360.c index 4e816fd618..ce9bf24453 100644 --- a/src/flash/nor/aducm360.c +++ b/src/flash/nor/aducm360.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2015 by Ivan Buliev * * i.buliev@mikrosistemi.com * - * * - * 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/>. * ***************************************************************************/ /*************************************************************************** diff --git a/src/flash/nor/ambiqmicro.c b/src/flash/nor/ambiqmicro.c index 6eda9286c1..2b458bc8fd 100644 --- a/src/flash/nor/ambiqmicro.c +++ b/src/flash/nor/ambiqmicro.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: BSD-3-Clause + /****************************************************************************** * * @file ambiqmicro.c @@ -14,33 +16,6 @@ * Copyright (c) 2015-2016, Ambiq Micro, Inc. * * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * *****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" diff --git a/src/flash/nor/at91sam3.c b/src/flash/nor/at91sam3.c index cec86fc241..b1cb8f110e 100644 --- a/src/flash/nor/at91sam3.c +++ b/src/flash/nor/at91sam3.c @@ -1,59 +1,17 @@ -/*************************************************************************** - * Copyright (C) 2009 by Duane Ellis * - * openocd@duaneellis.com * - * * - * Copyright (C) 2010 by Olaf Lüke (at91sam3s* support) * - * olaf@uni-paderborn.de * - * * - * Copyright (C) 2011 by Olivier Schonken (at91sam3x* support) * * - * and Jim Norris * - * 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/>. * -****************************************************************************/ - -/* Some of the lower level code was based on code supplied by - * ATMEL under this copyright. */ - -/* BEGIN ATMEL COPYRIGHT */ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-Source-Code) + +/* + * Copyright (C) 2009 by Duane Ellis <openocd@duaneellis.com> * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. + * at91sam3s* support + * Copyright (C) 2010 by Olaf Lüke <olaf@uni-paderborn.de> + * Copyright (C) 2011 by Olivier Schonken and Jim Norris * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- + * Some of the lower level code was based on code supplied by + * ATMEL under BSD-Source-Code License and this copyright. + * ATMEL Microcontroller Software Support + * Copyright (c) 2009, Atmel Corporation. All rights reserved. */ -/* END ATMEL COPYRIGHT */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -109,8 +67,6 @@ #define OFFSET_EFC_FSR 8 #define OFFSET_EFC_FRR 12 -extern const struct flash_driver at91sam3_flash; - static float _tomhz(uint32_t freq_hz) { float f; diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index 4ec2ee89ec..62127530f1 100644 --- a/src/flash/nor/at91sam4.c +++ b/src/flash/nor/at91sam4.c @@ -1,60 +1,19 @@ -/*************************************************************************** - * Copyright (C) 2009 by Duane Ellis * - * openocd@duaneellis.com * - * * - * Copyright (C) 2010 by Olaf Lüke (at91sam3s* support) * - * olaf@uni-paderborn.de * - * * - * Copyright (C) 2011 by Olivier Schonken, Jim Norris * - * (at91sam3x* & at91sam4 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/>. * -****************************************************************************/ - -/* Some of the lower level code was based on code supplied by - * ATMEL under this copyright. */ - -/* BEGIN ATMEL COPYRIGHT */ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-Source-Code) + +/* + * Copyright (C) 2009 by Duane Ellis <openocd@duaneellis.com> * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. + * at91sam3s* support + * Copyright (C) 2010 by Olaf Lüke <olaf@uni-paderborn.de> * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. + * at91sam3x* & at91sam4 support + * Copyright (C) 2011 by Olivier Schonken, Jim Norris * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- + * Some of the lower level code was based on code supplied by + * ATMEL under BSD-Source-Code License and this copyright. + * ATMEL Microcontroller Software Support + * Copyright (c) 2009, Atmel Corporation. All rights reserved. */ -/* END ATMEL COPYRIGHT */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -103,8 +62,6 @@ #define OFFSET_EFC_FSR 8 #define OFFSET_EFC_FRR 12 -extern const struct flash_driver at91sam4_flash; - static float _tomhz(uint32_t freq_hz) { float f; diff --git a/src/flash/nor/at91sam4l.c b/src/flash/nor/at91sam4l.c index 77dc07f7c6..ddf42a8c5f 100644 --- a/src/flash/nor/at91sam4l.c +++ b/src/flash/nor/at91sam4l.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2013 by Andrey Yurovsky * * Andrey Yurovsky <yurovsky@gmail.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/at91sam7.c b/src/flash/nor/at91sam7.c index f98d186fb4..6879a1bf23 100644 --- a/src/flash/nor/at91sam7.c +++ b/src/flash/nor/at91sam7.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Gheorghe Guran (atlas) * - * * - * 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/>. * ****************************************************************************/ /*************************************************************************** @@ -571,12 +560,22 @@ static int at91sam7_read_part_info(struct flash_bank *bank) if (bnk > 0) { if (!t_bank->next) { /* create a new flash bank element */ - struct flash_bank *fb = malloc(sizeof(struct flash_bank)); + struct flash_bank *fb = calloc(sizeof(struct flash_bank), 1); + if (!fb) { + LOG_ERROR("No memory for flash bank"); + return ERROR_FAIL; + } fb->target = target; fb->driver = bank->driver; + fb->default_padded_value = 0xff; + fb->erased_value = 0xff; fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank)); - fb->name = "sam7_probed"; - fb->next = NULL; + if (!fb->driver_priv) { + free(fb); + LOG_ERROR("No memory for flash driver priv"); + return ERROR_FAIL; + } + fb->name = strdup("sam7_probed"); /* link created bank in 'flash_banks' list */ t_bank->next = fb; @@ -587,8 +586,6 @@ static int at91sam7_read_part_info(struct flash_bank *bank) t_bank->bank_number = bnk; t_bank->base = base_address + bnk * bank_size; t_bank->size = bank_size; - t_bank->chip_width = 0; - t_bank->bus_width = 4; t_bank->num_sectors = sectors_num; /* allocate sectors */ @@ -702,8 +699,6 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command) uint32_t bank_size; uint32_t ext_freq = 0; - unsigned int chip_width; - unsigned int bus_width; unsigned int banks_num; unsigned int num_sectors; @@ -727,9 +722,6 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], base_address); - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[3], chip_width); - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[4], bus_width); - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[8], banks_num); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[9], num_sectors); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[10], pages_per_sector); @@ -743,7 +735,7 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command) at91sam7_info->ext_freq = ext_freq; } - if ((bus_width == 0) || (banks_num == 0) || (num_sectors == 0) || + if ((banks_num == 0) || (num_sectors == 0) || (pages_per_sector == 0) || (page_size == 0) || (num_nvmbits == 0)) { at91sam7_info->flash_autodetection = 1; return ERROR_OK; @@ -756,12 +748,22 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command) if (bnk > 0) { if (!t_bank->next) { /* create a new bank element */ - struct flash_bank *fb = malloc(sizeof(struct flash_bank)); + struct flash_bank *fb = calloc(sizeof(struct flash_bank), 1); + if (!fb) { + LOG_ERROR("No memory for flash bank"); + return ERROR_FAIL; + } fb->target = target; fb->driver = bank->driver; + fb->default_padded_value = 0xff; + fb->erased_value = 0xff; fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank)); - fb->name = "sam7_probed"; - fb->next = NULL; + if (!fb->driver_priv) { + free(fb); + LOG_ERROR("No memory for flash driver priv"); + return ERROR_FAIL; + } + fb->name = strdup("sam7_probed"); /* link created bank in 'flash_banks' list */ t_bank->next = fb; @@ -772,8 +774,6 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command) t_bank->bank_number = bnk; t_bank->base = base_address + bnk * bank_size; t_bank->size = bank_size; - t_bank->chip_width = chip_width; - t_bank->bus_width = bus_width; t_bank->num_sectors = num_sectors; /* allocate sectors */ diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index 5f314d82b2..36298f19d0 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2013 by Andrey Yurovsky * * Andrey Yurovsky <yurovsky@gmail.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -23,6 +12,7 @@ #include "imp.h" #include "helper/binarybuffer.h" +#include <helper/time_support.h> #include <jtag/jtag.h> #include <target/cortex_m.h> @@ -42,7 +32,7 @@ #define SAMD_NVMCTRL_CTRLA 0x00 /* NVM control A register */ #define SAMD_NVMCTRL_CTRLB 0x04 /* NVM control B register */ #define SAMD_NVMCTRL_PARAM 0x08 /* NVM parameters register */ -#define SAMD_NVMCTRL_INTFLAG 0x18 /* NVM Interrupt Flag Status & Clear */ +#define SAMD_NVMCTRL_INTFLAG 0x14 /* NVM Interrupt Flag Status & Clear */ #define SAMD_NVMCTRL_STATUS 0x18 /* NVM status register */ #define SAMD_NVMCTRL_ADDR 0x1C /* NVM address register */ #define SAMD_NVMCTRL_LOCK 0x20 /* NVM Lock section register */ @@ -66,6 +56,9 @@ /* NVMCTRL bits */ #define SAMD_NVM_CTRLB_MANW 0x80 +/* NVMCTRL_INTFLAG bits */ +#define SAMD_NVM_INTFLAG_READY 0x01 + /* Known identifiers */ #define SAMD_PROCESSOR_M0 0x01 #define SAMD_FAMILY_D 0x00 @@ -85,7 +78,7 @@ #define SAMD_GET_DEVSEL(id) (id & 0xFF) /* Bits to mask out lockbits in user row */ -#define NVMUSERROW_LOCKBIT_MASK ((uint64_t)0x0000FFFFFFFFFFFF) +#define NVMUSERROW_LOCKBIT_MASK 0x0000FFFFFFFFFFFFULL struct samd_part { uint8_t id; @@ -250,8 +243,12 @@ static const struct samd_part saml21_parts[] = { { 0x1F, "SAMR30E18A", 256, 32 }, /* SAMR34/R35 parts have integrated SAML21 with a lora radio */ - { 0x28, "SAMR34J18", 256, 32 }, - { 0x2B, "SAMR35J18", 256, 32 }, + { 0x28, "SAMR34J18", 256, 40 }, + { 0x29, "SAMR34J17", 128, 24 }, + { 0x2A, "SAMR34J16", 64, 12 }, + { 0x2B, "SAMR35J18", 256, 40 }, + { 0x2C, "SAMR35J17", 128, 24 }, + { 0x2D, "SAMR35J16", 64, 12 }, }; /* Known SAML22 parts. */ @@ -319,31 +316,31 @@ struct samd_family { static const struct samd_family samd_families[] = { { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_20, samd20_parts, ARRAY_SIZE(samd20_parts), - (uint64_t)0xFFFF01FFFE01FF77 }, + 0xFFFF01FFFE01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_21, samd21_parts, ARRAY_SIZE(samd21_parts), - (uint64_t)0xFFFF01FFFE01FF77 }, + 0xFFFF01FFFE01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_09, samd09_parts, ARRAY_SIZE(samd09_parts), - (uint64_t)0xFFFF01FFFE01FF77 }, + 0xFFFF01FFFE01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_10, samd10_parts, ARRAY_SIZE(samd10_parts), - (uint64_t)0xFFFF01FFFE01FF77 }, + 0xFFFF01FFFE01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_11, samd11_parts, ARRAY_SIZE(samd11_parts), - (uint64_t)0xFFFF01FFFE01FF77 }, + 0xFFFF01FFFE01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_21, saml21_parts, ARRAY_SIZE(saml21_parts), - (uint64_t)0xFFFF03FFFC01FF77 }, + 0xFFFF03FFFC01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_22, saml22_parts, ARRAY_SIZE(saml22_parts), - (uint64_t)0xFFFF03FFFC01FF77 }, + 0xFFFF03FFFC01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_20, samc20_parts, ARRAY_SIZE(samc20_parts), - (uint64_t)0xFFFF03FFFC01FF77 }, + 0xFFFF03FFFC01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_21, samc21_parts, ARRAY_SIZE(samc21_parts), - (uint64_t)0xFFFF03FFFC01FF77 }, + 0xFFFF03FFFC01FF77ULL }, }; struct samd_info { @@ -508,7 +505,27 @@ static int samd_probe(struct flash_bank *bank) static int samd_check_error(struct target *target) { int ret, ret2; + uint8_t intflag; uint16_t status; + int timeout_ms = 1000; + int64_t ts_start = timeval_ms(); + + do { + ret = target_read_u8(target, + SAMD_NVMCTRL + SAMD_NVMCTRL_INTFLAG, &intflag); + if (ret != ERROR_OK) { + LOG_ERROR("Can't read NVM intflag"); + return ret; + } + if (intflag & SAMD_NVM_INTFLAG_READY) + break; + keep_alive(); + } while (timeval_ms() - ts_start < timeout_ms); + + if (!(intflag & SAMD_NVM_INTFLAG_READY)) { + LOG_ERROR("SAMD: NVM programming timed out"); + return ERROR_FLASH_OPERATION_FAILED; + } ret = target_read_u16(target, SAMD_NVMCTRL + SAMD_NVMCTRL_STATUS, &status); @@ -554,7 +571,8 @@ static int samd_issue_nvmctrl_command(struct target *target, uint16_t cmd) } /* Issue the NVM command */ - res = target_write_u16(target, + /* 32-bit write is used to ensure atomic operation on ST-Link */ + res = target_write_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLA, SAMD_NVM_CMD(cmd)); if (res != ERROR_OK) return res; diff --git a/src/flash/nor/ath79.c b/src/flash/nor/ath79.c index 394b6dda06..1d1ec02b33 100644 --- a/src/flash/nor/ath79.c +++ b/src/flash/nor/ath79.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2015 by Tobias Diedrich * * <ranma+openwrt@tdiedrich.de> * @@ -5,20 +7,6 @@ * based on the stmsmi code written by Antonio Borneo * * <borneo.antonio@gmail.com> * * * - * 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, write to the * - * Free Software Foundation, Inc. * - * * ***************************************************************************/ /* * Driver for the Atheros AR7xxx/AR9xxx SPI flash interface. diff --git a/src/flash/nor/atsame5.c b/src/flash/nor/atsame5.c index fbf0fb2ede..c590081fcc 100644 --- a/src/flash/nor/atsame5.c +++ b/src/flash/nor/atsame5.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2017 by Tomas Vanek * * vanekt@fbl.cz * @@ -5,19 +7,6 @@ * Based on at91samd.c * * Copyright (C) 2013 by Andrey Yurovsky * * Andrey Yurovsky <yurovsky@gmail.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -104,7 +93,7 @@ #define SAMD_GET_DEVSEL(id) (id & 0xFF) /* Bits to mask user row */ -#define NVMUSERROW_SAM_E5_D5_MASK ((uint64_t)0x7FFF00FF3C007FFF) +#define NVMUSERROW_SAM_E5_D5_MASK 0x7FFF00FF3C007FFFULL struct samd_part { uint8_t id; diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c index efc242395f..24c432cba3 100644 --- a/src/flash/nor/atsamv.c +++ b/src/flash/nor/atsamv.c @@ -1,63 +1,22 @@ -/*************************************************************************** - * Copyright (C) 2009 by Duane Ellis * - * openocd@duaneellis.com * - * * - * Copyright (C) 2010 by Olaf Lüke (at91sam3s* support) * - * olaf@uni-paderborn.de * - * * - * Copyright (C) 2011 by Olivier Schonken, Jim Norris * - * (at91sam3x* & at91sam4 support)* * - * * - * Copyright (C) 2015 Morgan Quigley * - * (atsamv, atsams, and atsame 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/>. * - ***************************************************************************/ - -/* Some of the lower level code was based on code supplied by - * ATMEL under this copyright. */ - -/* BEGIN ATMEL COPYRIGHT */ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-Source-Code) + +/* + * Copyright (C) 2009 by Duane Ellis <openocd@duaneellis.com> * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: + * at91sam3s* support + * Copyright (C) 2010 by Olaf Lüke <olaf@uni-paderborn.de> * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. + * at91sam3x* & at91sam4 support + * Copyright (C) 2011 by Olivier Schonken and Jim Norris * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. + * atsamv, atsams, and atsame support + * Copyright (C) 2015 Morgan Quigley * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- + * Some of the lower level code was based on code supplied by + * ATMEL under BSD-Source-Code License and this copyright. + * ATMEL Microcontroller Software Support + * Copyright (c) 2009, Atmel Corporation. All rights reserved. */ -/* END ATMEL COPYRIGHT */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -94,8 +53,6 @@ #define SAMV_PAGE_SIZE 512 #define SAMV_FLASH_BASE 0x00400000 -extern const struct flash_driver atsamv_flash; - struct samv_flash_bank { bool probed; unsigned size_bytes; diff --git a/src/flash/nor/avrf.c b/src/flash/nor/avrf.c index 634f7396a8..1d317a10c6 100644 --- a/src/flash/nor/avrf.c +++ b/src/flash/nor/avrf.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 by Simon Qian * * SimonQian@SimonQian.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -75,6 +64,7 @@ static const struct avrf_type avft_chips_info[] = { {"atmega324pa", 0x9511, 128, 256, 4, 256}, {"atmega644p", 0x960a, 256, 256, 8, 256}, {"atmega1284p", 0x9705, 256, 512, 8, 512}, + {"atmega32u4", 0x9587, 128, 256, 4, 256}, }; /* avr program functions */ diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c index 60eccefaf0..9ced2e9718 100644 --- a/src/flash/nor/bluenrg-x.c +++ b/src/flash/nor/bluenrg-x.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2017 by Michele Sardo * * msmttchr@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -35,6 +24,8 @@ #define JTAG_IDCODE_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->jtag_idcode_reg) #define FLASH_PAGE_SIZE(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_page_size) +#define FLASH_SIZE_REG_MASK (0xFFFF) + struct flash_ctrl_priv_data { uint32_t die_id_reg; uint32_t jtag_idcode_reg; @@ -75,6 +66,16 @@ static const struct flash_ctrl_priv_data flash_priv_data_lp = { .part_name = "BLUENRG-LP", }; +static const struct flash_ctrl_priv_data flash_priv_data_lps = { + .die_id_reg = 0x40000000, + .jtag_idcode_reg = 0x40000004, + .flash_base = 0x10040000, + .flash_regs_base = 0x40001000, + .flash_page_size = 2048, + .jtag_idcode = 0x02028041, + .part_name = "BLUENRG-LPS", +}; + struct bluenrgx_flash_bank { bool probed; uint32_t die_id; @@ -84,8 +85,8 @@ struct bluenrgx_flash_bank { static const struct flash_ctrl_priv_data *flash_ctrl[] = { &flash_priv_data_1, &flash_priv_data_2, - &flash_priv_data_lp -}; + &flash_priv_data_lp, + &flash_priv_data_lps}; /* flash_bank bluenrg-x 0 0 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command) @@ -235,7 +236,7 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, struct target *target = bank->target; uint32_t buffer_size = 16384 + 8; struct working_area *write_algorithm; - struct working_area *write_algorithm_sp; + struct working_area *write_algorithm_stack; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[5]; @@ -284,10 +285,10 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - /* Stack pointer area */ + /* Stack area */ if (target_alloc_working_area(target, 128, - &write_algorithm_sp) != ERROR_OK) { - LOG_DEBUG("no working area for write code stack pointer"); + &write_algorithm_stack) != ERROR_OK) { + LOG_DEBUG("no working area for target algorithm stack"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -299,8 +300,19 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "sp", 32, PARAM_OUT); - /* Put the parameter at the first available stack location */ - init_mem_param(&mem_params[0], write_algorithm_sp->address + 80, 32, PARAM_OUT); + /* Put the 4th parameter at the location in the stack frame of target write() function. + * See contrib/loaders/flash/bluenrg-x/bluenrg-x_write.lst + * 34 ldr r6, [sp, #80] + * ^^^ offset + */ + init_mem_param(&mem_params[0], write_algorithm_stack->address + 80, 32, PARAM_OUT); + /* Stack for target write algorithm - target write() function has + * __attribute__((naked)) so it does not setup the new stack frame. + * Therefore the stack frame uses the area from SP upwards! + * Interrupts are disabled and no subroutines are called from write() + * so no need to allocate stack below SP. + * TODO: remove __attribute__((naked)) and use similar parameter passing as stm32l4x */ + buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_stack->address); /* FIFO start address (first two words used for write and read pointers) */ buf_set_u32(reg_params[0].value, 0, 32, source->address); @@ -310,14 +322,12 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, buf_set_u32(reg_params[2].value, 0, 32, address); /* Number of bytes */ buf_set_u32(reg_params[3].value, 0, 32, count); - /* Stack pointer for program working area */ - buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_sp->address); /* Flash register base address */ buf_set_u32(mem_params[0].value, 0, 32, bluenrgx_info->flash_ptr->flash_regs_base); LOG_DEBUG("source->address = " TARGET_ADDR_FMT, source->address); LOG_DEBUG("source->address+ source->size = " TARGET_ADDR_FMT, source->address+source->size); - LOG_DEBUG("write_algorithm_sp->address = " TARGET_ADDR_FMT, write_algorithm_sp->address); + LOG_DEBUG("write_algorithm_stack->address = " TARGET_ADDR_FMT, write_algorithm_stack->address); LOG_DEBUG("address = %08" PRIx32, address); LOG_DEBUG("count = %08" PRIx32, count); @@ -356,7 +366,7 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); - target_free_working_area(target, write_algorithm_sp); + target_free_working_area(target, write_algorithm_stack); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); @@ -377,7 +387,7 @@ static int bluenrgx_probe(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - if (idcode != flash_priv_data_lp.jtag_idcode) { + if ((idcode != flash_priv_data_lp.jtag_idcode) && (idcode != flash_priv_data_lps.jtag_idcode)) { retval = target_read_u32(bank->target, BLUENRG2_JTAG_REG, &idcode); if (retval != ERROR_OK) return retval; @@ -395,6 +405,7 @@ static int bluenrgx_probe(struct flash_bank *bank) } } retval = bluenrgx_read_flash_reg(bank, FLASH_SIZE_REG, &size_info); + size_info = size_info & FLASH_SIZE_REG_MASK; if (retval != ERROR_OK) return retval; diff --git a/src/flash/nor/bluenrg-x.h b/src/flash/nor/bluenrg-x.h index 3b84b8b19f..720cb6e618 100644 --- a/src/flash/nor/bluenrg-x.h +++ b/src/flash/nor/bluenrg-x.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2019 by STMicroelectronics. * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_BLUENRGX_H diff --git a/src/flash/nor/cc26xx.c b/src/flash/nor/cc26xx.c index 7e526492bc..54d61421ce 100644 --- a/src/flash/nor/cc26xx.c +++ b/src/flash/nor/cc26xx.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2017 by Texas Instruments, Inc. * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -45,6 +34,16 @@ struct cc26xx_bank { uint32_t params_addr[2]; }; +/* Flash helper algorithm for CC26x0 Chameleon targets */ +static const uint8_t cc26x0_algo[] = { +#include "../../../contrib/loaders/flash/cc26xx/cc26x0_algo.inc" +}; + +/* Flash helper algorithm for CC26x2 Agama targets */ +static const uint8_t cc26x2_algo[] = { +#include "../../../contrib/loaders/flash/cc26xx/cc26x2_algo.inc" +}; + static int cc26xx_auto_probe(struct flash_bank *bank); static uint32_t cc26xx_device_type(uint32_t icepick_id, uint32_t user_id) @@ -262,7 +261,6 @@ FLASH_BANK_COMMAND_HANDLER(cc26xx_flash_bank_command) /* Finish initialization of bank */ bank->driver_priv = cc26xx_bank; - bank->next = NULL; return ERROR_OK; } diff --git a/src/flash/nor/cc26xx.h b/src/flash/nor/cc26xx.h index 51a09f19bb..83fc94024a 100644 --- a/src/flash/nor/cc26xx.h +++ b/src/flash/nor/cc26xx.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2017 by Texas Instruments, Inc. * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_CC26XX_H @@ -88,14 +77,4 @@ struct cc26xx_algo_params { uint8_t status[4]; }; -/* Flash helper algorithm for CC26x0 Chameleon targets */ -const uint8_t cc26x0_algo[] = { -#include "../../../contrib/loaders/flash/cc26xx/cc26x0_algo.inc" -}; - -/* Flash helper algorithm for CC26x2 Agama targets */ -const uint8_t cc26x2_algo[] = { -#include "../../../contrib/loaders/flash/cc26xx/cc26x2_algo.inc" -}; - #endif /* OPENOCD_FLASH_NOR_CC26XX_H */ diff --git a/src/flash/nor/cc3220sf.c b/src/flash/nor/cc3220sf.c index 723e605c70..74cb7aea57 100644 --- a/src/flash/nor/cc3220sf.c +++ b/src/flash/nor/cc3220sf.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2017 by Texas Instruments, Inc. * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -33,6 +22,11 @@ struct cc3220sf_bank { struct armv7m_algorithm armv7m_info; }; +/* Flash helper algorithm for CC3220SF */ +static const uint8_t cc3220sf_algo[] = { +#include "../../../contrib/loaders/flash/cc3220sf/cc3220sf.inc" +}; + static int cc3220sf_mass_erase(struct flash_bank *bank) { struct target *target = bank->target; @@ -102,7 +96,6 @@ FLASH_BANK_COMMAND_HANDLER(cc3220sf_flash_bank_command) /* Finish initialization of flash bank */ bank->driver_priv = cc3220sf_bank; - bank->next = NULL; return ERROR_OK; } diff --git a/src/flash/nor/cc3220sf.h b/src/flash/nor/cc3220sf.h index 36c17be900..eb2a6c6480 100644 --- a/src/flash/nor/cc3220sf.h +++ b/src/flash/nor/cc3220sf.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2017 by Texas Instruments, Inc. * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_CC3220SF_H @@ -37,9 +26,4 @@ #define FMC_ERASE_VALUE (FMC_DEFAULT_VALUE | FMC_ERASE_BIT) #define FMC_MERASE_VALUE (FMC_DEFAULT_VALUE | FMC_MERASE_BIT) -/* Flash helper algorithm for CC3220SF */ -const uint8_t cc3220sf_algo[] = { -#include "../../../contrib/loaders/flash/cc3220sf/cc3220sf.inc" -}; - #endif /* OPENOCD_FLASH_NOR_CC3220SF_H */ diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c index 85115869d5..78bc91e7d0 100644 --- a/src/flash/nor/cfi.c +++ b/src/flash/nor/cfi.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -5,19 +7,6 @@ * michael@schwingen.org * * Copyright (C) 2010 Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/cfi.h b/src/flash/nor/cfi.h index f8ca290a53..ec7f47403a 100644 --- a/src/flash/nor/cfi.h +++ b/src/flash/nor/cfi.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_CFI_H diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index 30d387ae0c..5e6c971527 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007-2010 Øyvind Harboe <oyvind.harboe@zylin.com> * @@ -5,19 +7,6 @@ * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * * Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> * * Copyright (C) 2017-2018 Tomas Vanek <vanekt@fbl.cz> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -429,7 +418,11 @@ int default_flash_blank_check(struct flash_bank *bank) bank->sectors[i].is_erased = block_array[i].result; retval = ERROR_OK; } else { - LOG_USER("Running slow fallback erase check - add working memory"); + if (retval == ERROR_NOT_IMPLEMENTED) + LOG_USER("Running slow fallback erase check"); + else + LOG_USER("Running slow fallback erase check - add working memory"); + retval = default_flash_mem_blank_check(bank); } free(block_array); diff --git a/src/flash/nor/core.h b/src/flash/nor/core.h index 97a368e8e8..80911f799c 100644 --- a/src/flash/nor/core.h +++ b/src/flash/nor/core.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * * Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_CORE_H @@ -31,8 +20,6 @@ struct image; -#define FLASH_MAX_ERROR_STR (128) - /** * Describes the geometry and status of a single flash sector * within a flash bank. A single bank typically consists of multiple @@ -265,6 +252,19 @@ int get_flash_bank_by_num(unsigned int num, struct flash_bank **bank); */ COMMAND_HELPER(flash_command_get_bank, unsigned name_index, struct flash_bank **bank); +/** + * Retrieves @a bank from a command argument, reporting errors parsing + * the bank identifier or retrieving the specified bank. The bank + * may be identified by its bank number or by @c name.instance, where + * @a instance is driver-specific. + * @param name_index The index to the string in args containing the + * bank identifier. + * @param bank On output, contains a pointer to the bank or NULL. + * @param do_probe Does auto-probing when set, otherwise without probing. + * @returns ERROR_OK on success, or an error indicating the problem. + */ +COMMAND_HELPER(flash_command_get_bank_probe_optional, unsigned int name_index, + struct flash_bank **bank, bool do_probe); /** * Returns the flash bank like get_flash_bank_by_num(), without probing. * @param num The flash bank number. diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index 7a5be65174..fc1644e297 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * * Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_DRIVER_H @@ -248,4 +237,77 @@ struct flash_driver { */ const struct flash_driver *flash_driver_find_by_name(const char *name); +extern const struct flash_driver aduc702x_flash; +extern const struct flash_driver aducm360_flash; +extern const struct flash_driver ambiqmicro_flash; +extern const struct flash_driver at91sam3_flash; +extern const struct flash_driver at91sam4_flash; +extern const struct flash_driver at91sam4l_flash; +extern const struct flash_driver at91sam7_flash; +extern const struct flash_driver at91samd_flash; +extern const struct flash_driver ath79_flash; +extern const struct flash_driver atsame5_flash; +extern const struct flash_driver atsamv_flash; +extern const struct flash_driver avr_flash; +extern const struct flash_driver bluenrgx_flash; +extern const struct flash_driver cc26xx_flash; +extern const struct flash_driver cc3220sf_flash; +extern const struct flash_driver cfi_flash; +extern const struct flash_driver dsp5680xx_flash; +extern const struct flash_driver efm32_flash; +extern const struct flash_driver em357_flash; +extern const struct flash_driver esirisc_flash; +extern const struct flash_driver faux_flash; +extern const struct flash_driver fespi_flash; +extern const struct flash_driver fm3_flash; +extern const struct flash_driver fm4_flash; +extern const struct flash_driver jtagspi_flash; +extern const struct flash_driver kinetis_flash; +extern const struct flash_driver kinetis_ke_flash; +extern const struct flash_driver lpc2000_flash; +extern const struct flash_driver lpc288x_flash; +extern const struct flash_driver lpc2900_flash; +extern const struct flash_driver lpcspifi_flash; +extern const struct flash_driver max32xxx_flash; +extern const struct flash_driver mdr_flash; +extern const struct flash_driver mrvlqspi_flash; +extern const struct flash_driver msp432_flash; +extern const struct flash_driver niietcm4_flash; +extern const struct flash_driver npcx_flash; +extern const struct flash_driver nrf51_flash; +extern const struct flash_driver nrf5_flash; +extern const struct flash_driver numicro_flash; +extern const struct flash_driver ocl_flash; +extern const struct flash_driver pic32mx_flash; +extern const struct flash_driver psoc4_flash; +extern const struct flash_driver psoc5lp_eeprom_flash; +extern const struct flash_driver psoc5lp_flash; +extern const struct flash_driver psoc5lp_nvl_flash; +extern const struct flash_driver psoc6_flash; +extern const struct flash_driver qn908x_flash; +extern const struct flash_driver renesas_rpchf_flash; +extern const struct flash_driver rp2040_flash; +extern const struct flash_driver rsl10_flash; +extern const struct flash_driver sh_qspi_flash; +extern const struct flash_driver sim3x_flash; +extern const struct flash_driver stellaris_flash; +extern const struct flash_driver stm32f1x_flash; +extern const struct flash_driver stm32f2x_flash; +extern const struct flash_driver stm32h7x_flash; +extern const struct flash_driver stm32l4x_flash; +extern const struct flash_driver stm32lx_flash; +extern const struct flash_driver stmqspi_flash; +extern const struct flash_driver stmsmi_flash; +extern const struct flash_driver str7x_flash; +extern const struct flash_driver str9x_flash; +extern const struct flash_driver str9xpec_flash; +extern const struct flash_driver swm050_flash; +extern const struct flash_driver tms470_flash; +extern const struct flash_driver vexriscv_nor_spi; +extern const struct flash_driver virtual_flash; +extern const struct flash_driver w600_flash; +extern const struct flash_driver xcf_flash; +extern const struct flash_driver xmc1xxx_flash; +extern const struct flash_driver xmc4xxx_flash; + #endif /* OPENOCD_FLASH_NOR_DRIVER_H */ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 132275ffc2..aab8ce5052 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -20,78 +9,6 @@ #endif #include "imp.h" -extern const struct flash_driver aduc702x_flash; -extern const struct flash_driver aducm360_flash; -extern const struct flash_driver ambiqmicro_flash; -extern const struct flash_driver at91sam3_flash; -extern const struct flash_driver at91sam4_flash; -extern const struct flash_driver at91sam4l_flash; -extern const struct flash_driver at91sam7_flash; -extern const struct flash_driver at91samd_flash; -extern const struct flash_driver ath79_flash; -extern const struct flash_driver atsame5_flash; -extern const struct flash_driver atsamv_flash; -extern const struct flash_driver avr_flash; -extern const struct flash_driver bluenrgx_flash; -extern const struct flash_driver cc3220sf_flash; -extern const struct flash_driver cc26xx_flash; -extern const struct flash_driver cfi_flash; -extern const struct flash_driver dsp5680xx_flash; -extern const struct flash_driver efm32_flash; -extern const struct flash_driver em357_flash; -extern const struct flash_driver esirisc_flash; -extern const struct flash_driver faux_flash; -extern const struct flash_driver fm3_flash; -extern const struct flash_driver fm4_flash; -extern const struct flash_driver fespi_flash; -extern const struct flash_driver gd32vf103_flash; -extern const struct flash_driver jtagspi_flash; -extern const struct flash_driver kinetis_flash; -extern const struct flash_driver kinetis_ke_flash; -extern const struct flash_driver lpc2000_flash; -extern const struct flash_driver lpc288x_flash; -extern const struct flash_driver lpc2900_flash; -extern const struct flash_driver lpcspifi_flash; -extern const struct flash_driver max32xxx_flash; -extern const struct flash_driver mdr_flash; -extern const struct flash_driver mrvlqspi_flash; -extern const struct flash_driver msp432_flash; -extern const struct flash_driver niietcm4_flash; -extern const struct flash_driver npcx_flash; -extern const struct flash_driver nrf5_flash; -extern const struct flash_driver nrf51_flash; -extern const struct flash_driver numicro_flash; -extern const struct flash_driver ocl_flash; -extern const struct flash_driver pic32mx_flash; -extern const struct flash_driver psoc4_flash; -extern const struct flash_driver psoc5lp_flash; -extern const struct flash_driver psoc5lp_eeprom_flash; -extern const struct flash_driver psoc5lp_nvl_flash; -extern const struct flash_driver psoc6_flash; -extern const struct flash_driver renesas_rpchf_flash; -extern const struct flash_driver rp2040_flash; -extern const struct flash_driver sh_qspi_flash; -extern const struct flash_driver sim3x_flash; -extern const struct flash_driver stellaris_flash; -extern const struct flash_driver stm32f1x_flash; -extern const struct flash_driver stm32f2x_flash; -extern const struct flash_driver stm32lx_flash; -extern const struct flash_driver stm32l4x_flash; -extern const struct flash_driver stm32h7x_flash; -extern const struct flash_driver stmqspi_flash; -extern const struct flash_driver stmsmi_flash; -extern const struct flash_driver str7x_flash; -extern const struct flash_driver str9x_flash; -extern const struct flash_driver str9xpec_flash; -extern const struct flash_driver swm050_flash; -extern const struct flash_driver tms470_flash; -extern const struct flash_driver vexriscv_nor_spi; -extern const struct flash_driver virtual_flash; -extern const struct flash_driver w600_flash; -extern const struct flash_driver xcf_flash; -extern const struct flash_driver xmc1xxx_flash; -extern const struct flash_driver xmc4xxx_flash; - /** * The list of built-in flash drivers. * @todo Make this dynamically extendable with loadable modules. @@ -121,7 +38,6 @@ static const struct flash_driver * const flash_drivers[] = { &fm3_flash, &fm4_flash, &fespi_flash, - &gd32vf103_flash, &jtagspi_flash, &kinetis_flash, &kinetis_ke_flash, @@ -146,6 +62,7 @@ static const struct flash_driver * const flash_drivers[] = { &psoc5lp_eeprom_flash, &psoc5lp_nvl_flash, &psoc6_flash, + &qn908x_flash, &renesas_rpchf_flash, &rp2040_flash, &sh_qspi_flash, @@ -168,6 +85,7 @@ static const struct flash_driver * const flash_drivers[] = { &xmc1xxx_flash, &xmc4xxx_flash, &w600_flash, + &rsl10_flash, NULL, }; diff --git a/src/flash/nor/dsp5680xx_flash.c b/src/flash/nor/dsp5680xx_flash.c index 5e8eec30fb..b1625f11f0 100644 --- a/src/flash/nor/dsp5680xx_flash.c +++ b/src/flash/nor/dsp5680xx_flash.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Rodrigo L. Rosa * * rodrigorosa.LG@gmail.com * @@ -6,19 +8,6 @@ * Kevin McGuire * * Marcel Wijlaars * * Michael Ashton * - * * - * 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/>. * ***************************************************************************/ /** @@ -45,14 +34,11 @@ static int dsp5680xx_build_sector_list(struct flash_bank *bank) { - uint32_t offset = HFM_FLASH_BASE_ADDR; - bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; ++i) { bank->sectors[i].offset = i * HFM_SECTOR_SIZE; bank->sectors[i].size = HFM_SECTOR_SIZE; - offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index 2c5a5020ee..f8e0886570 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -16,19 +18,6 @@ * * * Copyright (C) 2021 Doug Brunner * * doug.a.brunner@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -262,18 +251,6 @@ static int efm32x_read_info(struct flash_bank *bank) memset(efm32_info, 0, sizeof(struct efm32_info)); - const struct cortex_m_common *cortex_m = target_to_cm(bank->target); - - switch (cortex_m->core_info->partno) { - case CORTEX_M3_PARTNO: - case CORTEX_M4_PARTNO: - case CORTEX_M0P_PARTNO: - break; - default: - LOG_ERROR("Target is not Cortex-Mx Device"); - return ERROR_FAIL; - } - ret = efm32x_get_flash_size(bank, &(efm32_info->flash_sz_kib)); if (ret != ERROR_OK) return ret; @@ -1086,8 +1063,8 @@ static int efm32x_probe(struct flash_bank *bank) LOG_INFO("detected part: %s Gecko, rev %d", efm32_mcu_info->family_data->name, efm32_mcu_info->prod_rev); - LOG_INFO("flash size = %dkbytes", efm32_mcu_info->flash_sz_kib); - LOG_INFO("flash page size = %dbytes", efm32_mcu_info->page_size); + LOG_INFO("flash size = %d KiB", efm32_mcu_info->flash_sz_kib); + LOG_INFO("flash page size = %d B", efm32_mcu_info->page_size); assert(efm32_mcu_info->page_size != 0); diff --git a/src/flash/nor/em357.c b/src/flash/nor/em357.c index 705c1b3399..043494c789 100644 --- a/src/flash/nor/em357.c +++ b/src/flash/nor/em357.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * Copyright (C) 2011 by Erik Botö * erik.boto@pelagicore.com - * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -720,7 +709,7 @@ static int em357_probe(struct flash_bank *bank) em357_info->ppage_size = 4; - LOG_INFO("flash size = %dkbytes", num_pages*page_size/1024); + LOG_INFO("flash size = %d KiB", num_pages*page_size/1024); free(bank->sectors); diff --git a/src/flash/nor/esirisc_flash.c b/src/flash/nor/esirisc_flash.c index 23fd01e55a..938d0f6afa 100644 --- a/src/flash/nor/esirisc_flash.c +++ b/src/flash/nor/esirisc_flash.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * * James Zhao <hjz@squareup.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/faux.c b/src/flash/nor/faux.c index 7646e4b1d0..e76dc493fe 100644 --- a/src/flash/nor/faux.c +++ b/src/flash/nor/faux.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/fespi.c b/src/flash/nor/fespi.c index 5474ffae4b..9191764a96 100644 --- a/src/flash/nor/fespi.c +++ b/src/flash/nor/fespi.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> * * Modified by Megan Wachs <megan@sifive.com> from the original stmsmi.c * - * * - * 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/>. * ***************************************************************************/ /* The Freedom E SPI controller is a SPI bus controller @@ -523,6 +512,12 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer, } } + struct riscv_info *riscv = riscv_info(target); + if (!is_riscv(riscv)) { + LOG_ERROR("Unexpected target type"); + return ERROR_FAIL; + } + unsigned int xlen = riscv_xlen(target); struct working_area *algorithm_wa = NULL; struct working_area *data_wa = NULL; diff --git a/src/flash/nor/fm3.c b/src/flash/nor/fm3.c index 831f342571..48f4493ab6 100644 --- a/src/flash/nor/fm3.c +++ b/src/flash/nor/fm3.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Marc Willam, Holger Wech * * openOCD.fseu(AT)de.fujitsu.com * @@ -5,19 +7,6 @@ * * * Copyright (C) 2013 Nemui Trinomius * * nemuisan_kawausogasuki@live.jp * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/fm4.c b/src/flash/nor/fm4.c index 09865d2ab7..979ae84d01 100644 --- a/src/flash/nor/fm4.c +++ b/src/flash/nor/fm4.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Spansion FM4 flash * @@ -686,24 +688,8 @@ FLASH_BANK_COMMAND_HANDLER(fm4_flash_bank_command) return ret; } -static const struct command_registration fm4_exec_command_handlers[] = { - COMMAND_REGISTRATION_DONE -}; - -static const struct command_registration fm4_command_handlers[] = { - { - .name = "fm4", - .mode = COMMAND_ANY, - .help = "fm4 flash command group", - .usage = "", - .chain = fm4_exec_command_handlers, - }, - COMMAND_REGISTRATION_DONE -}; - const struct flash_driver fm4_flash = { .name = "fm4", - .commands = fm4_command_handlers, .flash_bank_command = fm4_flash_bank_command, .info = fm4_get_info_command, .probe = fm4_probe, diff --git a/src/flash/nor/imp.h b/src/flash/nor/imp.h index f66cf03293..199d6706ad 100644 --- a/src/flash/nor/imp.h +++ b/src/flash/nor/imp.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_IMP_H diff --git a/src/flash/nor/jtagspi.c b/src/flash/nor/jtagspi.c index a5672c63e9..4b975390be 100644 --- a/src/flash/nor/jtagspi.c +++ b/src/flash/nor/jtagspi.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2015 Robert Jordens <jordens@gmail.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -23,6 +12,7 @@ #include <jtag/jtag.h> #include <flash/nor/spi.h> #include <helper/time_support.h> +#include <pld/pld.h> #define JTAGSPI_MAX_TIMEOUT 3000 @@ -32,19 +22,44 @@ struct jtagspi_flash_bank { struct flash_device dev; char devname[32]; bool probed; - bool always_4byte; /* use always 4-byte address except for basic read 0x03 */ - uint32_t ir; - unsigned int addr_len; /* address length in bytes */ + bool always_4byte; /* use always 4-byte address except for basic read 0x03 */ + unsigned int addr_len; /* address length in bytes */ + struct pld_device *pld_device; /* if not NULL, the PLD has special instructions for JTAGSPI */ + uint32_t ir; /* when !pld_device, this instruction code is used in + jtagspi_set_user_ir to connect through a proxy bitstream */ }; FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command) { - struct jtagspi_flash_bank *info; - if (CMD_ARGC < 7) return ERROR_COMMAND_SYNTAX_ERROR; - info = malloc(sizeof(struct jtagspi_flash_bank)); + unsigned int ir = 0; + struct pld_device *device = NULL; + if (strcmp(CMD_ARGV[6], "-pld") == 0) { + if (CMD_ARGC < 8) + return ERROR_COMMAND_SYNTAX_ERROR; + device = get_pld_device_by_name_or_numstr(CMD_ARGV[7]); + if (device) { + bool has_jtagspi_instruction = false; + int retval = pld_has_jtagspi_instruction(device, &has_jtagspi_instruction); + if (retval != ERROR_OK) + return retval; + if (!has_jtagspi_instruction) { + retval = pld_get_jtagspi_userircode(device, &ir); + if (retval != ERROR_OK) + return retval; + device = NULL; + } + } else { + LOG_ERROR("pld device '#%s' is out of bounds or unknown", CMD_ARGV[7]); + return ERROR_FAIL; + } + } else { + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[6], ir); + } + + struct jtagspi_flash_bank *info = calloc(1, sizeof(struct jtagspi_flash_bank)); if (!info) { LOG_ERROR("no memory for flash bank info"); return ERROR_FAIL; @@ -52,20 +67,25 @@ FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command) bank->sectors = NULL; bank->driver_priv = info; - info->tap = NULL; + if (!bank->target->tap) { + LOG_ERROR("Target has no JTAG tap"); + return ERROR_FAIL; + } + info->tap = bank->target->tap; info->probed = false; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->ir); + + info->ir = ir; + info->pld_device = device; return ERROR_OK; } -static void jtagspi_set_ir(struct flash_bank *bank) +static void jtagspi_set_user_ir(struct jtagspi_flash_bank *info) { - struct jtagspi_flash_bank *info = bank->driver_priv; struct scan_field field; uint8_t buf[4] = { 0 }; - LOG_DEBUG("loading jtagspi ir"); + LOG_DEBUG("loading jtagspi ir(0x%" PRIx32 ")", info->ir); buf_set_u32(buf, 0, info->tap->ir_length, info->ir); field.num_bits = info->tap->ir_length; field.out_value = buf; @@ -86,6 +106,7 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd, assert(data_buffer || data_len == 0); struct scan_field fields[6]; + struct jtagspi_flash_bank *info = bank->driver_priv; LOG_DEBUG("cmd=0x%02x write_len=%d data_len=%d", cmd, write_len, data_len); @@ -94,22 +115,34 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd, if (is_read) data_len = -data_len; + unsigned int facing_read_bits = 0; + unsigned int trailing_write_bits = 0; + + if (info->pld_device) { + int retval = pld_get_jtagspi_stuff_bits(info->pld_device, &facing_read_bits, &trailing_write_bits); + if (retval != ERROR_OK) + return retval; + } + int n = 0; const uint8_t marker = 1; - fields[n].num_bits = 1; - fields[n].out_value = ▮ - fields[n].in_value = NULL; - n++; - - /* transfer length = cmd + address + read/write, - * -1 due to the counter implementation */ uint8_t xfer_bits[4]; - h_u32_to_be(xfer_bits, ((sizeof(cmd) + write_len + data_len) * CHAR_BIT) - 1); - flip_u8(xfer_bits, xfer_bits, sizeof(xfer_bits)); - fields[n].num_bits = sizeof(xfer_bits) * CHAR_BIT; - fields[n].out_value = xfer_bits; - fields[n].in_value = NULL; - n++; + if (!info->pld_device) { /* mode == JTAGSPI_MODE_PROXY_BITSTREAM */ + facing_read_bits = jtag_tap_count_enabled(); + fields[n].num_bits = 1; + fields[n].out_value = ▮ + fields[n].in_value = NULL; + n++; + + /* transfer length = cmd + address + read/write, + * -1 due to the counter implementation */ + h_u32_to_be(xfer_bits, ((sizeof(cmd) + write_len + data_len) * CHAR_BIT) - 1); + flip_u8(xfer_bits, xfer_bits, sizeof(xfer_bits)); + fields[n].num_bits = sizeof(xfer_bits) * CHAR_BIT; + fields[n].out_value = xfer_bits; + fields[n].in_value = NULL; + n++; + } flip_u8(&cmd, &cmd, sizeof(cmd)); fields[n].num_bits = sizeof(cmd) * CHAR_BIT; @@ -127,10 +160,12 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd, if (data_len > 0) { if (is_read) { - fields[n].num_bits = jtag_tap_count_enabled(); - fields[n].out_value = NULL; - fields[n].in_value = NULL; - n++; + if (facing_read_bits) { + fields[n].num_bits = facing_read_bits; + fields[n].out_value = NULL; + fields[n].in_value = NULL; + n++; + } fields[n].out_value = NULL; fields[n].in_value = data_buffer; @@ -142,16 +177,33 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd, fields[n].num_bits = data_len * CHAR_BIT; n++; } + if (!is_read && trailing_write_bits) { + fields[n].num_bits = trailing_write_bits; + fields[n].out_value = NULL; + fields[n].in_value = NULL; + n++; + } + + if (info->pld_device) { + int retval = pld_connect_spi_to_jtag(info->pld_device); + if (retval != ERROR_OK) + return retval; + } else { + jtagspi_set_user_ir(info); + } - jtagspi_set_ir(bank); /* passing from an IR scan to SHIFT-DR clears BYPASS registers */ - struct jtagspi_flash_bank *info = bank->driver_priv; jtag_add_dr_scan(info->tap, n, fields, TAP_IDLE); int retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; if (is_read) flip_u8(data_buffer, data_buffer, data_len); - return retval; + + if (info->pld_device) + return pld_disconnect_spi_from_jtag(info->pld_device); + return ERROR_OK; } COMMAND_HANDLER(jtagspi_handle_set) @@ -172,7 +224,12 @@ COMMAND_HANDLER(jtagspi_handle_set) return ERROR_COMMAND_SYNTAX_ERROR; } - retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + /* calling flash_command_get_bank without probing because handle_set is used + to set device parameters if not autodetected. So probing would fail + anyhow. + */ + retval = CALL_COMMAND_HANDLER(flash_command_get_bank_probe_optional, 0, + &bank, false); if (ERROR_OK != retval) return retval; info = bank->driver_priv; @@ -303,52 +360,50 @@ COMMAND_HANDLER(jtagspi_handle_set) COMMAND_HANDLER(jtagspi_handle_cmd) { struct flash_bank *bank; - unsigned int index = 1; - const int max = 21; - uint8_t num_write, num_read, write_buffer[max], read_buffer[1 << CHAR_BIT]; - uint8_t data, *ptr; - char temp[4], output[(2 + max + (1 << CHAR_BIT)) * 3 + 8]; - int retval; + const unsigned int max = 20; + uint8_t cmd_byte, num_read, write_buffer[max], read_buffer[1 << CHAR_BIT]; LOG_DEBUG("%s", __func__); - if (CMD_ARGC < 3) { - command_print(CMD, "jtagspi: not enough arguments"); + if (CMD_ARGC < 3) return ERROR_COMMAND_SYNTAX_ERROR; - } - num_write = CMD_ARGC - 2; + uint8_t num_write = CMD_ARGC - 3; if (num_write > max) { - LOG_ERROR("at most %d bytes may be send", max); - return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "at most %d bytes may be send", max); + return ERROR_COMMAND_ARGUMENT_INVALID; } - retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + /* calling flash_command_get_bank without probing because we like to be + able to send commands before auto-probing occurred. For example sending + "release from power down" is needed before probing when flash is in + power down mode. + */ + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank_probe_optional, 0, + &bank, false); + if (retval != ERROR_OK) return retval; - COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], num_read); + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], num_read); + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[2], cmd_byte); - snprintf(output, sizeof(output), "spi: "); - for (ptr = &write_buffer[0] ; index < CMD_ARGC; index++) { - COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index], data); - *ptr++ = data; - snprintf(temp, sizeof(temp), "%02" PRIx8 " ", data); - strncat(output, temp, sizeof(output) - strlen(output) - 1); - } - strncat(output, "-> ", sizeof(output) - strlen(output) - 1); + for (unsigned int i = 0; i < num_write; i++) + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[i + 3], write_buffer[i]); /* process command */ - ptr = &read_buffer[0]; - jtagspi_cmd(bank, write_buffer[0], &write_buffer[1], num_write - 1, ptr, -num_read); + retval = jtagspi_cmd(bank, cmd_byte, write_buffer, num_write, read_buffer, -num_read); if (retval != ERROR_OK) return retval; - for ( ; num_read > 0; num_read--) { - snprintf(temp, sizeof(temp), "%02" PRIx8 " ", *ptr++); - strncat(output, temp, sizeof(output) - strlen(output) - 1); - } - command_print(CMD, "%s", output); + command_print_sameline(CMD, "spi: %02" PRIx8, cmd_byte); + + for (unsigned int i = 0; i < num_write; i++) + command_print_sameline(CMD, " %02" PRIx8, write_buffer[i]); + + command_print_sameline(CMD, " ->"); + + for (unsigned int i = 0; i < num_read; i++) + command_print_sameline(CMD, " %02" PRIx8, read_buffer[i]); return ERROR_OK; } @@ -392,12 +447,6 @@ static int jtagspi_probe(struct flash_bank *bank) } info->probed = false; - if (!bank->target->tap) { - LOG_ERROR("Target has no JTAG tap"); - return ERROR_FAIL; - } - info->tap = bank->target->tap; - jtagspi_cmd(bank, SPIFLASH_READ_ID, NULL, 0, in_buf, -3); /* the table in spi.c has the manufacturer byte (first) as the lsb */ id = le_to_h_u24(in_buf); @@ -529,7 +578,7 @@ static int jtagspi_bulk_erase(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - jtagspi_cmd(bank, info->dev.chip_erase_cmd, NULL, 0, NULL, 0); + retval = jtagspi_cmd(bank, info->dev.chip_erase_cmd, NULL, 0, NULL, 0); if (retval != ERROR_OK) return retval; diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index edb4eb58fe..e8074e35bb 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * kesmtp@freenet.de * @@ -13,19 +15,6 @@ * * * Copyright (C) 2015 Tomas Vanek * * vanekt@fbl.cz * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -91,6 +80,7 @@ #define FLEXRAM 0x14000000 #define MSCM_OCMDR0 0x40001400 +#define MSCM_OCMDR1 0x40001404 #define FMC_PFB01CR 0x4001f004 #define FTFX_FSTAT 0x40020000 #define FTFX_FCNFG 0x40020001 @@ -108,6 +98,8 @@ #define SMC_PMSTAT 0x4007E003 #define SMC32_PMCTRL 0x4007E00C #define SMC32_PMSTAT 0x4007E014 +#define PMC_REGSC 0x4007D002 +#define MC_PMCTRL 0x4007E003 #define MCM_PLACR 0xF000300C /* Offsets */ @@ -199,6 +191,9 @@ #define KINETIS_K_SDID_K60_M150 0x000001C0 #define KINETIS_K_SDID_K70_M150 0x000001D0 +#define KINETIS_K_REVID_MASK 0x0000F000 +#define KINETIS_K_REVID_SHIFT 12 + #define KINETIS_SDID_SERIESID_MASK 0x00F00000 #define KINETIS_SDID_SERIESID_K 0x00000000 #define KINETIS_SDID_SERIESID_KL 0x00100000 @@ -236,6 +231,28 @@ #define KINETIS_SDID_PROJECTID_KE1XF 0x00000080 #define KINETIS_SDID_PROJECTID_KE1XZ 0x00000100 +/* The S32K series uses a different, incompatible SDID layout : + * Bit 31-28 : GENERATION + * Bit 27-24 : SUBSERIES + * Bit 23-20 : DERIVATE + * Bit 19-16 : RAMSIZE + * Bit 15-12 : REVID + * Bit 11-8 : PACKAGE + * Bit 7-0 : FEATURES + */ + +#define KINETIS_SDID_S32K_SERIES_MASK 0xFF000000 /* GENERATION + SUBSERIES */ +#define KINETIS_SDID_S32K_SERIES_K11X 0x11000000 +#define KINETIS_SDID_S32K_SERIES_K14X 0x14000000 + +#define KINETIS_SDID_S32K_DERIVATE_MASK 0x00F00000 +#define KINETIS_SDID_S32K_DERIVATE_KXX2 0x00200000 +#define KINETIS_SDID_S32K_DERIVATE_KXX3 0x00300000 +#define KINETIS_SDID_S32K_DERIVATE_KXX4 0x00400000 +#define KINETIS_SDID_S32K_DERIVATE_KXX5 0x00500000 +#define KINETIS_SDID_S32K_DERIVATE_KXX6 0x00600000 +#define KINETIS_SDID_S32K_DERIVATE_KXX8 0x00800000 + struct kinetis_flash_bank { struct kinetis_chip *k_chip; bool probed; @@ -281,6 +298,11 @@ struct kinetis_chip { uint32_t progr_accel_ram; uint32_t sim_base; + enum { + CT_KINETIS = 0, + CT_S32K, + } chip_type; + enum { FS_PROGRAM_SECTOR = 1, FS_PROGRAM_LONGWORD = 2, @@ -296,6 +318,7 @@ struct kinetis_chip { KINETIS_CACHE_K, /* invalidate using FMC->PFB0CR/PFB01CR */ KINETIS_CACHE_L, /* invalidate using MCM->PLACR */ KINETIS_CACHE_MSCM, /* devices like KE1xF, invalidate MSCM->OCMDR0 */ + KINETIS_CACHE_MSCM2, /* devices like S32K, invalidate MSCM->OCMDR0 and MSCM->OCMDR1 */ } cache_type; enum { @@ -309,6 +332,7 @@ struct kinetis_chip { enum { KINETIS_SMC, KINETIS_SMC32, + KINETIS_MC, } sysmodectrlr_type; char name[40]; @@ -397,21 +421,29 @@ const struct flash_driver kinetis_flash; static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count); static int kinetis_probe_chip(struct kinetis_chip *k_chip); +static int kinetis_probe_chip_s32k(struct kinetis_chip *k_chip); static int kinetis_auto_probe(struct flash_bank *bank); static int kinetis_mdm_write_register(struct adiv5_dap *dap, unsigned reg, uint32_t value) { - int retval; LOG_DEBUG("MDM_REG[0x%02x] <- %08" PRIX32, reg, value); - retval = dap_queue_ap_write(dap_ap(dap, MDM_AP), reg, value); + struct adiv5_ap *ap = dap_get_ap(dap, MDM_AP); + if (!ap) { + LOG_DEBUG("MDM: failed to get AP"); + return ERROR_FAIL; + } + + int retval = dap_queue_ap_write(ap, reg, value); if (retval != ERROR_OK) { LOG_DEBUG("MDM: failed to queue a write request"); + dap_put_ap(ap); return retval; } retval = dap_run(dap); + dap_put_ap(ap); if (retval != ERROR_OK) { LOG_DEBUG("MDM: dap_run failed"); return retval; @@ -423,15 +455,21 @@ static int kinetis_mdm_write_register(struct adiv5_dap *dap, unsigned reg, uint3 static int kinetis_mdm_read_register(struct adiv5_dap *dap, unsigned reg, uint32_t *result) { - int retval; + struct adiv5_ap *ap = dap_get_ap(dap, MDM_AP); + if (!ap) { + LOG_DEBUG("MDM: failed to get AP"); + return ERROR_FAIL; + } - retval = dap_queue_ap_read(dap_ap(dap, MDM_AP), reg, result); + int retval = dap_queue_ap_read(ap, reg, result); if (retval != ERROR_OK) { LOG_DEBUG("MDM: failed to queue a read request"); + dap_put_ap(ap); return retval; } retval = dap_run(dap); + dap_put_ap(ap); if (retval != ERROR_OK) { LOG_DEBUG("MDM: dap_run failed"); return retval; @@ -787,12 +825,18 @@ COMMAND_HANDLER(kinetis_check_flash_security_status) if ((val & (MDM_STAT_SYSSEC | MDM_STAT_FREADY)) != MDM_STAT_FREADY) { uint32_t stats[32]; + struct adiv5_ap *ap = dap_get_ap(dap, MDM_AP); + if (!ap) { + LOG_ERROR("MDM: failed to get AP"); + return ERROR_OK; + } for (unsigned int i = 0; i < 32; i++) { stats[i] = MDM_STAT_FREADY; - dap_queue_ap_read(dap_ap(dap, MDM_AP), MDM_REG_STAT, &stats[i]); + dap_queue_ap_read(ap, MDM_REG_STAT, &stats[i]); } retval = dap_run(dap); + dap_put_ap(ap); if (retval != ERROR_OK) { LOG_DEBUG("MDM: dap_run failed when validating secured state"); return ERROR_OK; @@ -863,6 +907,8 @@ static int kinetis_chip_options(struct kinetis_chip *k_chip, int argc, const cha if (strcmp(argv[i], "-sim-base") == 0) { if (i + 1 < argc) k_chip->sim_base = strtoul(argv[++i], NULL, 0); + } else if (strcmp(argv[i], "-s32k") == 0) { + k_chip->chip_type = CT_S32K; } else LOG_ERROR("Unsupported flash bank option %s", argv[i]); } @@ -934,7 +980,7 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) unsigned num_blocks; struct kinetis_flash_bank *k_bank; struct flash_bank *bank; - char base_name[69], name[80], num[4]; + char base_name[69], name[87], num[11]; char *class, *p; num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks; @@ -1126,7 +1172,13 @@ static int kinetis_disable_wdog(struct kinetis_chip *k_chip) int retval; if (!k_chip->probed) { - retval = kinetis_probe_chip(k_chip); + switch (k_chip->chip_type) { + case CT_S32K: + retval = kinetis_probe_chip_s32k(k_chip); + break; + default: + retval = kinetis_probe_chip(k_chip); + } if (retval != ERROR_OK) return retval; } @@ -1529,6 +1581,17 @@ static int kinetis_read_pmstat(struct kinetis_chip *k_chip, uint8_t *pmstat) if (result == ERROR_OK) *pmstat = stat32 & 0xff; return result; + + case KINETIS_MC: + /* emulate SMC by reading PMC_REGSC bit 3 (VLPRS) */ + result = target_read_u8(target, PMC_REGSC, pmstat); + if (result == ERROR_OK) { + if (*pmstat & 0x08) + *pmstat = PM_STAT_VLPR; + else + *pmstat = PM_STAT_RUN; + } + return result; } return ERROR_FAIL; } @@ -1569,6 +1632,10 @@ static int kinetis_check_run_mode(struct kinetis_chip *k_chip) case KINETIS_SMC32: result = target_write_u32(target, SMC32_PMCTRL, PM_CTRL_RUNM_RUN); break; + + case KINETIS_MC: + result = target_write_u32(target, MC_PMCTRL, PM_CTRL_RUNM_RUN); + break; } if (result != ERROR_OK) return result; @@ -1610,6 +1677,12 @@ static void kinetis_invalidate_flash_cache(struct kinetis_chip *k_chip) /* disable data prefetch and flash speculate */ break; + case KINETIS_CACHE_MSCM2: + target_write_u32(target, MSCM_OCMDR0, 0x30); + target_write_u32(target, MSCM_OCMDR1, 0x30); + /* disable data prefetch and flash speculate */ + break; + default: break; } @@ -2019,6 +2092,174 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer, } +static int kinetis_probe_chip_s32k(struct kinetis_chip *k_chip) +{ + int result; + uint8_t fcfg1_eesize, fcfg1_depart; + uint32_t ee_size = 0; + uint32_t pflash_size_k, nvm_size_k, dflash_size_k; + unsigned int generation = 0, subseries = 0, derivate = 0; + + struct target *target = k_chip->target; + k_chip->probed = false; + k_chip->pflash_sector_size = 0; + k_chip->pflash_base = 0; + k_chip->nvm_base = 0x10000000; + k_chip->progr_accel_ram = FLEXRAM; + k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; + k_chip->watchdog_type = KINETIS_WDOG32_KE1X; + + if (k_chip->sim_base == 0) + k_chip->sim_base = SIM_BASE; + + result = target_read_u32(target, k_chip->sim_base + SIM_SDID_OFFSET, &k_chip->sim_sdid); + if (result != ERROR_OK) + return result; + + generation = (k_chip->sim_sdid) >> 28 & 0x0f; + subseries = (k_chip->sim_sdid) >> 24 & 0x0f; + derivate = (k_chip->sim_sdid) >> 20 & 0x0f; + + switch (k_chip->sim_sdid & KINETIS_SDID_S32K_SERIES_MASK) { + case KINETIS_SDID_S32K_SERIES_K11X: + k_chip->cache_type = KINETIS_CACHE_L; + k_chip->num_pflash_blocks = 1; + k_chip->num_nvm_blocks = 1; + /* Non-interleaved */ + k_chip->max_flash_prog_size = 512; + + switch (k_chip->sim_sdid & KINETIS_SDID_S32K_DERIVATE_MASK) { + case KINETIS_SDID_S32K_DERIVATE_KXX6: + /* S32K116 CPU 48Mhz Flash 128KB RAM 17KB+2KB */ + /* Non-Interleaved */ + k_chip->pflash_size = 128 << 10; + k_chip->pflash_sector_size = 2 << 10; + /* Non-Interleaved */ + k_chip->nvm_size = 32 << 10; + k_chip->nvm_sector_size = 2 << 10; + break; + case KINETIS_SDID_S32K_DERIVATE_KXX8: + /* S32K118 CPU 80Mhz Flash 256KB+32KB RAM 32KB+4KB */ + /* Non-Interleaved */ + k_chip->pflash_size = 256 << 10; + k_chip->pflash_sector_size = 2 << 10; + /* Non-Interleaved */ + k_chip->nvm_size = 32 << 10; + k_chip->nvm_sector_size = 2 << 10; + break; + } + break; + + case KINETIS_SDID_S32K_SERIES_K14X: + k_chip->cache_type = KINETIS_CACHE_MSCM2; + k_chip->num_pflash_blocks = 1; + k_chip->num_nvm_blocks = 1; + /* Non-interleaved */ + k_chip->max_flash_prog_size = 512; + switch (k_chip->sim_sdid & KINETIS_SDID_S32K_DERIVATE_MASK) { + case KINETIS_SDID_S32K_DERIVATE_KXX2: + case KINETIS_SDID_S32K_DERIVATE_KXX3: + /* S32K142/S32K142W CPU 80Mhz Flash 256KB+64KB RAM 32KB+4KB */ + /* Non-Interleaved */ + k_chip->pflash_size = 256 << 10; + k_chip->pflash_sector_size = 2 << 10; + /* Non-Interleaved */ + k_chip->nvm_size = 64 << 10; + k_chip->nvm_sector_size = 2 << 10; + break; + case KINETIS_SDID_S32K_DERIVATE_KXX4: + case KINETIS_SDID_S32K_DERIVATE_KXX5: + /* S32K144/S32K144W CPU 80Mhz Flash 512KB+64KB RAM 64KB+4KB */ + /* Interleaved */ + k_chip->pflash_size = 512 << 10; + k_chip->pflash_sector_size = 4 << 10; + /* Non-Interleaved */ + k_chip->nvm_size = 64 << 10; + k_chip->nvm_sector_size = 2 << 10; + break; + case KINETIS_SDID_S32K_DERIVATE_KXX6: + /* S32K146 CPU 80Mhz Flash 1024KB+64KB RAM 128KB+4KB */ + /* Interleaved */ + k_chip->pflash_size = 1024 << 10; + k_chip->pflash_sector_size = 4 << 10; + k_chip->num_pflash_blocks = 2; + /* Non-Interleaved */ + k_chip->nvm_size = 64 << 10; + k_chip->nvm_sector_size = 2 << 10; + break; + case KINETIS_SDID_S32K_DERIVATE_KXX8: + /* S32K148 CPU 80Mhz Flash 1536KB+512KB RAM 256KB+4KB */ + /* Interleaved */ + k_chip->pflash_size = 1536 << 10; + k_chip->pflash_sector_size = 4 << 10; + k_chip->num_pflash_blocks = 3; + /* Interleaved */ + k_chip->nvm_size = 512 << 10; + k_chip->nvm_sector_size = 4 << 10; + /* Interleaved */ + k_chip->max_flash_prog_size = 1 << 10; + break; + } + break; + + default: + LOG_ERROR("Unsupported S32K1xx-series"); + } + + if (k_chip->pflash_sector_size == 0) { + LOG_ERROR("MCU is unsupported, SDID 0x%08" PRIx32, k_chip->sim_sdid); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + + result = target_read_u32(target, k_chip->sim_base + SIM_FCFG1_OFFSET, &k_chip->sim_fcfg1); + if (result != ERROR_OK) + return result; + k_chip->sim_fcfg2 = 0; /* S32K1xx does not implement FCFG2 register. */ + + fcfg1_depart = (k_chip->sim_fcfg1 >> 12) & 0x0f; + fcfg1_eesize = (k_chip->sim_fcfg1 >> 16) & 0x0f; + if (fcfg1_eesize <= 9) + ee_size = (16 << (10 - fcfg1_eesize)); + if ((fcfg1_depart & 0x8) == 0) { + /* Binary 0xxx values encode the amount reserved for EEPROM emulation. */ + if (fcfg1_depart) + k_chip->dflash_size = k_chip->nvm_size - (4096 << fcfg1_depart); + else + k_chip->dflash_size = k_chip->nvm_size; + } else { + /* Binary 1xxx valued encode the DFlash size. */ + if (fcfg1_depart & 0x7) + k_chip->dflash_size = 4096 << (fcfg1_depart & 0x7); + else + k_chip->dflash_size = 0; + } + + snprintf(k_chip->name, sizeof(k_chip->name), "S32K%u%u%u", + generation, subseries, derivate); + + pflash_size_k = k_chip->pflash_size / 1024; + dflash_size_k = k_chip->dflash_size / 1024; + + LOG_INFO("%s detected: %u flash blocks", k_chip->name, k_chip->num_pflash_blocks + k_chip->num_nvm_blocks); + LOG_INFO("%u PFlash banks: %" PRIu32 " KiB total", k_chip->num_pflash_blocks, pflash_size_k); + + nvm_size_k = k_chip->nvm_size / 1024; + + if (k_chip->num_nvm_blocks) { + LOG_INFO("%u FlexNVM banks: %" PRIu32 " KiB total, %" PRIu32 " KiB available as data flash, %" + PRIu32 " bytes FlexRAM", + k_chip->num_nvm_blocks, nvm_size_k, dflash_size_k, ee_size); + } + + k_chip->probed = true; + + if (create_banks) + kinetis_create_missing_banks(k_chip); + + return ERROR_OK; +} + + static int kinetis_probe_chip(struct kinetis_chip *k_chip) { int result; @@ -2135,6 +2376,24 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) } } + /* first revision of some devices has no SMC */ + switch (mcu_type) { + case KINETIS_K_SDID_K10_M100: + case KINETIS_K_SDID_K20_M100: + case KINETIS_K_SDID_K30_M100: + case KINETIS_K_SDID_K40_M100: + case KINETIS_K_SDID_K60_M100: + { + uint32_t revid = (k_chip->sim_sdid & KINETIS_K_REVID_MASK) >> KINETIS_K_REVID_SHIFT; + /* highest bit set corresponds to rev 2.x */ + if (revid <= 7) { + k_chip->sysmodectrlr_type = KINETIS_MC; + strcat(name, " Rev 1.x"); + } + } + break; + } + } else { /* Newer K-series or KL series MCU */ familyid = (k_chip->sim_sdid & KINETIS_SDID_FAMILYID_MASK) >> KINETIS_SDID_FAMILYID_SHIFT; @@ -2615,12 +2874,12 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) snprintf(k_chip->name, sizeof(k_chip->name), name, flash_marking); LOG_INFO("Kinetis %s detected: %u flash blocks", k_chip->name, num_blocks); - LOG_INFO("%u PFlash banks: %" PRIu32 "k total", k_chip->num_pflash_blocks, pflash_size_k); + LOG_INFO("%u PFlash banks: %" PRIu32 " KiB total", k_chip->num_pflash_blocks, pflash_size_k); if (k_chip->num_nvm_blocks) { nvm_size_k = k_chip->nvm_size / 1024; dflash_size_k = k_chip->dflash_size / 1024; - LOG_INFO("%u FlexNVM banks: %" PRIu32 "k total, %" PRIu32 "k available as data flash, %" PRIu32 "bytes FlexRAM", - k_chip->num_nvm_blocks, nvm_size_k, dflash_size_k, ee_size); + LOG_INFO("%u FlexNVM banks: %" PRIu32 " KiB total, %" PRIu32 " KiB available as data flash, %" + PRIu32 " bytes FlexRAM", k_chip->num_nvm_blocks, nvm_size_k, dflash_size_k, ee_size); } k_chip->probed = true; @@ -2646,7 +2905,13 @@ static int kinetis_probe(struct flash_bank *bank) k_bank->probed = false; if (!k_chip->probed) { - result = kinetis_probe_chip(k_chip); + switch (k_chip->chip_type) { + case CT_S32K: + result = kinetis_probe_chip_s32k(k_chip); + break; + default: + result = kinetis_probe_chip(k_chip); + } if (result != ERROR_OK) return result; } @@ -2718,23 +2983,26 @@ static int kinetis_probe(struct flash_bank *bank) return ERROR_FLASH_BANK_INVALID; } - fcfg2_pflsh = (uint8_t)((k_chip->sim_fcfg2 >> 23) & 0x01); - fcfg2_maxaddr0 = (uint8_t)((k_chip->sim_fcfg2 >> 24) & 0x7f); - fcfg2_maxaddr1 = (uint8_t)((k_chip->sim_fcfg2 >> 16) & 0x7f); + /* S32K1xx does not implement FCFG2 register. Skip checks. */ + if (k_chip->chip_type != CT_S32K) { + fcfg2_pflsh = (uint8_t)((k_chip->sim_fcfg2 >> 23) & 0x01); + fcfg2_maxaddr0 = (uint8_t)((k_chip->sim_fcfg2 >> 24) & 0x7f); + fcfg2_maxaddr1 = (uint8_t)((k_chip->sim_fcfg2 >> 16) & 0x7f); - if (k_bank->bank_number == 0 && k_chip->fcfg2_maxaddr0_shifted != bank->size) - LOG_WARNING("MAXADDR0 0x%02" PRIx8 " check failed," - " please report to OpenOCD mailing list", fcfg2_maxaddr0); + if (k_bank->bank_number == 0 && k_chip->fcfg2_maxaddr0_shifted != bank->size) + LOG_WARNING("MAXADDR0 0x%02" PRIx8 " check failed," + " please report to OpenOCD mailing list", fcfg2_maxaddr0); - if (fcfg2_pflsh) { - if (k_bank->bank_number == 1 && k_chip->fcfg2_maxaddr1_shifted != bank->size) - LOG_WARNING("MAXADDR1 0x%02" PRIx8 " check failed," - " please report to OpenOCD mailing list", fcfg2_maxaddr1); - } else { - if (k_bank->bank_number == first_nvm_bank - && k_chip->fcfg2_maxaddr1_shifted != k_chip->dflash_size) - LOG_WARNING("FlexNVM MAXADDR1 0x%02" PRIx8 " check failed," - " please report to OpenOCD mailing list", fcfg2_maxaddr1); + if (fcfg2_pflsh) { + if (k_bank->bank_number == 1 && k_chip->fcfg2_maxaddr1_shifted != bank->size) + LOG_WARNING("MAXADDR1 0x%02" PRIx8 " check failed," + " please report to OpenOCD mailing list", fcfg2_maxaddr1); + } else { + if (k_bank->bank_number == first_nvm_bank + && k_chip->fcfg2_maxaddr1_shifted != k_chip->dflash_size) + LOG_WARNING("FlexNVM MAXADDR1 0x%02" PRIx8 " check failed," + " please report to OpenOCD mailing list", fcfg2_maxaddr1); + } } free(bank->sectors); @@ -2885,6 +3153,11 @@ COMMAND_HANDLER(kinetis_nvm_partition) k_chip = kinetis_get_chip(target); + if (k_chip->chip_type == CT_S32K) { + LOG_ERROR("NVM partition not supported on S32K1xx (yet)."); + return ERROR_FAIL; + } + if (CMD_ARGC >= 2) { if (strcmp(CMD_ARGV[0], "dataflash") == 0) sz_type = DF_SIZE; diff --git a/src/flash/nor/kinetis_ke.c b/src/flash/nor/kinetis_ke.c index 48749e617d..c069f3ac89 100644 --- a/src/flash/nor/kinetis_ke.c +++ b/src/flash/nor/kinetis_ke.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2015 by Ivan Meleca * * ivan@artekit.eu * @@ -18,19 +20,6 @@ * * * Copyright (C) 2015 Tomas Vanek * * vanekt@fbl.cz * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -147,16 +136,23 @@ struct kinetis_ke_flash_bank { static int kinetis_ke_mdm_write_register(struct adiv5_dap *dap, unsigned reg, uint32_t value) { - int retval; LOG_DEBUG("MDM_REG[0x%02x] <- %08" PRIX32, reg, value); - retval = dap_queue_ap_write(dap_ap(dap, 1), reg, value); + struct adiv5_ap *ap = dap_get_ap(dap, 1); + if (!ap) { + LOG_DEBUG("MDM: failed to get AP"); + return ERROR_FAIL; + } + + int retval = dap_queue_ap_write(ap, reg, value); if (retval != ERROR_OK) { LOG_DEBUG("MDM: failed to queue a write request"); + dap_put_ap(ap); return retval; } retval = dap_run(dap); + dap_put_ap(ap); if (retval != ERROR_OK) { LOG_DEBUG("MDM: dap_run failed"); return retval; @@ -167,14 +163,21 @@ static int kinetis_ke_mdm_write_register(struct adiv5_dap *dap, unsigned reg, ui static int kinetis_ke_mdm_read_register(struct adiv5_dap *dap, unsigned reg, uint32_t *result) { - int retval; - retval = dap_queue_ap_read(dap_ap(dap, 1), reg, result); + struct adiv5_ap *ap = dap_get_ap(dap, 1); + if (!ap) { + LOG_DEBUG("MDM: failed to get AP"); + return ERROR_FAIL; + } + + int retval = dap_queue_ap_read(ap, reg, result); if (retval != ERROR_OK) { LOG_DEBUG("MDM: failed to queue a read request"); + dap_put_ap(ap); return retval; } retval = dap_run(dap); + dap_put_ap(ap); if (retval != ERROR_OK) { LOG_DEBUG("MDM: dap_run failed"); return retval; diff --git a/src/flash/nor/lpc2000.c b/src/flash/nor/lpc2000.c index 465199d798..f12eef7e4c 100644 --- a/src/flash/nor/lpc2000.c +++ b/src/flash/nor/lpc2000.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -14,19 +16,6 @@ * * * LPC8N04/HNS31xx support Copyright (C) 2018 * * by Jean-Christian de Rivaz jcdr [at] innodelec [dot] ch * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/lpc288x.c b/src/flash/nor/lpc288x.c index 1c10e50157..3006db1cbf 100644 --- a/src/flash/nor/lpc288x.c +++ b/src/flash/nor/lpc288x.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2008 by * * Karl RobinSod <karl.robinsod@gmail.com> * - * * - * 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/>. * ***************************************************************************/ /*************************************************************************** diff --git a/src/flash/nor/lpc2900.c b/src/flash/nor/lpc2900.c index 4bf52974b6..948def9829 100644 --- a/src/flash/nor/lpc2900.c +++ b/src/flash/nor/lpc2900.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 by * * Rolf Meeser <rolfm_9dq@yahoo.de> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -1143,9 +1132,9 @@ static int lpc2900_write(struct flash_bank *bank, const uint8_t *buffer, * reduced size if that fails. */ struct working_area *warea; uint32_t buffer_size = lpc2900_info->max_ram_block - 1 * KiB; - while ((retval = target_alloc_working_area_try(target, + while (target_alloc_working_area_try(target, buffer_size + target_code_size, - &warea)) != ERROR_OK) { + &warea) != ERROR_OK) { /* Try a smaller buffer now, and stop if it's too small. */ buffer_size -= 1 * KiB; if (buffer_size < 2 * KiB) { diff --git a/src/flash/nor/lpcspifi.c b/src/flash/nor/lpcspifi.c index 160e2dc674..f950f21db7 100644 --- a/src/flash/nor/lpcspifi.c +++ b/src/flash/nor/lpcspifi.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2012 by George Harris * * george@luminairecoffee.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/max32xxx.c b/src/flash/nor/max32xxx.c index e7a690d3a5..51d6ae271a 100644 --- a/src/flash/nor/max32xxx.c +++ b/src/flash/nor/max32xxx.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2016 by Maxim Integrated * * Kevin Gillespie <kevin.gillespie@maximintegrated.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/mdr.c b/src/flash/nor/mdr.c index f3c85525a1..f6285de5b8 100644 --- a/src/flash/nor/mdr.c +++ b/src/flash/nor/mdr.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -10,19 +12,6 @@ * * * Copyright (C) 2013 by Paul Fertser * * fercerpav@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/mrvlqspi.c b/src/flash/nor/mrvlqspi.c index a752f0943c..4eb6522bea 100644 --- a/src/flash/nor/mrvlqspi.c +++ b/src/flash/nor/mrvlqspi.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2014 by Mahavir Jain <mjain@marvell.com> * - * * - * 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/>. * ***************************************************************************/ /* diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c index 61741c8d68..5e2935d02b 100644 --- a/src/flash/nor/msp432.c +++ b/src/flash/nor/msp432.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2018 by Texas Instruments, Inc. * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -56,6 +45,21 @@ struct msp432_bank { struct armv7m_algorithm armv7m_info; }; +/* Flash helper algorithm for MSP432P401x targets */ +static const uint8_t msp432p401x_algo[] = { +#include "../../../contrib/loaders/flash/msp432/msp432p401x_algo.inc" +}; + +/* Flash helper algorithm for MSP432P411x targets */ +static const uint8_t msp432p411x_algo[] = { +#include "../../../contrib/loaders/flash/msp432/msp432p411x_algo.inc" +}; + +/* Flash helper algorithm for MSP432E4x targets */ +static const uint8_t msp432e4x_algo[] = { +#include "../../../contrib/loaders/flash/msp432/msp432e4x_algo.inc" +}; + static int msp432_auto_probe(struct flash_bank *bank); static int msp432_device_type(uint32_t family_type, uint32_t device_id, @@ -371,7 +375,7 @@ static int msp432_init(struct flash_bank *bank) buf_set_u32(reg_params[0].value, 0, 32, ALGO_STACK_POINTER_ADDR); /* Begin executing the flash helper algorithm */ - retval = target_start_algorithm(target, 0, 0, 1, reg_params, + retval = target_start_algorithm(target, 0, NULL, 1, reg_params, algo_entry_addr, 0, &msp432_bank->armv7m_info); destroy_reg_param(®_params[0]); if (retval != ERROR_OK) { diff --git a/src/flash/nor/msp432.h b/src/flash/nor/msp432.h index af1d40c3c3..d0a62c4884 100644 --- a/src/flash/nor/msp432.h +++ b/src/flash/nor/msp432.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2018 by Texas Instruments, Inc. * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_MSP432_H @@ -112,19 +101,4 @@ struct msp432_algo_params { uint8_t unlock_bsl[4]; }; -/* Flash helper algorithm for MSP432P401x targets */ -const uint8_t msp432p401x_algo[] = { -#include "../../../contrib/loaders/flash/msp432/msp432p401x_algo.inc" -}; - -/* Flash helper algorithm for MSP432P411x targets */ -const uint8_t msp432p411x_algo[] = { -#include "../../../contrib/loaders/flash/msp432/msp432p411x_algo.inc" -}; - -/* Flash helper algorithm for MSP432E4x targets */ -const uint8_t msp432e4x_algo[] = { -#include "../../../contrib/loaders/flash/msp432/msp432e4x_algo.inc" -}; - #endif /* OPENOCD_FLASH_NOR_MSP432_H */ diff --git a/src/flash/nor/niietcm4.c b/src/flash/nor/niietcm4.c index 6f9a5d378e..0c36e2c96d 100644 --- a/src/flash/nor/niietcm4.c +++ b/src/flash/nor/niietcm4.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2015 by Bogdan Kolbov * * kolbov@niiet.ru * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/non_cfi.c b/src/flash/nor/non_cfi.c index 1566f38582..f096ba69c3 100644 --- a/src/flash/nor/non_cfi.c +++ b/src/flash/nor/non_cfi.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2009 Michael Schwingen * * michael@schwingen.org * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/non_cfi.h b/src/flash/nor/non_cfi.h index c411cb8852..47d7e59f6f 100644 --- a/src/flash/nor/non_cfi.h +++ b/src/flash/nor/non_cfi.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_NON_CFI_H diff --git a/src/flash/nor/npcx.c b/src/flash/nor/npcx.c index a4d639524b..8309630d7c 100644 --- a/src/flash/nor/npcx.c +++ b/src/flash/nor/npcx.c @@ -1,9 +1,10 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2020 by Nuvoton Technology Corporation * Mulin Chao <mlchao@nuvoton.com> * Wealian Liao <WHLIAO@nuvoton.com> + * Luca Hung <YCHUNG0@nuvoton.com> */ #ifdef HAVE_CONFIG_H @@ -17,12 +18,11 @@ #include "../../../contrib/loaders/flash/npcx/npcx_flash.h" /* NPCX flash loader */ -const uint8_t npcx_algo[] = { +static const uint8_t npcx_algo[] = { #include "../../../contrib/loaders/flash/npcx/npcx_algo.inc" }; #define NPCX_FLASH_TIMEOUT_MS 8000 -#define NPCX_FLASH_BASE_ADDR 0x64000000 /* flash list */ enum npcx_flash_device_index { @@ -33,7 +33,6 @@ enum npcx_flash_device_index { }; struct npcx_flash_bank { - const char *family_name; uint32_t sector_length; bool probed; enum npcx_flash_device_index flash; @@ -44,6 +43,7 @@ struct npcx_flash_bank { uint32_t algo_working_size; uint32_t buffer_addr; uint32_t params_addr; + uint32_t fiu_ver; }; struct npcx_flash_info { @@ -90,7 +90,7 @@ static int npcx_init(struct flash_bank *bank) /* Confirm the defined working address is the area we need to use */ if (npcx_bank->working_area->address != NPCX_FLASH_LOADER_WORKING_ADDR) { - LOG_ERROR("%s: Invalid working address", npcx_bank->family_name); + LOG_TARGET_ERROR(target, "Invalid working address"); LOG_INFO("Hint: Use '-work-area-phys 0x%" PRIx32 "' in your target configuration", NPCX_FLASH_LOADER_WORKING_ADDR); target_free_working_area(target, npcx_bank->working_area); @@ -102,8 +102,7 @@ static int npcx_init(struct flash_bank *bank) retval = target_write_buffer(target, NPCX_FLASH_LOADER_PROGRAM_ADDR, npcx_bank->algo_size, npcx_bank->algo_code); if (retval != ERROR_OK) { - LOG_ERROR("%s: Failed to load flash helper algorithm", - npcx_bank->family_name); + LOG_TARGET_ERROR(target, "Failed to load flash helper algorithm"); target_free_working_area(target, npcx_bank->working_area); npcx_bank->working_area = NULL; return retval; @@ -118,8 +117,7 @@ static int npcx_init(struct flash_bank *bank) NPCX_FLASH_LOADER_PROGRAM_ADDR, 0, &npcx_bank->armv7m_info); if (retval != ERROR_OK) { - LOG_ERROR("%s: Failed to start flash helper algorithm", - npcx_bank->family_name); + LOG_TARGET_ERROR(target, "Failed to start flash helper algorithm"); target_free_working_area(target, npcx_bank->working_area); npcx_bank->working_area = NULL; return retval; @@ -154,7 +152,6 @@ static int npcx_quit(struct flash_bank *bank) static int npcx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr) { struct target *target = bank->target; - struct npcx_flash_bank *npcx_bank = bank->driver_priv; uint32_t status_addr = params_addr + offsetof(struct npcx_flash_params, sync); uint32_t status; int64_t start_ms = timeval_ms(); @@ -172,9 +169,7 @@ static int npcx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr) } while (status == NPCX_FLASH_LOADER_EXECUTE); if (status != NPCX_FLASH_LOADER_WAIT) { - LOG_ERROR("%s: Flash operation failed, status=0x%" PRIx32, - npcx_bank->family_name, - status); + LOG_TARGET_ERROR(target, "Flash operation failed, status (%0x" PRIX32 ") ", status); return ERROR_FAIL; } @@ -197,6 +192,7 @@ static enum npcx_flash_device_index npcx_get_flash_id(struct flash_bank *bank, u return retval; /* Set up algorithm parameters for get flash ID command */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.fiu_ver, npcx_bank->fiu_ver); target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_GET_FLASH_ID); target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT); @@ -250,6 +246,7 @@ static int npcx_probe(struct flash_bank *bank) npcx_bank->buffer_addr = NPCX_FLASH_LOADER_BUFFER_ADDR; npcx_bank->params_addr = NPCX_FLASH_LOADER_PARAMS_ADDR; + int retval = npcx_get_flash_id(bank, &flash_id); if (retval != ERROR_OK) return retval; @@ -264,7 +261,6 @@ static int npcx_probe(struct flash_bank *bank) return ERROR_FAIL; } - bank->base = NPCX_FLASH_BASE_ADDR; bank->num_sectors = num_sectors; bank->size = num_sectors * sector_length; bank->write_start_alignment = 0; @@ -300,7 +296,7 @@ FLASH_BANK_COMMAND_HANDLER(npcx_flash_bank_command) { struct npcx_flash_bank *npcx_bank; - if (CMD_ARGC < 6) + if (CMD_ARGC < 6 || CMD_ARGC > 7) return ERROR_COMMAND_SYNTAX_ERROR; npcx_bank = calloc(1, sizeof(struct npcx_flash_bank)); @@ -309,13 +305,32 @@ FLASH_BANK_COMMAND_HANDLER(npcx_flash_bank_command) return ERROR_FAIL; } + const char *fiu; + if (CMD_ARGC == 6) { + LOG_WARNING("No FIU is selection, using default."); + npcx_bank->fiu_ver = NPCX_FIU_NPCX; + } + + if (CMD_ARGC == 7) { + fiu = CMD_ARGV[6]; + if (strcmp(fiu, "npcx.fiu") == 0) { + npcx_bank->fiu_ver = NPCX_FIU_NPCX; + } else if (strcmp(fiu, "npcx_v2.fiu") == 0) { + npcx_bank->fiu_ver = NPCX_FIU_NPCX_V2; + } else if (strcmp(fiu, "npck.fiu") == 0) { + npcx_bank->fiu_ver = NPCX_FIU_NPCK; + } else { + LOG_ERROR("%s is not a valid fiu", fiu); + free(npcx_bank); + return ERROR_TARGET_INVALID; + } + } + /* Initialize private flash information */ - npcx_bank->family_name = "npcx"; npcx_bank->sector_length = NPCX_FLASH_ERASE_SIZE; /* Finish initialization of bank */ bank->driver_priv = npcx_bank; - bank->next = NULL; return ERROR_OK; } @@ -341,6 +356,7 @@ static int npcx_chip_erase(struct flash_bank *bank) return retval; /* Set up algorithm parameters for chip erase command */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.fiu_ver, npcx_bank->fiu_ver); target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_ERASE_ALL); target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT); @@ -397,6 +413,7 @@ static int npcx_erase(struct flash_bank *bank, unsigned int first, return retval; /* Set up algorithm parameters for erase command */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.fiu_ver, npcx_bank->fiu_ver); target_buffer_set_u32(target, (uint8_t *)&algo_params.addr, address); target_buffer_set_u32(target, (uint8_t *)&algo_params.len, length); target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, NPCX_FLASH_CMD_ERASE_SECTORS); @@ -464,6 +481,7 @@ static int npcx_write(struct flash_bank *bank, const uint8_t *buffer, } /* Update algo parameters for flash write */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.fiu_ver, npcx_bank->fiu_ver); target_buffer_set_u32(target, (uint8_t *)&algo_params.addr, address); target_buffer_set_u32(target, (uint8_t *)&algo_params.len, size); target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, NPCX_FLASH_LOADER_WAIT); @@ -502,7 +520,7 @@ static int npcx_info(struct flash_bank *bank, struct command_invocation *cmd) struct npcx_flash_bank *npcx_bank = bank->driver_priv; command_print_sameline(cmd, "%s flash: %s\n", - npcx_bank->family_name, + target_name(bank->target), flash_info[npcx_bank->flash].name); return ERROR_OK; diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index c96415547b..d5de4a4644 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2013 Synapse Product Development * * Andrey Smirnov <andrew.smironv@gmail.com> * * Angus Gratton <gus@projectgus.com> * * Erdem U. Altunyurt <spamjunkeater@gmail.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -147,7 +136,7 @@ struct nrf5_device_spec { }; struct nrf5_info { - uint32_t refcount; + unsigned int refcount; struct nrf5_bank { struct nrf5_info *chip; diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c index cb7c1df836..a0c6e0c815 100644 --- a/src/flash/nor/numicro.c +++ b/src/flash/nor/numicro.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by James K. Larson * * jlarson@pacifier.com * @@ -11,18 +13,11 @@ * Copyright (C) 2015 Nemui Trinomius * * nemuisan_kawausogasuki@live.jp * * * - * 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. * + * Copyright (C) 2017 Zale Yu * + * CYYU@nuvoton.com * * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * + * Copyright (C) 2022 Jian-Hong Pan * + * chienhung.pan@gmail.com * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -125,1008 +120,412 @@ struct numicro_cpu_type { struct numicro_flash_bank_type bank[NUMICRO_MAX_FLASH_BANKS]; }; -/* TODO : Support variable DataFlash region for 128kB Flash model */ -#define NUMICRO_BANKS_NUC100(aprom_size) \ - .n_banks = 4, \ - { {NUMICRO_APROM_BASE, (aprom_size)}, {NUMICRO_DATA_BASE, 4*1024}, {NUMICRO_LDROM_BASE, 4*1024}, \ - {NUMICRO_CONFIG_BASE, 1024} } - -#define NUMICRO_BANKS_M051(aprom_size) \ +/* If DataFlash size equals zero, it means the actual size depends on config settings. */ +#define NUMICRO_BANKS_GENERAL(aprom_size, data_size, ldrom_size, config_size) \ .n_banks = 4, \ - { {NUMICRO_APROM_BASE, (aprom_size)}, {NUMICRO_DATA_BASE, 4*1024}, {NUMICRO_LDROM_BASE, 4*1024}, \ - {NUMICRO_CONFIG_BASE, 1024} } - -#define NUMICRO_BANKS_MINI51(aprom_size) \ - .n_banks = 3, \ - { {NUMICRO_APROM_BASE, (aprom_size)}, {NUMICRO_LDROM_BASE, 2*1024}, {NUMICRO_CONFIG_BASE, 512} } - -#define NUMICRO_BANKS_NANO(aprom_size) \ - .n_banks = 4, \ - { {NUMICRO_APROM_BASE, (aprom_size)}, {NUMICRO_DATA_BASE, 4*1024}, {NUMICRO_LDROM_BASE, 4*1024}, \ - {NUMICRO_CONFIG_BASE, 1024} } - -#define NUMICRO_BANKS_NUC400(aprom_size) \ - .n_banks = 4, \ - { {NUMICRO_APROM_BASE, (aprom_size)}, {NUMICRO_DATA_BASE, 4*1024}, {NUMICRO_LDROM_BASE, 16*1024}, \ - {NUMICRO_CONFIG_BASE, 1024} } - + {{NUMICRO_APROM_BASE, (aprom_size)}, \ + {NUMICRO_DATA_BASE, (data_size)}, \ + {NUMICRO_LDROM_BASE, (ldrom_size)}, \ + {NUMICRO_CONFIG_BASE, (config_size)}} static const struct numicro_cpu_type numicro_parts[] = { /*PART NO*/ /*PART ID*/ /*Banks*/ - /* NUC100 Version B */ - {"NUC100LD2BN", 0x10010004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100LD1BN", 0x10010005, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100LD0BN", 0x10010027, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100LC2BN", 0x10010007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100LC1BN", 0x10010008, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100LC0BN", 0x10010028, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100LB2BN", 0x10010029, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC100LB1BN", 0x10010030, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC100LB0BN", 0x10010031, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC100LA2BN", 0x10010032, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC100LA1BN", 0x10010033, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC100LA0BN", 0x10010034, NUMICRO_BANKS_NUC100(8*1024)}, - - {"NUC100RD2BN", 0x10010013, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100RD1BN", 0x10010014, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100RD0BN", 0x10010035, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100RC2BN", 0x10010016, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100RC1BN", 0x10010017, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100RC0BN", 0x10010036, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100RB2BN", 0x10010037, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC100RB1BN", 0x10010038, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC100RB0BN", 0x10010039, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC100RA2BN", 0x10010040, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC100RA1BN", 0x10010041, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC100RA0BN", 0x10010042, NUMICRO_BANKS_NUC100(8*1024)}, - - /* NUC100 Version C */ - {"NUC100LE3CN", 0x20010000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100LE2CN", 0x20010001, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100LE1CN", 0x20010002, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100LD3CN", 0x20010003, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100LD2CN", 0x20010004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100LD1CN", 0x20010005, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100LC3CN", 0x20010006, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100LC2CN", 0x20010007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100LC1CN", 0x20010008, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100RE3CN", 0x20010009, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100RE2CN", 0x20010010, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100RE1CN", 0x20010011, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100RD3CN", 0x20010012, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100RD2CN", 0x20010013, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100RD1CN", 0x20010014, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100RC3CN", 0x20010015, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100RC2CN", 0x20010016, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100RC1CN", 0x20010017, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100VE3CN", 0x20010018, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100VE2CN", 0x20010019, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100VE1CN", 0x20010020, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100VD3CN", 0x20010021, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100VD2CN", 0x20010022, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100VD1CN", 0x20010023, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100VC3CN", 0x20010024, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100VC2CN", 0x20010025, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100VC1CN", 0x20010026, NUMICRO_BANKS_NUC100(32*1024)}, - - /* NUC100 Version B */ - {"NUC101YD2BN", 0x10010143, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101YD1BN", 0x10010144, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101YD0BN", 0x10010145, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101YC2BN", 0x10010146, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101YC1BN", 0x10010147, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101YC0BN", 0x10010148, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101YB2BN", 0x10010149, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC101YB1BN", 0x10010150, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC101YB0BN", 0x10010151, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC101YA2BN", 0x10010152, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC101YA1BN", 0x10010153, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC101YA0BN", 0x10010154, NUMICRO_BANKS_NUC100(8*1024)}, - - {"NUC101LD2BN", 0x10010104, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101LD1BN", 0x10010105, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101LD0BN", 0x10010127, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101LC2BN", 0x10010107, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101LC1BN", 0x10010108, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101LC0BN", 0x10010128, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101LB2BN", 0x10010129, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC101LB1BN", 0x10010130, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC101LB0BN", 0x10010131, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC101LA2BN", 0x10010132, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC101LA1BN", 0x10010133, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC101LA0BN", 0x10010134, NUMICRO_BANKS_NUC100(8*1024)}, - - {"NUC101RD2BN", 0x10010113, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101RD1BN", 0x10010114, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101RD0BN", 0x10010135, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101RC2BN", 0x10010116, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101RC1BN", 0x10010117, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101RC0BN", 0x10010136, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101RB2BN", 0x10010137, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC101RB1BN", 0x10010138, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC101RB0BN", 0x10010139, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC101RA2BN", 0x10010140, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC101RA1BN", 0x10010141, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC101RA0BN", 0x10010142, NUMICRO_BANKS_NUC100(8*1024)}, - - /* NUC101 Version C */ - {"NUC101LE3CN", 0x20010100, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101LE2CN", 0x20010101, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101LE1CN", 0x20010102, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101LD3CN", 0x20010103, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101LD2CN", 0x20010104, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101LD1CN", 0x20010105, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101LC3CN", 0x20010106, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101LC2CN", 0x20010107, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101LC1CN", 0x20010108, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101RE3CN", 0x20010109, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101RE2CN", 0x20010110, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101RE1CN", 0x20010111, NUMICRO_BANKS_NUC100(128*1024)}, - - {"NUC101RD3CN", 0x20010112, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101RD2CN", 0x20010113, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101RD1CN", 0x20010114, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101RC3CN", 0x20010115, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101RC2CN", 0x20010116, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101RC1CN", 0x20010117, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101VE3CN", 0x20010118, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101VE2CN", 0x20010119, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101VE1CN", 0x20010120, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101VD3CN", 0x20010121, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101VD2CN", 0x20010122, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101VD1CN", 0x20010123, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101VC3CN", 0x20010124, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101VC2CN", 0x20010125, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101VC1CN", 0x20010126, NUMICRO_BANKS_NUC100(32*1024)}, - - /* NUC102 Version A */ - {"NUC102ZD2AN", 0x00010231, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC102ZC1AN", 0x00010235, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC102LD2AN", 0x00010204, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC102LC1AN", 0x00010208, NUMICRO_BANKS_NUC100(32*1024)}, - - {"NUC102RB3AN", 0x00010248, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC102RB2AN", 0x00010249, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC102RB1AN", 0x00010250, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC102RA3AN", 0x00010251, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC102RA2AN", 0x00010252, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC102RA1AN", 0x00010253, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC102VB3AN", 0x00010254, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC102VB2AN", 0x00010255, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC102VB1AN", 0x00010256, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC102VA3AN", 0x00010257, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC102VA2AN", 0x00010258, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC102VA1AN", 0x00010259, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC102LA0AN", 0x00010260, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC102LB0AN", 0x00010261, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC102LC0AN", 0x00010262, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC102LD0AN", 0x00010263, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC102RA0AN", 0x00010264, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC102RB0AN", 0x00010265, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC102RC0AN", 0x00010266, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC102RD0AN", 0x00010267, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC102VA0AN", 0x00010268, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC102VB0AN", 0x00010269, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC102VC0AN", 0x00010270, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC102VD0AN", 0x00010271, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC102ZA0AN", 0x00010272, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC102ZB0AN", 0x00010273, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC102ZC0AN", 0x00010274, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC102ZD0AN", 0x00010275, NUMICRO_BANKS_NUC100(64*1024)}, - - /* NUC102 Version A */ - {"NUC122LD2AN", 0x00012204, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC122LD1AN", 0x00012205, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC122LC2AN", 0x00012207, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC122LC1AN", 0x00012208, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC122RD2AN", 0x00012213, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC122RD1AN", 0x00012214, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC122RC2AN", 0x00012216, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC122RC1AN", 0x00012217, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC122SD2AN", 0x00012222, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC122SD1AN", 0x00012223, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC122SC2AN", 0x00012225, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC122SC1AN", 0x00012226, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC122ZD2AN", 0x00012231, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC122ZD1AN", 0x00012232, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC122ZC2AN", 0x00012234, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC122ZC1AN", 0x00012235, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC122ZB2AN", 0x00012237, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC122ZB1AN", 0x00012238, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC122ZA2AN", 0x00012240, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC122ZA1AN", 0x00012241, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC122LB2AN", 0x00012243, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC122LB1AN", 0x00012244, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC122LA2AN", 0x00012246, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC122LA1AN", 0x00012247, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC122RB2AN", 0x00012249, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC122RB1AN", 0x00012250, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC122RA2AN", 0x00012252, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC122RA1AN", 0x00012253, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC122SB2AN", 0x00012255, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC122SB1AN", 0x00012256, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC122SA2AN", 0x00012258, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC122SA1AN", 0x00012259, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC122LA0AN", 0x00012260, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC122LB0AN", 0x00012261, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC122LC0AN", 0x00012262, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC122LD0AN", 0x00012263, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC122RA0AN", 0x00012264, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC122RB0AN", 0x00012265, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC122RC0AN", 0x00012266, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC122RD0AN", 0x00012267, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC122SA0AN", 0x00012268, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC122SB0AN", 0x00012269, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC122SC0AN", 0x00012270, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC122SD0AN", 0x00012271, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC122ZA0AN", 0x00012272, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC122ZB0AN", 0x00012273, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC122ZC0AN", 0x00012274, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC122ZD0AN", 0x00012275, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC122YD2AN", 0x00012277, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC122YD1AN", 0x00012278, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC122YD0AN", 0x00012279, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC122YC2AN", 0x00012281, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC122YC1AN", 0x00012282, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC122YC0AN", 0x00012283, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC122YB2AN", 0x00012285, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC122YB1AN", 0x00012286, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC122YB0AN", 0x00012287, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC122YA2AN", 0x00012289, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC122YA1AN", 0x00012290, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC122YA0AN", 0x00012291, NUMICRO_BANKS_NUC100(8*1024)}, - - /* NUC120 Version C */ - {"NUC120LD2BN", 0x10012004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120LD1BN", 0x10012005, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120LD0BN", 0x10012027, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120LC2BN", 0x10012007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120LC1BN", 0x10012008, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120LC0BN", 0x10012028, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120LB2BN", 0x10012029, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC120LB1BN", 0x10012030, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC120LB0BN", 0x10012031, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC120LA2BN", 0x10012032, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC120LA1BN", 0x10012033, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC120LA0BN", 0x10012034, NUMICRO_BANKS_NUC100(8*1024)}, - - {"NUC120RD2BN", 0x10012013, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120RD1BN", 0x10012014, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120RD0BN", 0x10012035, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120RC2BN", 0x10012016, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120RC1BN", 0x10012017, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120RC0BN", 0x10012036, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120RB2BN", 0x10012037, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC120RB1BN", 0x10012038, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC120RB0BN", 0x10012039, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC120RA2BN", 0x10012040, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC120RA1BN", 0x10012041, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC120RA0BN", 0x10012042, NUMICRO_BANKS_NUC100(8*1024)}, - - /* NUC120 Version C */ - {"NUC120LE3CN", 0x20012000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120LE2CN", 0x20012001, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120LE1CN", 0x20012002, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120LD3CN", 0x20012003, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120LD2CN", 0x20012004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120LD1CN", 0x20012005, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120LC3CN", 0x20012006, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120LC2CN", 0x20012007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120LC1CN", 0x20012008, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120RE3CN", 0x20012009, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120RE2CN", 0x20012010, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120RE1CN", 0x20012011, NUMICRO_BANKS_NUC100(128*1024)}, - - {"NUC120RD3CN", 0x20012012, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120RD2CN", 0x20012013, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120RD1CN", 0x20012014, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120RC3CN", 0x20012015, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120RC2CN", 0x20012016, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120RC1CN", 0x20012017, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120VE3CN", 0x20012018, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120VE2CN", 0x20012019, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120VE1CN", 0x20012020, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120VD3CN", 0x20012021, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120VD2CN", 0x20012022, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120VD1CN", 0x20012023, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120VC3CN", 0x20012024, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120VC2CN", 0x20012025, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120VC1CN", 0x20012026, NUMICRO_BANKS_NUC100(32*1024)}, - - /* NUC120 Version B */ - {"NUC130LD2BN", 0x10013004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130LD1BN", 0x10013005, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130LD0BN", 0x10013027, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130LC2BN", 0x10013007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130LC1BN", 0x10013008, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130LC0BN", 0x10013028, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130LB2BN", 0x10013029, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC130LB1BN", 0x10013030, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC130LB0BN", 0x10013031, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC130LA2BN", 0x10013032, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC130LA1BN", 0x10013033, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC130LA0BN", 0x10013034, NUMICRO_BANKS_NUC100(8*1024)}, - - {"NUC130RD2BN", 0x10013013, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130RD1BN", 0x10013014, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130RD0BN", 0x10013035, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130RC2BN", 0x10013016, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130RC1BN", 0x10013017, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130RC0BN", 0x10013036, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130RB2BN", 0x10013037, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC130RB1BN", 0x10013038, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC130RB0BN", 0x10013039, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC130RA2BN", 0x10013040, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC130RA1BN", 0x10013041, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC130RA0BN", 0x10013042, NUMICRO_BANKS_NUC100(8*1024)}, - - /* NUC130 Version C */ - {"NUC130LE3CN", 0x20013000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130LE2CN", 0x20013001, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130LE1CN", 0x20013002, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130LD3CN", 0x20013003, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130LD2CN", 0x20013004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130LD1CN", 0x20013005, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130LC3CN", 0x20013006, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130LC2CN", 0x20013007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130LC1CN", 0x20013008, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130RE3CN", 0x20013009, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130RE2CN", 0x20013010, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130RE1CN", 0x20013011, NUMICRO_BANKS_NUC100(128*1024)}, - - {"NUC130RD3CN", 0x20013012, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130RD2CN", 0x20013013, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130RD1CN", 0x20013014, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130RC3CN", 0x20013015, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130RC2CN", 0x20013016, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130RC1CN", 0x20013017, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130VE3CN", 0x20013018, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130VE2CN", 0x20013019, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130VE1CN", 0x20013020, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130VD3CN", 0x20013021, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130VD2CN", 0x20013022, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130VD1CN", 0x20013023, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130VC3CN", 0x20013024, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130VC2CN", 0x20013025, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130VC1CN", 0x20013026, NUMICRO_BANKS_NUC100(32*1024)}, - - /* NUC140 Version B */ - {"NUC140LD2BN", 0x10014004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140LD1BN", 0x10014005, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140LD0BN", 0x10014027, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140LC2BN", 0x10014007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140LC1BN", 0x10014008, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140LC0BN", 0x10014028, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140LB2BN", 0x10014029, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC140LB1BN", 0x10014030, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC140LB0BN", 0x10014031, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC140LA2BN", 0x10014032, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC140LA1BN", 0x10014033, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC140LA0BN", 0x10014034, NUMICRO_BANKS_NUC100(8*1024)}, - - {"NUC140RD2BN", 0x10014013, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140RD1BN", 0x10014014, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140RD0BN", 0x10014035, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140RC2BN", 0x10014016, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140RC1BN", 0x10014017, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140RC0BN", 0x10014036, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140RB2BN", 0x10014037, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC140RB1BN", 0x10014038, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC140RB0BN", 0x10014039, NUMICRO_BANKS_NUC100(16*1024)}, - {"NUC140RA2BN", 0x10014040, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC140RA1BN", 0x10014041, NUMICRO_BANKS_NUC100(8*1024)}, - {"NUC140RA0BN", 0x10014042, NUMICRO_BANKS_NUC100(8*1024)}, - - /* NUC140 Version C */ - {"NUC140LE3CN", 0x20014000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140LE2CN", 0x20014001, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140LE1CN", 0x20014002, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140LD3CN", 0x20014003, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140LD2CN", 0x20014004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140LD1CN", 0x20014005, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140LC3CN", 0x20014006, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140LC2CN", 0x20014007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140LC1CN", 0x20014008, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140RE3CN", 0x20014009, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140RE2CN", 0x20014010, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140RE1CN", 0x20014011, NUMICRO_BANKS_NUC100(128*1024)}, - - {"NUC140RD3CN", 0x20014012, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140RD2CN", 0x20014013, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140RD1CN", 0x20014014, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140RC3CN", 0x20014015, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140RC2CN", 0x20014016, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140RC1CN", 0x20014017, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140VE3CN", 0x20014018, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140VE2CN", 0x20014019, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140VE1CN", 0x20014020, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140VD3CN", 0x20014021, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140VD2CN", 0x20014022, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140VD1CN", 0x20014023, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140VC3CN", 0x20014024, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140VC2CN", 0x20014025, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140VC1CN", 0x20014026, NUMICRO_BANKS_NUC100(32*1024)}, - - /* NUC100 Version A */ - {"NUC100LE3AN", 0x00010000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100LE2AN", 0x00010001, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100LE1AN", 0x00010002, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100LD3AN", 0x00010003, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100LD2AN", 0x00010004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100LD1AN", 0x00010005, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100LC3AN", 0x00010006, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100LC2AN", 0x00010007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100LC1AN", 0x00010008, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100RE3AN", 0x00010009, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100RE2AN", 0x00010010, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100RE1AN", 0x00010011, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100RD3AN", 0x00010012, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100RD2AN", 0x00010013, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100RD1AN", 0x00010014, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100RC3AN", 0x00010015, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100RC2AN", 0x00010016, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100RC1AN", 0x00010017, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100VE3AN", 0x00010018, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100VE2AN", 0x00010019, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100VE1AN", 0x00010020, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100VD3AN", 0x00010021, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100VD2AN", 0x00010022, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100VD1AN", 0x00010023, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100VC3AN", 0x00010024, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100VC2AN", 0x00010025, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100VC1AN", 0x00010026, NUMICRO_BANKS_NUC100(32*1024)}, - - /* NUC100 Version A */ - {"NUC101LE3AN", 0x00010100, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101LE2AN", 0x00010101, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101LE1AN", 0x00010102, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101LD3AN", 0x00010103, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101LD2AN", 0x00010104, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101LD1AN", 0x00010105, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101LC3AN", 0x00010106, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101LC2AN", 0x00010107, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101LC1AN", 0x00010108, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101RE3AN", 0x00010109, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101RE2AN", 0x00010110, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101RE1AN", 0x00010111, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101RD3AN", 0x00010112, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101RD2AN", 0x00010113, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101RD1AN", 0x00010114, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101RC3AN", 0x00010115, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101RC2AN", 0x00010116, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101RC1AN", 0x00010117, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101VE3AN", 0x00010118, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101VE2AN", 0x00010119, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101VE1AN", 0x00010120, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC101VD3AN", 0x00010121, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101VD2AN", 0x00010122, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101VD1AN", 0x00010123, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC101VC3AN", 0x00010124, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101VC2AN", 0x00010125, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC101VC1AN", 0x00010126, NUMICRO_BANKS_NUC100(32*1024)}, - - /* NUC120 Version A */ - {"NUC120LE3AN", 0x00012000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120LE2AN", 0x00012001, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120LE1AN", 0x00012002, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120LD3AN", 0x00012003, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120LD2AN", 0x00012004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120LD1AN", 0x00012005, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120LC3AN", 0x00012006, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120LC2AN", 0x00012007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120LC1AN", 0x00012008, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120RE3AN", 0x00012009, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120RE2AN", 0x00012010, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120RE1AN", 0x00012011, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120RD3AN", 0x00012012, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120RD2AN", 0x00012013, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120RD1AN", 0x00012014, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120RC3AN", 0x00012015, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120RC2AN", 0x00012016, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120RC1AN", 0x00012017, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120VE3AN", 0x00012018, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120VE2AN", 0x00012019, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120VE1AN", 0x00012020, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120VD3AN", 0x00012021, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120VD2AN", 0x00012022, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120VD1AN", 0x00012023, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120VC3AN", 0x00012024, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120VC2AN", 0x00012025, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120VC1AN", 0x00012026, NUMICRO_BANKS_NUC100(32*1024)}, - - /* NUC120 Version A */ - {"NUC130LE3AN", 0x00013000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130LE2AN", 0x00013001, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130LE1AN", 0x00013002, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130LD3AN", 0x00013003, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130LD2AN", 0x00013004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130LD1AN", 0x00013005, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130LC3AN", 0x00013006, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130LC2AN", 0x00013007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130LC1AN", 0x00013008, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130RE3AN", 0x00013009, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130RE2AN", 0x00013010, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130RE1AN", 0x00013011, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130RD3AN", 0x00013012, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130RD2AN", 0x00013013, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130RD1AN", 0x00013014, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130RC3AN", 0x00013015, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130RC2AN", 0x00013016, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130RC1AN", 0x00013017, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130VE3AN", 0x00013018, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130VE2AN", 0x00013019, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130VE1AN", 0x00013020, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130VD3AN", 0x00013021, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130VD2AN", 0x00013022, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130VD1AN", 0x00013023, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC130VC3AN", 0x00013024, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130VC2AN", 0x00013025, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC130VC1AN", 0x00013026, NUMICRO_BANKS_NUC100(32*1024)}, - - /* NUC140 Version A */ - {"NUC140LE3AN", 0x00014000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140LE2AN", 0x00014001, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140LE1AN", 0x00014002, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140LD3AN", 0x00014003, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140LD2AN", 0x00014004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140LD1AN", 0x00014005, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140LC3AN", 0x00014006, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140LC2AN", 0x00014007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140LC1AN", 0x00014008, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140RE3AN", 0x00014009, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140RE2AN", 0x00014010, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140RE1AN", 0x00014011, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140RD3AN", 0x00014012, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140RD2AN", 0x00014013, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140RD1AN", 0x00014014, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140RC3AN", 0x00014015, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140RC2AN", 0x00014016, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140RC1AN", 0x00014017, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140VE3AN", 0x00014018, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140VE2AN", 0x00014019, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140VE1AN", 0x00014020, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC140VD3AN", 0x00014021, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140VD2AN", 0x00014022, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140VD1AN", 0x00014023, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC140VC3AN", 0x00014024, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140VC2AN", 0x00014025, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC140VC1AN", 0x00014026, NUMICRO_BANKS_NUC100(32*1024)}, - - - /* M052 */ - {"M052LAN" , 0x00005200, NUMICRO_BANKS_M051(8*1024)}, - {"M052PAN" , 0x00005201, NUMICRO_BANKS_M051(8*1024)}, - {"M052YAN" , 0x00005202, NUMICRO_BANKS_M051(8*1024)}, - {"M052ZAN" , 0x00005203, NUMICRO_BANKS_M051(8*1024)}, - - /* M054 */ - {"M054LAN" , 0x00005400, NUMICRO_BANKS_M051(16*1024)}, - {"M054PAN" , 0x00005401, NUMICRO_BANKS_M051(16*1024)}, - {"M054YAN" , 0x00005402, NUMICRO_BANKS_M051(16*1024)}, - {"M054ZAN" , 0x00005403, NUMICRO_BANKS_M051(16*1024)}, - - /* M058 */ - {"M058LAN" , 0x00005800, NUMICRO_BANKS_M051(32*1024)}, - {"M058PAN" , 0x00005801, NUMICRO_BANKS_M051(32*1024)}, - {"M058YAN" , 0x00005802, NUMICRO_BANKS_M051(32*1024)}, - {"M058ZAN" , 0x00005803, NUMICRO_BANKS_M051(32*1024)}, - - /* M0516 */ - {"M0516LAN" , 0x00005A00, NUMICRO_BANKS_M051(64*1024)}, - {"M0516PAN" , 0x00005A01, NUMICRO_BANKS_M051(64*1024)}, - {"M0516YAN" , 0x00005A02, NUMICRO_BANKS_M051(64*1024)}, - {"M0516ZAN" , 0x00005A03, NUMICRO_BANKS_M051(64*1024)}, - {"M051LBN" , 0x10005100, NUMICRO_BANKS_M051(4*1024)}, - {"M051PBN" , 0x10005101, NUMICRO_BANKS_M051(4*1024)}, - {"M051YBN" , 0x10005102, NUMICRO_BANKS_M051(4*1024)}, - {"M051ZBN" , 0x10005103, NUMICRO_BANKS_M051(4*1024)}, - {"M052LBN" , 0x10005200, NUMICRO_BANKS_M051(8*1024)}, - {"M052PBN" , 0x10005201, NUMICRO_BANKS_M051(8*1024)}, - {"M052YBN" , 0x10005202, NUMICRO_BANKS_M051(8*1024)}, - {"M052ZBN" , 0x10005203, NUMICRO_BANKS_M051(8*1024)}, - {"M054LBN" , 0x10005400, NUMICRO_BANKS_M051(16*1024)}, - {"M054PBN" , 0x10005401, NUMICRO_BANKS_M051(16*1024)}, - {"M054YBN" , 0x10005402, NUMICRO_BANKS_M051(16*1024)}, - {"M054ZBN" , 0x10005403, NUMICRO_BANKS_M051(16*1024)}, - {"M058LBN" , 0x10005800, NUMICRO_BANKS_M051(32*1024)}, - {"M058PBN" , 0x10005801, NUMICRO_BANKS_M051(32*1024)}, - {"M058YBN" , 0x10005802, NUMICRO_BANKS_M051(32*1024)}, - {"M058ZBN" , 0x10005803, NUMICRO_BANKS_M051(32*1024)}, - {"M0516LBN" , 0x10005A00, NUMICRO_BANKS_M051(64*1024)}, - {"M0516PBN" , 0x10005A01, NUMICRO_BANKS_M051(64*1024)}, - {"M0516YBN" , 0x10005A02, NUMICRO_BANKS_M051(64*1024)}, - {"M0516ZBN" , 0x10005A03, NUMICRO_BANKS_M051(64*1024)}, - {"M052LDN" , 0x20005200, NUMICRO_BANKS_M051(8*1024)}, - {"M054LDN" , 0x20005400, NUMICRO_BANKS_M051(16*1024)}, - {"M058LDN" , 0x20005800, NUMICRO_BANKS_M051(32*1024)}, - {"M0516LDN" , 0x20005A00, NUMICRO_BANKS_M051(64*1024)}, - {"M052ZDN" , 0x20005203, NUMICRO_BANKS_M051(8*1024)}, - {"M054ZDN" , 0x20005403, NUMICRO_BANKS_M051(16*1024)}, - {"M058ZDN" , 0x20005803, NUMICRO_BANKS_M051(32*1024)}, - {"M0516ZDN" , 0x20005A03, NUMICRO_BANKS_M051(64*1024)}, - {"M052TDN" , 0x20005204, NUMICRO_BANKS_M051(8*1024)}, - {"M054TDN" , 0x20005404, NUMICRO_BANKS_M051(16*1024)}, - {"M058TDN" , 0x20005804, NUMICRO_BANKS_M051(32*1024)}, - {"M0516TDN" , 0x20005A04, NUMICRO_BANKS_M051(64*1024)}, - {"M052XDN" , 0x20005205, NUMICRO_BANKS_M051(8*1024)}, - {"M054XDN" , 0x20005405, NUMICRO_BANKS_M051(16*1024)}, - {"M058XDN" , 0x20005805, NUMICRO_BANKS_M051(32*1024)}, - {"M0516XDN" , 0x20005A05, NUMICRO_BANKS_M051(64*1024)}, - {"M052LDE" , 0x30005200, NUMICRO_BANKS_M051(8*1024)}, - {"M054LDE" , 0x30005400, NUMICRO_BANKS_M051(16*1024)}, - {"M058LDE" , 0x30005800, NUMICRO_BANKS_M051(32*1024)}, - {"M0516LDE" , 0x30005A00, NUMICRO_BANKS_M051(64*1024)}, - {"M052ZDE" , 0x30005203, NUMICRO_BANKS_M051(8*1024)}, - {"M054ZDE" , 0x30005403, NUMICRO_BANKS_M051(16*1024)}, - {"M058ZDE" , 0x30005803, NUMICRO_BANKS_M051(32*1024)}, - {"M0516ZDE" , 0x30005A03, NUMICRO_BANKS_M051(64*1024)}, - {"M052TDE" , 0x30005204, NUMICRO_BANKS_M051(8*1024)}, - {"M054TDE" , 0x30005404, NUMICRO_BANKS_M051(16*1024)}, - {"M058TDE" , 0x30005804, NUMICRO_BANKS_M051(32*1024)}, - {"M0516TDE" , 0x30005A04, NUMICRO_BANKS_M051(64*1024)}, - {"M052XDE" , 0x30005205, NUMICRO_BANKS_M051(8*1024)}, - {"M054XDE" , 0x30005405, NUMICRO_BANKS_M051(16*1024)}, - {"M058XDE" , 0x30005805, NUMICRO_BANKS_M051(32*1024)}, - {"M0516XDE" , 0x30005A05, NUMICRO_BANKS_M051(64*1024)}, - - /* Mini51 */ - {"MINI51LAN", 0x00205100, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI51QAN", 0x00205101, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI51 ", 0x00205102, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI51ZAN", 0x00205103, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI51TAN", 0x00205104, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI52LAN", 0x00205200, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI52QAN", 0x00205201, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI52 ", 0x00205202, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI52ZAN", 0x00205203, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI52TAN", 0x00205204, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI54LAN", 0x00205400, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI54QAN", 0x00205401, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI54 ", 0x00205402, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI54ZAN", 0x00205403, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI54TAN", 0x00205404, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI51LBN", 0x10205100, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI51QBN", 0x10205101, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI51 ", 0x10205102, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI51ZBN", 0x10205103, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI51TBN", 0x10205104, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI52LBN", 0x10205200, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI52QBN", 0x10205201, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI52 ", 0x10205202, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI52ZBN", 0x10205203, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI52TBN", 0x10205204, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI54LBN", 0x10205400, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI54QBN", 0x10205401, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI54 ", 0x10205402, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI54ZBN" , 0x10205403, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI54TBN" , 0x10205404, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI51LDE" , 0x20205100, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI51QDE" , 0x20205101, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI51 " , 0x20205102, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI51ZDE" , 0x20205103, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI51TDE" , 0x20205104, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI51FDE" , 0x20205105, NUMICRO_BANKS_MINI51(4*1024)}, - {"MINI52LDE" , 0x20205200, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI52QDE" , 0x20205201, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI52 " , 0x20205202, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI52ZDE" , 0x20205203, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI52TDE" , 0x20205204, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI52FDE" , 0x20205205, NUMICRO_BANKS_MINI51(8*1024)}, - {"MINI54LDE" , 0x20205400, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI54QDE" , 0x20205401, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI54 " , 0x20205402, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI54ZDE" , 0x20205403, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI54TDE" , 0x20205404, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI54FDE" , 0x20205405, NUMICRO_BANKS_MINI51(16*1024)}, - {"MINI55LDE" , 0x20205500, NUMICRO_BANKS_MINI51(16*1024)}, - - /* NANO100 */ - {"NANO100VF3AN" , 0x00110000, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO100VF2AN" , 0x00110001, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO100RF3AN" , 0x00110002, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO100RF2AN" , 0x00110003, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO100LF3AN" , 0x00110004, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO100LF2AN" , 0x00110005, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO100VE3AN" , 0x00110006, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO100VE2AN" , 0x00110007, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO100RE3AN" , 0x00110008, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO100RE2AN" , 0x00110009, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO100LE3AN" , 0x00110010, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO100LE2AN" , 0x00110011, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO100VD3AN" , 0x00110012, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100VD2AN" , 0x00110013, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100VD1AN" , 0x00110014, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100RD3AN" , 0x00110015, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100RD2AN" , 0x00110016, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100RD1AN" , 0x00110017, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100LD3AN" , 0x00110018, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100LD2AN" , 0x00110019, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100LD1AN" , 0x00110020, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100VC2AN" , 0x00110021, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO100VC1AN" , 0x00110022, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO100RC2AN" , 0x00110023, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO100RC1AN" , 0x00110024, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO100LC2AN" , 0x00110025, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO100LC1AN" , 0x00110026, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO100VB1AN" , 0x00110027, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO100VB0AN" , 0x00110028, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO100RB1AN" , 0x00110029, NUMICRO_BANKS_NANO(16*1024)}, - - {"NANO110VF3AN" , 0x00111000, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO110VF2AN" , 0x00111001, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO110RF3AN" , 0x00111002, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO110RF2AN" , 0x00111003, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO110VE3AN" , 0x00111006, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO110VE2AN" , 0x00111007, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO110RE3AN" , 0x00111008, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO110RE2AN" , 0x00111009, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO110VD3AN" , 0x00111012, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO110VD2AN" , 0x00111013, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO110VD1AN" , 0x00111014, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO110RD3AN" , 0x00111015, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO110RD2AN" , 0x00111016, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO110RD1AN" , 0x00111017, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO110VC2AN" , 0x00111021, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO110VC1AN" , 0x00111022, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO110SC2AN" , 0x00111023, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO110SC1AN" , 0x00111024, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO120VF3AN" , 0x00112000, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO120VF2AN" , 0x00112001, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO120RF3AN" , 0x00112002, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO120RF2AN" , 0x00112003, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO120LF3AN" , 0x00112004, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO120LF2AN" , 0x00112005, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO120VE3AN" , 0x00112006, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO120VE2AN" , 0x00112007, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO120RE3AN" , 0x00112008, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO120RE2AN" , 0x00112009, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO120LE3AN" , 0x00112010, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO120LE2AN" , 0x00112011, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO120VD3AN" , 0x00112012, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120VD2AN" , 0x00112013, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120VD1AN" , 0x00112014, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120SD3AN" , 0x00112015, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120SD2AN" , 0x00112016, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120SD1AN" , 0x00112017, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120LD3AN" , 0x00112018, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120LD2AN" , 0x00112019, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120LD1AN" , 0x00112020, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120VC2AN" , 0x00112021, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO120VC1AN" , 0x00112022, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO120SC2AN" , 0x00112023, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO120SC1AN" , 0x00112024, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO120LC2AN" , 0x00112025, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO120LC1AN" , 0x00112026, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO130VF3AN" , 0x00113000, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO130VF2AN" , 0x00113001, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO130SF3AN" , 0x00113002, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO130SF2AN" , 0x00113003, NUMICRO_BANKS_NANO(256*1024)}, - {"NANO130VE3AN" , 0x00113006, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO130VE2AN" , 0x00113007, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO130SE3AN" , 0x00113008, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO130SE2AN" , 0x00113009, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO130VD3AN" , 0x00113012, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO130VD2AN" , 0x00113013, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO130VD1AN" , 0x00113014, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO130SD3AN" , 0x00113015, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO130SD2AN" , 0x00113016, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO130SD1AN" , 0x00113017, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO130VC2AN" , 0x00113021, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO130VC1AN" , 0x00113022, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO130SC2AN" , 0x00113023, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO130SC1AN" , 0x00113024, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO100KE3BN" , 0x00110030, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO100KE2BN" , 0x00110031, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO100VE3BN" , 0x00110032, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO100VE2BN" , 0x00110033, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO100SE3BN" , 0x00110034, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO100SE2BN" , 0x00110035, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO100LE3BN" , 0x00110036, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO100LE2BN" , 0x00110037, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO100KD3BN" , 0x00110038, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100KD2BN" , 0x00110039, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100VD3BN" , 0x0011003A, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100VD2BN" , 0x0011003B, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100SD3BN" , 0x0011003C, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100SD2BN" , 0x0011003D, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100LD3BN" , 0x0011003E, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100LD2BN" , 0x0011003F, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO100KC2BN" , 0x00110040, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO100VC2BN" , 0x00110041, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO100SC2BN" , 0x00110042, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO100LC2BN" , 0x00110043, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO110KE3BN" , 0x00111030, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO110KE2BN" , 0x00111031, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO110VE3BN" , 0x00111032, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO110VE2BN" , 0x00111033, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO110SE3BN" , 0x00111034, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO110SE2BN" , 0x00111035, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO110KD3BN" , 0x00111038, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO110KD2BN" , 0x00111039, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO110VD3BN" , 0x0011103A, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO110VD2BN" , 0x0011103B, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO110SD3BN" , 0x0011103C, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO110SD2BN" , 0x0011103D, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO110KC2BN" , 0x00111040, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO110VC2BN" , 0x00111041, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO110SC2BN" , 0x00111042, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO120KE3BN" , 0x00112030, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO120KE2BN" , 0x00112031, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO120VE3BN" , 0x00112032, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO120VE2BN" , 0x00112033, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO120SE3BN" , 0x00112034, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO120SE2BN" , 0x00112035, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO120LE3BN" , 0x00112036, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO120LE2BN" , 0x00112037, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO120KD3BN" , 0x00112038, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120KD2BN" , 0x00112039, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120VD3BN" , 0x0011203A, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120VD2BN" , 0x0011203B, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120SD3BN" , 0x0011203C, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120SD2BN" , 0x0011203D, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120LD3BN" , 0x0011203E, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120LD2BN" , 0x0011203F, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO120KC2BN" , 0x00112040, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO120VC2BN" , 0x00112041, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO120SC2BN" , 0x00112042, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO120LC2BN" , 0x00112043, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO130KE3BN" , 0x00113030, NUMICRO_BANKS_NANO(123*1024)}, - {"NANO130KE2BN" , 0x00113031, NUMICRO_BANKS_NANO(123*1024)}, - {"NANO130VE3BN" , 0x00113032, NUMICRO_BANKS_NANO(123*1024)}, - {"NANO130VE2BN" , 0x00113033, NUMICRO_BANKS_NANO(123*1024)}, - {"NANO130SE3BN" , 0x00113034, NUMICRO_BANKS_NANO(123*1024)}, - {"NANO130SE2BN" , 0x00113035, NUMICRO_BANKS_NANO(123*1024)}, - {"NANO130KD3BN" , 0x00113038, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO130KD2BN" , 0x00113039, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO130VD3BN" , 0x0011303A, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO130VD2BN" , 0x0011303B, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO130SD3BN" , 0x0011303C, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO130SD2BN" , 0x0011303D, NUMICRO_BANKS_NANO(64*1024)}, - {"NANO130KC2BN" , 0x00113040, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO130VC2BN" , 0x00113041, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO130SC2BN" , 0x00113042, NUMICRO_BANKS_NANO(32*1024)}, - {"N512DC4" , 0x00100000, NUMICRO_BANKS_NANO(64*1024)}, - {"N512LC4" , 0x00100001, NUMICRO_BANKS_NANO(64*1024)}, - {"N512MC4" , 0x00100003, NUMICRO_BANKS_NANO(64*1024)}, - - {"N512SC4" , 0x00100005, NUMICRO_BANKS_NANO(64*1024)}, - {"N512VD4" , 0x00100008, NUMICRO_BANKS_NANO(128*1024)}, - {"N512MD4" , 0x00100009, NUMICRO_BANKS_NANO(128*1024)}, - {"N512SD4" , 0x00100010, NUMICRO_BANKS_NANO(128*1024)}, - {"NANO110RC2BN" , 0x00111043, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO110RD3BN" , 0x00111045, NUMICRO_BANKS_NANO(64*1024)}, - {"TX110VE3BN" , 0x00111036, NUMICRO_BANKS_NANO(128*1024)}, - - /* NANO102/NANO112 */ - {"NANO112LB0AN" , 0x00111201, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO112LB1AN" , 0x00111202, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO112LC1AN" , 0x00111203, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO112LC2AN" , 0x00111204, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO112SB0AN" , 0x00111205, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO112SB1AN" , 0x00111206, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO112SC1AN" , 0x00111207, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO112SC2AN" , 0x00111208, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO112RB0AN" , 0x00111209, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO112RB1AN" , 0x00111210, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO112RC1AN" , 0x00111211, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO112RC2AN" , 0x00111212, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO112VB0AN" , 0x00111213, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO112VB1AN" , 0x00111214, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO112VC1AN" , 0x00111215, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO112VC2AN" , 0x00111216, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO102ZB0AN" , 0x00110201, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO102ZB1AN" , 0x00110202, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO102ZC1AN" , 0x00110203, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO102ZC2AN" , 0x00110204, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO102LB0AN" , 0x00110205, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO102LB1AN" , 0x00110206, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO102LC1AN" , 0x00110207, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO102LC2AN" , 0x00110208, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO102SB0AN" , 0x00110209, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO102SB1AN" , 0x00110210, NUMICRO_BANKS_NANO(16*1024)}, - {"NANO102SC1AN" , 0x00110211, NUMICRO_BANKS_NANO(32*1024)}, - {"NANO102SC2AN" , 0x00110212, NUMICRO_BANKS_NANO(32*1024)}, - - /* NUC103/NUC105/NUC123 */ - {"NUC123SC2AN" , 0x00012305, NUMICRO_BANKS_NUC100(36*1024)}, - {"NUC123SD4AN" , 0x00012315, NUMICRO_BANKS_NUC100(68*1024)}, - {"NUC123LC2AN" , 0x00012325, NUMICRO_BANKS_NUC100(36*1024)}, - {"NUC103LC2AN" , 0x00010325, NUMICRO_BANKS_NUC100(36*1024)}, - {"NUC105LC2AN" , 0x00010525, NUMICRO_BANKS_NUC100(36*1024)}, - {"NUC123LD4AN" , 0x00012335, NUMICRO_BANKS_NUC100(68*1024)}, - {"NUC103LD4AN" , 0x00010335, NUMICRO_BANKS_NUC100(68*1024)}, - {"NUC105LD4AN" , 0x00010535, NUMICRO_BANKS_NUC100(68*1024)}, - {"NUC123ZC2AN" , 0x00012345, NUMICRO_BANKS_NUC100(36*1024)}, - {"NUC103ZC2AN" , 0x00010345, NUMICRO_BANKS_NUC100(36*1024)}, - {"NUC105ZC2AN" , 0x00010545, NUMICRO_BANKS_NUC100(36*1024)}, - {"NUC123ZD4AN" , 0x00012355, NUMICRO_BANKS_NUC100(68*1024)}, - {"NUC103ZD4AN" , 0x00010355, NUMICRO_BANKS_NUC100(68*1024)}, - {"NUC105ZD4AN" , 0x00010555, NUMICRO_BANKS_NUC100(68*1024)}, - - /* NUC200 */ - {"NUC200LC2AN" , 0x00020007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC200LD2AN" , 0x00020004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC200LE3AN" , 0x00020000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC200SC1AN" , 0x00020035, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC200SD2AN" , 0x00020031, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC200SE3AN" , 0x00020027, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC200VE3AN" , 0x00020018, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC220LC2AN" , 0x00022007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC220LD2AN" , 0x00022004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC220LE3AN" , 0x00022000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC220SC1AN" , 0x00022035, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC220SD2AN" , 0x00022031, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC220SE3AN" , 0x00022027, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC220VE3AN" , 0x00022018, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC230LC2AN" , 0x00023007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC230LD2AN" , 0x00023004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC230LE3AN" , 0x00023000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC230SC1AN" , 0x00023035, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC230SD2AN" , 0x00023031, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC230SE3AN" , 0x00023027, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC230VE3AN" , 0x00023018, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC240LC2AN" , 0x00024007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC240LD2AN" , 0x00024004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC240LE3AN" , 0x00024000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC240SC1AN" , 0x00024035, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC240SD2AN" , 0x00024031, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC240SE3AN" , 0x00024027, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC240VE3AN" , 0x00024018, NUMICRO_BANKS_NUC100(128*1024)}, - - /* NUC200 NUC2XXAE */ - {"NUC230RC1AE" , 0x40013017, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC200LC2AE" , 0x10020007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC200LD2AE" , 0x10020004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC200LE3AE" , 0x10020000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC200SC2AE" , 0x10020034, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC200SD2AE" , 0x10020031, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC200SE3AE" , 0x10020027, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC200VE3AE" , 0x10020018, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC230LC2AE" , 0x10023007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC230LD2AE" , 0x10023004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC230LE3AE" , 0x10023000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC230SC2AE" , 0x10023034, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC230SD2AE" , 0x10023031, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC230SE3AE" , 0x10023027, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC230VE3AE" , 0x10023018, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC240LC2AE" , 0x10024007, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC240LD2AE" , 0x10024004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC240LE3AE" , 0x10024000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC240SC2AE" , 0x10024034, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC240SD2AE" , 0x10024031, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC240SE3AE" , 0x10024027, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC240VE3AE" , 0x10024018, NUMICRO_BANKS_NUC100(128*1024)}, - - /* NUC100 Version D */ - {"NUC100LC1DN" , 0x30010008, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100LD1DN" , 0x30010005, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100LD2DN" , 0x30010004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100RC1DN" , 0x30010017, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC100RD1DN" , 0x30010014, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100RD2DN" , 0x30010013, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100LD3DN" , 0x30010003, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100LE3DN" , 0x30010000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100RD3DN" , 0x30010012, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100RE3DN" , 0x30010009, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC100VD2DN" , 0x30010022, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100VD3DN" , 0x30010021, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC100VE3DN" , 0x30010018, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120LC1DN" , 0x30012008, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120LD1DN" , 0x30012005, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120LD2DN" , 0x30012004, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120RC1DN" , 0x30012017, NUMICRO_BANKS_NUC100(32*1024)}, - {"NUC120RD1DN" , 0x30012014, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120RD2DN" , 0x30012013, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120LD3DN" , 0x30012003, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120LE3DN" , 0x30012000, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120RD3DN" , 0x30012012, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120RE3DN" , 0x30012009, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC120VD2DN" , 0x30012022, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120VD3DN" , 0x30012021, NUMICRO_BANKS_NUC100(64*1024)}, - {"NUC120VE3DN" , 0x30012018, NUMICRO_BANKS_NUC100(128*1024)}, - {"NUC130RC1DN" , 0x30013017, NUMICRO_BANKS_NUC100(32*1024)}, - - {"UNKNOWN" , 0x00000000, NUMICRO_BANKS_NUC100(128*1024)}, + /* M051AN */ + {"M052LAN", 0x00005200, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M054LAN", 0x00005400, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M058LAN", 0x00005800, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M0516LAN", 0x00005A00, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M052ZAN", 0x00005203, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M054ZAN", 0x00005403, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M058ZAN", 0x00005803, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M0516ZAN", 0x00005A03, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, + + /* M051BN */ + {"M052LBN", 0x10005200, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M054LBN", 0x10005400, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M058LBN", 0x10005800, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M0516LBN", 0x10005A00, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M052ZBN", 0x10005203, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M054ZBN", 0x10005403, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M058ZBN", 0x10005803, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M0516ZBN", 0x10005A03, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, + + /* M051DN */ + {"M0516LDN", 0x20005A00, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M0516ZDN", 0x20005A03, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M052LDN", 0x20005200, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M052ZDN", 0x20005203, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M054LDN", 0x20005400, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M054ZDN", 0x20005403, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M058LDN", 0x20005800, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M058ZDN", 0x20005803, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, + + /* M051DE */ + {"M0516LDE", 0x30005A00, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M0516ZDE", 0x30005A03, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M052LDE", 0x30005200, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M052ZDE", 0x30005203, NUMICRO_BANKS_GENERAL(8 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M054LDE", 0x30005400, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M054ZDE", 0x30005403, NUMICRO_BANKS_GENERAL(16 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M058LDE", 0x30005800, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"M058ZDE", 0x30005803, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, + + /* M0518 */ + {"M0518LC2AE", 0x10051803, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"M0518LD2AE", 0x10051800, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"M0518SC2AE", 0x10051813, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"M0518SD2AE", 0x10051810, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + + /* M0519 */ + {"M0519LD3AE", 0x00051902, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 8 * 1024, 8)}, + {"M0519LE3AE", 0x00051900, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, + {"M0519SD3AE", 0x00051922, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 8 * 1024, 8)}, + {"M0519SE3AE", 0x00051920, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, + {"M0519VE3AE", 0x00051930, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, + + /* M058S */ + {"M058SFAN", 0x00005818, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"M058SLAN", 0x00005810, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"M058SSAN", 0x00005816, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"M058SZAN", 0x00005813, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + + /* MINI51AN */ + {"MINI51LAN", 0x00205100, NUMICRO_BANKS_GENERAL(4 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI51TAN", 0x00205104, NUMICRO_BANKS_GENERAL(4 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI51ZAN", 0x00205103, NUMICRO_BANKS_GENERAL(4 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI52LAN", 0x00205200, NUMICRO_BANKS_GENERAL(8 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI52TAN", 0x00205204, NUMICRO_BANKS_GENERAL(8 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI52ZAN", 0x00205203, NUMICRO_BANKS_GENERAL(8 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI54LAN", 0x00205400, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI54TAN", 0x00205404, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI54ZAN", 0x00205403, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, + + /* MINI51DE */ + {"MINI51FDE", 0x20205105, NUMICRO_BANKS_GENERAL(4 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI51LDE", 0x20205100, NUMICRO_BANKS_GENERAL(4 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI51TDE", 0x20205104, NUMICRO_BANKS_GENERAL(4 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI51ZDE", 0x20205103, NUMICRO_BANKS_GENERAL(4 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI52FDE", 0x20205205, NUMICRO_BANKS_GENERAL(8 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI52LDE", 0x20205200, NUMICRO_BANKS_GENERAL(8 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI52TDE", 0x20205204, NUMICRO_BANKS_GENERAL(8 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI52ZDE", 0x20205203, NUMICRO_BANKS_GENERAL(8 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI54FDE", 0x20205405, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI54LDE", 0x20205400, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI54TDE", 0x20205404, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, + {"MINI54ZDE", 0x20205403, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, + + /* MINI55 */ + {"MINI55LDE", 0x00505500, NUMICRO_BANKS_GENERAL(35 * 512, 0 * 1024, 2 * 1024, 8)}, + {"MINI55ZDE", 0x00505503, NUMICRO_BANKS_GENERAL(35 * 512, 0 * 1024, 2 * 1024, 8)}, + + /* MINI58 */ + {"MINI58FDE", 0x00A05805, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 5 * 512, 8)}, + {"MINI58LDE", 0x00A05800, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 5 * 512, 8)}, + {"MINI58TDE", 0x00A05804, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 5 * 512, 8)}, + {"MINI58ZDE", 0x00A05803, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 5 * 512, 8)}, + + /* NANO100AN */ + {"NANO100LC2AN", 0x00110025, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100LD2AN", 0x00110019, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100LD3AN", 0x00110018, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100SC2AN", 0x00110023, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100SD2AN", 0x00110016, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100SD3AN", 0x00110015, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100VD2AN", 0x00110013, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100VD3AN", 0x00110012, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100ZC2AN", 0x00110029, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100ZD2AN", 0x00110028, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100ZD3AN", 0x00110027, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120LC2AN", 0x00112025, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120LD2AN", 0x00112019, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120LD3AN", 0x00112018, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120SC2AN", 0x00112023, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120SD2AN", 0x00112016, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120SD3AN", 0x00112015, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120VD2AN", 0x00112013, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120VD3AN", 0x00112012, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120ZC2AN", 0x00112029, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120ZD2AN", 0x00112028, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120ZD3AN", 0x00112027, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + + /* NANO100BN */ + {"NANO100KC2BN", 0x00110040, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100KD2BN", 0x00110039, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100KD3BN", 0x00110038, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100KE3BN", 0x00110030, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100LC2BN", 0x00110043, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100LD2BN", 0x0011003F, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100LD3BN", 0x0011003E, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100LE3BN", 0x00110036, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100ND2BN", 0x00110046, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100ND3BN", 0x00110045, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100NE3BN", 0x00110044, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100SC2BN", 0x00110042, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100SD2BN", 0x0011003D, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100SD3BN", 0x0011003C, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO100SE3BN", 0x00110034, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO110KC2BN", 0x00111040, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO110KD2BN", 0x00111039, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO110KD3BN", 0x00111038, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO110KE3BN", 0x00111030, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO110RC2BN", 0x00111043, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO110RD2BN", 0x00111044, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO110RD3BN", 0x00111045, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO110SC2BN", 0x00111042, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO110SD2BN", 0x0011103D, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO110SD3BN", 0x0011103C, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO110SE3BN", 0x00111034, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120KC2BN", 0x00112040, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120KD2BN", 0x00112039, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120KD3BN", 0x00112038, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120KE3BN", 0x00112030, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120LC2BN", 0x00112043, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120LD2BN", 0x0011203F, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120LD3BN", 0x0011203E, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120LE3BN", 0x00112036, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120SC2BN", 0x00112042, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120SD2BN", 0x0011203D, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120SD3BN", 0x0011203C, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO120SE3BN", 0x00112034, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO130KC2BN", 0x00113040, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO130KD2BN", 0x00113039, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO130KD3BN", 0x00113038, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO130KE3BN", 0x00113030, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO130SC2BN", 0x00113042, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO130SD2BN", 0x0011303D, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO130SD3BN", 0x0011303C, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO130SE3BN", 0x00113034, NUMICRO_BANKS_GENERAL(123 * 1024, 0 * 1024, 4 * 1024, 8)}, + + /* NANO103 */ + {"NANO103SD3AE", 0x00110301, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO103LD3AE", 0x00110304, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO103ZD3AE", 0x00110307, NUMICRO_BANKS_GENERAL(64 * 1024, 0 * 1024, 4 * 1024, 8)}, + + /* NANO112AN */ + {"NANO102LB1AN", 0x00110206, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO102LC2AN", 0x00110208, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO102SC2AN", 0x00110212, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO102ZB1AN", 0x00110202, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO102ZC2AN", 0x00110204, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO112LB1AN", 0x00111202, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO112LC2AN", 0x00111204, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO112RB1AN", 0x00111210, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO112RC2AN", 0x00111212, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO112SB1AN", 0x00111206, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO112SC2AN", 0x00111208, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NANO112VC2AN", 0x00111216, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 4 * 1024, 8)}, + + /* NUC029AN */ + {"NUC029LAN", 0x00295A00, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 4)}, + {"NUC029TAN", 0x00295804, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 4)}, + + /* NUC029AE */ + {"NUC029FAE", 0x00295415, NUMICRO_BANKS_GENERAL(16 * 1024, 0 * 1024, 2 * 1024, 8)}, + + /* NUC100AN */ + {"NUC100LD3AN", 0x00010003, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100LE3AN", 0x00010000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC100RD3AN", 0x00010012, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100RE3AN", 0x00010009, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC100VD2AN", 0x00010022, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100VD3AN", 0x00010021, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100VE3AN", 0x00100018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC120LD3AN", 0x00012003, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120LE3AN", 0x00120000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC120RD3AN", 0x00012012, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120RE3AN", 0x00012009, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC120VD2AN", 0x00012022, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120VD3AN", 0x00012021, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120VE3AN", 0x00012018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + + /* NUC100BN */ + {"NUC100LC1BN", 0x10010008, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100LD1BN", 0x10010005, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100LD2BN", 0x10010004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100RC1BN", 0x10010017, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100RD1BN", 0x10010014, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100RD2BN", 0x10010013, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120LC1BN", 0x10012008, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120LD1BN", 0x10012005, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120LD2BN", 0x10012004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120RC1BN", 0x10012017, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120RD1BN", 0x10012014, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120RD2BN", 0x10012013, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + + /* NUC100CN */ + {"NUC130LC1CN", 0x20013008, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC130LD2CN", 0x20013004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC130LE3CN", 0x20013000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC130RC1CN", 0x20013017, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC130RD2CN", 0x20013013, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC130RE3CN", 0x20013009, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC130VE3CN", 0x20013018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC140LC1CN", 0x20014008, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC140LD2CN", 0x20014004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC140LE3CN", 0x20014000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC140RC1CN", 0x20014017, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC140RD2CN", 0x20014013, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC140RE3CN", 0x20014009, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC140VE3CN", 0x20014018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + + /* NUC100DN */ + {"NUC100LC1DN", 0x30010008, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100LD1DN", 0x30010005, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100LD2DN", 0x30010004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100LD3DN", 0x30010003, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100LE3DN", 0x30010000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC100RC1DN", 0x30010017, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100RD1DN", 0x30010014, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100RD2DN", 0x30010013, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100RD3DN", 0x30010012, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100RE3DN", 0x30010009, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC100VD2DN", 0x30010022, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100VD3DN", 0x30010021, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC100VE3DN", 0x30010018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC120LC1DN", 0x30012008, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120LD1DN", 0x30012005, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120LD2DN", 0x30012004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120LD3DN", 0x30012003, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120LE3DN", 0x30012000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC120RC1DN", 0x30012035, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120RD1DN", 0x30012032, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120RD2DN", 0x30012031, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120RD3DN", 0x30012030, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120RE3DN", 0x30012027, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC120VD2DN", 0x30012022, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120VD3DN", 0x30012021, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC120VE3DN", 0x30012018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + + /* NUC121 */ + {"NUC121SC2AE", 0x00012105, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 9 * 512, 8)}, + {"NUC121LC2AE", 0x00012125, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 9 * 512, 8)}, + {"NUC121ZC2AE", 0x00012145, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 9 * 512, 8)}, + {"NUC125SC2AE", 0x00012505, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 9 * 512, 8)}, + {"NUC125LC2AE", 0x00012525, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 9 * 512, 8)}, + {"NUC125ZC2AE", 0x00012545, NUMICRO_BANKS_GENERAL(32 * 1024, 0 * 1024, 9 * 512, 8)}, + + /* NUC122 */ + {"NUC122LC1AN", 0x00012208, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC122LD2AN", 0x00012204, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC122SC1AN", 0x00012226, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC122SD2AN", 0x00012222, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC122ZC1AN", 0x00012235, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC122ZD2AN", 0x00012231, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + + /* NUC123AN */ + {"NUC123LC2AN1", 0x00012325, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC123LD4AN0", 0x00012335, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC123SC2AN1", 0x00012305, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC123SD4AN0", 0x00012315, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC123ZC2AN1", 0x00012345, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC123ZD4AN0", 0x00012355, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + + /* NUC123AE */ + {"NUC123LC2AE1", 0x10012325, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC123LD4AE0", 0x10012335, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC123SC2AE1", 0x10012305, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC123SD4AE0", 0x10012315, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC123ZC2AE1", 0x10012345, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC123ZD4AE0", 0x10012355, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + + /* NUC131AE */ + {"NUC131LC2AE", 0x10013103, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC131LD2AE", 0x10013100, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC131SC2AE", 0x10013113, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC131SD2AE", 0x10013110, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + + /* NUC200/220AN */ + {"NUC200LC2AN", 0x00020007, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC200LD2AN", 0x00020004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC200LE3AN", 0x00020000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC200SC2AN", 0x00020034, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC200SD2AN", 0x00020031, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC200SE3AN", 0x00020027, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC200VE3AN", 0x00020018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC220LC2AN", 0x00022007, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC220LD2AN", 0x00022004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC220LE3AN", 0x00022000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC220SC2AN", 0x00022034, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC220SD2AN", 0x00022031, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 4 * 1024, 8)}, + {"NUC220SE3AN", 0x00022027, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"NUC220VE3AN", 0x00022018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + + /* NUC230/240AE */ + {"NUC230LC2AE", 0x10023007, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 8 * 1024, 8)}, + {"NUC230LD2AE", 0x10023004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 8 * 1024, 8)}, + {"NUC230LE3AE", 0x10023000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, + {"NUC230SC2AE", 0x10023034, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 8 * 1024, 8)}, + {"NUC230SD2AE", 0x10023031, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 8 * 1024, 8)}, + {"NUC230SE3AE", 0x10023027, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, + {"NUC230VE3AE", 0x10023018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, + {"NUC240LC2AE", 0x10024007, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 8 * 1024, 8)}, + {"NUC240LD2AE", 0x10024004, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 8 * 1024, 8)}, + {"NUC240LE3AE", 0x10024000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, + {"NUC240SC2AE", 0x10024034, NUMICRO_BANKS_GENERAL(32 * 1024, 4 * 1024, 8 * 1024, 8)}, + {"NUC240SD2AE", 0x10024031, NUMICRO_BANKS_GENERAL(64 * 1024, 4 * 1024, 8 * 1024, 8)}, + {"NUC240SE3AE", 0x10024027, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, + {"NUC240VE3AE", 0x10024018, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 8 * 1024, 8)}, + + /* M451 */ + {"M451LC3AE", 0x00945101, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M451LD3AE", 0x00945100, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M451LE6AE", 0x00845101, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M451LG6AE", 0x00845100, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M451MLC3AE", 0x00945001, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M451MLD3AE", 0x00945000, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M451MLE6AE", 0x00845001, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M451MLG6AE", 0x00845000, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M451MSC3AE", 0x00945011, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M451MSD3AE", 0x00945010, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M451RC3AE", 0x00945121, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M451RD3AE", 0x00945120, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M451RE6AE", 0x00845121, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M451RG6AE", 0x00845120, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M451VE6AE", 0x00845131, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M451VG6AE", 0x00845130, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M452LC3AE", 0x00945201, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M452LD3AE", 0x00945200, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M452LE6AE", 0x00845201, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M452LG6AE", 0x00845200, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M452RD3AE", 0x00945220, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M452RE6AE", 0x00845221, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M452RG6AE", 0x00845220, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M453LC3AE", 0x00945301, NUMICRO_BANKS_GENERAL(40 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M453LD3AE", 0x00945300, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M453LE6AE", 0x00845301, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M453LG6AE", 0x00845300, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M453RD3AE", 0x00945320, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M453RE6AE", 0x00845321, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M453RG6AE", 0x00845320, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M453VD3AE", 0x00945330, NUMICRO_BANKS_GENERAL(72 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M453VE6AE", 0x00845331, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M453VG6AE", 0x00845330, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M4TKVG6AE", 0x00845430, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M4TKVE6AE", 0x00845431, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M4TKRG6AE", 0x00845420, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M4TKRE6AE", 0x00845421, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M4TKLG6AE", 0x00845400, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 4 * 1024, 8)}, + {"M4TKLE6AE", 0x00845401, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 4 * 1024, 8)}, + + /* NUC442_472 */ + {"NUC442JG8AE", 0x00044203, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, + {"NUC442JI8AE", 0x00044201, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, + {"NUC442KG8AE", 0x00044206, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, + {"NUC442KI8AE", 0x00044204, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, + {"NUC442RG8AE", 0x00044212, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, + {"NUC442RI8AE", 0x00044210, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, + {"NUC442VG8AE", 0x00044209, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, + {"NUC442VI8AE", 0x00044207, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, + {"NUC472HG8AE", 0x00047203, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, + {"NUC472HI8AE", 0x00047201, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, + {"NUC472JG8AE", 0x00047206, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, + {"NUC472JI8AE", 0x00047204, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, + {"NUC472KG8AE", 0x00047209, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, + {"NUC472KI8AE", 0x00047207, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, + {"NUC472VG8AE", 0x00047212, NUMICRO_BANKS_GENERAL(256 * 1024, 0 * 1024, 16 * 1024, 16)}, + {"NUC472VI8AE", 0x00047210, NUMICRO_BANKS_GENERAL(512 * 1024, 0 * 1024, 16 * 1024, 16)}, + + {"UNKNOWN", 0x00000000, NUMICRO_BANKS_GENERAL(128 * 1024, 0 * 1024, 16 * 1024, 8)}, }; /* Private bank information for NuMicro. */ @@ -1136,32 +535,53 @@ struct numicro_flash_bank { const struct numicro_cpu_type *cpu; }; +/* Private variables */ +static uint32_t m_page_size = NUMICRO_PAGESIZE; +static uint32_t m_address_bias_offset; + /* Private methods */ +static int numicro_get_arm_arch(struct target *target) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + + if (armv7m->arm.arch != ARM_ARCH_V6M) { + LOG_DEBUG("NuMicro arm architecture: armv7m\n"); + m_page_size = NUMICRO_PAGESIZE * 4; + m_address_bias_offset = 0x10000000; + } else { + LOG_DEBUG("NuMicro arm architecture: armv6m\n"); + m_page_size = NUMICRO_PAGESIZE; + m_address_bias_offset = 0x0; + } + + return ERROR_OK; +} + static int numicro_reg_unlock(struct target *target) { uint32_t is_protected; int retval = ERROR_OK; /* Check to see if NUC is register unlocked or not */ - retval = target_read_u32(target, NUMICRO_SYS_WRPROT, &is_protected); + retval = target_read_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, &is_protected); if (retval != ERROR_OK) return retval; LOG_DEBUG("protected = 0x%08" PRIx32 "", is_protected); if (is_protected == 0) { /* means protected - so unlock it */ /* unlock flash registers */ - retval = target_write_u32(target, NUMICRO_SYS_WRPROT, REG_KEY1); + retval = target_write_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, REG_KEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, NUMICRO_SYS_WRPROT, REG_KEY2); + retval = target_write_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, REG_KEY2); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, NUMICRO_SYS_WRPROT, REG_KEY3); + retval = target_write_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, REG_KEY3); if (retval != ERROR_OK) return retval; } /* Check that unlock worked */ - retval = target_read_u32(target, NUMICRO_SYS_WRPROT, &is_protected); + retval = target_read_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, &is_protected); if (retval != ERROR_OK) return retval; @@ -1189,27 +609,27 @@ static int numicro_init_isp(struct target *target) return retval; /* Enable ISP/SRAM/TICK Clock */ - retval = target_read_u32(target, NUMICRO_SYSCLK_AHBCLK, ®_stat); + retval = target_read_u32(target, NUMICRO_SYSCLK_AHBCLK - m_address_bias_offset, ®_stat); if (retval != ERROR_OK) return retval; reg_stat |= AHBCLK_ISP_EN | AHBCLK_SRAM_EN | AHBCLK_TICK_EN; - retval = target_write_u32(target, NUMICRO_SYSCLK_AHBCLK, reg_stat); + retval = target_write_u32(target, NUMICRO_SYSCLK_AHBCLK - m_address_bias_offset, reg_stat); if (retval != ERROR_OK) return retval; /* Enable ISP */ - retval = target_read_u32(target, NUMICRO_FLASH_ISPCON, ®_stat); + retval = target_read_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, ®_stat); if (retval != ERROR_OK) return retval; reg_stat |= ISPCON_ISPFF | ISPCON_LDUEN | ISPCON_APUEN | ISPCON_CFGUEN | ISPCON_ISPEN; - retval = target_write_u32(target, NUMICRO_FLASH_ISPCON, reg_stat); + retval = target_write_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, reg_stat); if (retval != ERROR_OK) return retval; /* Write one to undocumented flash control register */ - retval = target_write_u32(target, NUMICRO_FLASH_CHEAT, 1); + retval = target_write_u32(target, NUMICRO_FLASH_CHEAT - m_address_bias_offset, 1); if (retval != ERROR_OK) return retval; @@ -1221,29 +641,28 @@ static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t ad uint32_t timeout, status; int retval = ERROR_OK; - retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD, cmd); + retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD - m_address_bias_offset, cmd); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, NUMICRO_FLASH_ISPDAT, wdata); + retval = target_write_u32(target, NUMICRO_FLASH_ISPDAT - m_address_bias_offset, wdata); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, NUMICRO_FLASH_ISPADR, addr); + retval = target_write_u32(target, NUMICRO_FLASH_ISPADR - m_address_bias_offset, addr); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG, ISPTRG_ISPGO); + retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG - m_address_bias_offset, ISPTRG_ISPGO); if (retval != ERROR_OK) return retval; /* Wait for busy to clear - check the GO flag */ timeout = 100; for (;;) { - retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG, &status); + retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG - m_address_bias_offset, &status); if (retval != ERROR_OK) return retval; - LOG_DEBUG("status: 0x%" PRIx32 "", status); if ((status & (ISPTRG_ISPGO)) == 0) break; if (timeout-- <= 0) { @@ -1253,79 +672,28 @@ static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t ad busy_sleep(1); /* can use busy sleep for short times. */ } - retval = target_read_u32(target, NUMICRO_FLASH_ISPDAT, rdata); + retval = target_read_u32(target, NUMICRO_FLASH_ISPDAT - m_address_bias_offset, rdata); if (retval != ERROR_OK) return retval; return ERROR_OK; } - /* NuMicro Program-LongWord Microcodes */ static const uint8_t numicro_flash_write_code[] = { - /* Params: - * r0 - workarea buffer / result - * r1 - target address - * r2 - wordcount - * Clobbered: - * r4 - tmp - * r5 - tmp - * r6 - tmp - * r7 - tmp - */ - - /* .L1: */ - /* for(register uint32_t i=0;i<wcount;i++){ */ - 0x04, 0x1C, /* mov r4, r0 */ - 0x00, 0x23, /* mov r3, #0 */ - /* .L2: */ - 0x0D, 0x1A, /* sub r5, r1, r0 */ - 0x67, 0x19, /* add r7, r4, r7 */ - 0x93, 0x42, /* cmp r3, r2 */ - 0x0C, 0xD0, /* beq .L7 */ - /* .L4: */ - /* NUMICRO_FLASH_ISPADR = faddr; */ - 0x08, 0x4E, /* ldr r6, .L8 */ - 0x37, 0x60, /* str r7, [r6] */ - /* NUMICRO_FLASH_ISPDAT = *pLW; */ - 0x80, 0xCC, /* ldmia r4!, {r7} */ - 0x08, 0x4D, /* ldr r5, .L8+4 */ - 0x2F, 0x60, /* str r7, [r5] */ - /* faddr += 4; */ - /* pLW++; */ - /* Trigger write action */ - /* NUMICRO_FLASH_ISPTRG = ISPTRG_ISPGO; */ - 0x08, 0x4D, /* ldr r5, .L8+8 */ - 0x01, 0x26, /* mov r6, #1 */ - 0x2E, 0x60, /* str r6, [r5] */ - /* .L3: */ - /* while((NUMICRO_FLASH_ISPTRG & ISPTRG_ISPGO) == ISPTRG_ISPGO){}; */ - 0x2F, 0x68, /* ldr r7, [r5] */ - 0xFF, 0x07, /* lsl r7, r7, #31 */ - 0xFC, 0xD4, /* bmi .L3 */ - - 0x01, 0x33, /* add r3, r3, #1 */ - 0xEE, 0xE7, /* b .L2 */ - /* .L7: */ - /* return (NUMICRO_FLASH_ISPCON & ISPCON_ISPFF); */ - 0x05, 0x4B, /* ldr r3, .L8+12 */ - 0x18, 0x68, /* ldr r0, [r3] */ - 0x40, 0x21, /* mov r1, #64 */ - 0x08, 0x40, /* and r0, r1 */ - /* .L9: */ - 0x00, 0xBE, /* bkpt #0 */ - /* .L8: */ - 0x04, 0xC0, 0x00, 0x50,/* .word 1342226436 */ - 0x08, 0xC0, 0x00, 0x50,/* .word 1342226440 */ - 0x10, 0xC0, 0x00, 0x50,/* .word 1342226448 */ - 0x00, 0xC0, 0x00, 0x50 /* .word 1342226432 */ +#include "../../../contrib/loaders/flash/numicro/numicro_m0.inc" +}; + +static const uint8_t numicro_m4_flash_write_code[] = { +#include "../../../contrib/loaders/flash/numicro/numicro_m4.inc" }; + /* Program LongWord Block Write */ static int numicro_writeblock(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; - uint32_t buffer_size = 1024; /* Default minimum value */ + uint32_t buffer_size = 1024; /* Default minimum value */ struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; @@ -1353,18 +721,34 @@ static int numicro_writeblock(struct flash_bank *bank, const uint8_t *buffer, LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } + /* Difference between M0 and M4 */ + if (m_page_size == NUMICRO_PAGESIZE) { + /* allocate working area with flash programming code */ + if (target_alloc_working_area(target, sizeof(numicro_flash_write_code), + &write_algorithm) != ERROR_OK) { + LOG_WARNING("no working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } - /* allocate working area with flash programming code */ - if (target_alloc_working_area(target, sizeof(numicro_flash_write_code), + retval = target_write_buffer(target, write_algorithm->address, + sizeof(numicro_flash_write_code), numicro_flash_write_code); + if (retval != ERROR_OK) + return retval; + } else { /* for M4 */ + /* allocate working area with flash programming code */ + if (target_alloc_working_area(target, sizeof(numicro_m4_flash_write_code), &write_algorithm) != ERROR_OK) { - LOG_WARNING("no working area available, can't do block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } + LOG_WARNING("no working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } - retval = target_write_buffer(target, write_algorithm->address, - sizeof(numicro_flash_write_code), numicro_flash_write_code); - if (retval != ERROR_OK) - return retval; + retval = target_write_buffer(target, write_algorithm->address, + sizeof(numicro_m4_flash_write_code), numicro_m4_flash_write_code); + if (retval != ERROR_OK) + return retval; + + buffer_size = m_page_size; + } /* memory buffer */ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { @@ -1385,13 +769,6 @@ static int numicro_writeblock(struct flash_bank *bank, const uint8_t *buffer, init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* faddr */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* number of words to program */ - struct armv7m_common *armv7m = target_to_armv7m(target); - if (!armv7m) { - /* something is very wrong if armv7m is NULL */ - LOG_ERROR("unable to get armv7m target"); - return retval; - } - /* write code buffer and use Flash programming code within NuMicro */ /* Set breakpoint to 0 with time-out of 1000 ms */ while (count > 0) { @@ -1442,13 +819,14 @@ static int numicro_protect_check(struct flash_bank *bank) LOG_INFO("Nuvoton NuMicro: Flash Lock Check..."); + numicro_get_arm_arch(target); retval = numicro_init_isp(target); if (retval != ERROR_OK) return retval; /* Read CONFIG0,CONFIG1 */ - numicro_fmc_cmd(target, ISPCMD_READ, NUMICRO_CONFIG0, 0 , &config[0]); - numicro_fmc_cmd(target, ISPCMD_READ, NUMICRO_CONFIG1, 0 , &config[1]); + numicro_fmc_cmd(target, ISPCMD_READ, NUMICRO_CONFIG0 - m_address_bias_offset, 0, &config[0]); + numicro_fmc_cmd(target, ISPCMD_READ, NUMICRO_CONFIG1 - m_address_bias_offset, 0, &config[1]); LOG_DEBUG("CONFIG0: 0x%" PRIx32 ",CONFIG1: 0x%" PRIx32 "", config[0], config[1]); @@ -1488,31 +866,34 @@ static int numicro_erase(struct flash_bank *bank, unsigned int first, LOG_INFO("Nuvoton NuMicro: Sector Erase ... (%u to %u)", first, last); + numicro_get_arm_arch(target); retval = numicro_init_isp(target); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD, ISPCMD_ERASE); + retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD - m_address_bias_offset, ISPCMD_ERASE); if (retval != ERROR_OK) return retval; for (unsigned int i = first; i <= last; i++) { - LOG_DEBUG("erasing sector %u at address " TARGET_ADDR_FMT, i, - bank->base + bank->sectors[i].offset); - retval = target_write_u32(target, NUMICRO_FLASH_ISPADR, bank->base + bank->sectors[i].offset); + LOG_DEBUG("erasing sector %u at address " TARGET_ADDR_FMT, i, bank->base + bank->sectors[i].offset); + retval = target_write_u32(target, + NUMICRO_FLASH_ISPADR - m_address_bias_offset, + bank->base + bank->sectors[i].offset); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG, ISPTRG_ISPGO); /* This is the only bit available */ + retval = target_write_u32(target, + NUMICRO_FLASH_ISPTRG - m_address_bias_offset, + ISPTRG_ISPGO); /* This is the only bit available */ if (retval != ERROR_OK) return retval; /* wait for busy to clear - check the GO flag */ timeout = 100; for (;;) { - retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG, &status); + retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG - m_address_bias_offset, &status); if (retval != ERROR_OK) return retval; - LOG_DEBUG("status: 0x%" PRIx32 "", status); if (status == 0) break; if (timeout-- <= 0) { @@ -1523,13 +904,13 @@ static int numicro_erase(struct flash_bank *bank, unsigned int first, } /* check for failure */ - retval = target_read_u32(target, NUMICRO_FLASH_ISPCON, &status); + retval = target_read_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, &status); if (retval != ERROR_OK) return retval; if ((status & ISPCON_ISPFF) != 0) { LOG_DEBUG("failure: 0x%" PRIx32 "", status); /* if bit is set, then must write to it to clear it. */ - retval = target_write_u32(target, NUMICRO_FLASH_ISPCON, (status | ISPCON_ISPFF)); + retval = target_write_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, (status | ISPCON_ISPFF)); if (retval != ERROR_OK) return retval; } @@ -1556,11 +937,12 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer, LOG_INFO("Nuvoton NuMicro: Flash Write ..."); + numicro_get_arm_arch(target); retval = numicro_init_isp(target); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD, ISPCMD_WRITE); + retval = target_write_u32(target, NUMICRO_FLASH_ISPCMD - m_address_bias_offset, ISPCMD_WRITE); if (retval != ERROR_OK) return retval; @@ -1580,26 +962,34 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer, /* program command */ for (uint32_t i = 0; i < count; i += 4) { + /* write 4 bytes each time with 0xff padding to avoid unaligned case */ + uint8_t padding[4] = {0xff, 0xff, 0xff, 0xff}; + memcpy(padding, buffer + i, MIN(4, count - i)); - LOG_DEBUG("write longword @ %08" PRIX32, offset + i); - - retval = target_write_u32(target, NUMICRO_FLASH_ISPADR, bank->base + offset + i); + retval = target_write_u32(target, + NUMICRO_FLASH_ISPADR - m_address_bias_offset, + bank->base + offset + i); if (retval != ERROR_OK) return retval; - retval = target_write_memory(target, NUMICRO_FLASH_ISPDAT, 4, 1, buffer + i); + retval = target_write_memory(target, + NUMICRO_FLASH_ISPDAT - m_address_bias_offset, + 4, 1, padding); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG, ISPTRG_ISPGO); + retval = target_write_u32(target, + NUMICRO_FLASH_ISPTRG - m_address_bias_offset, + ISPTRG_ISPGO); if (retval != ERROR_OK) return retval; /* wait for busy to clear - check the GO flag */ timeout = 100; for (;;) { - retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG, &status); + retval = target_read_u32(target, + NUMICRO_FLASH_ISPTRG - m_address_bias_offset, + &status); if (retval != ERROR_OK) return retval; - LOG_DEBUG("status: 0x%" PRIx32 "", status); if (status == 0) break; if (timeout-- <= 0) { @@ -1613,13 +1003,15 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer, } /* check for failure */ - retval = target_read_u32(target, NUMICRO_FLASH_ISPCON, &status); + retval = target_read_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, &status); if (retval != ERROR_OK) return retval; if ((status & ISPCON_ISPFF) != 0) { LOG_DEBUG("failure: 0x%" PRIx32 "", status); /* if bit is set, then must write to it to clear it. */ - retval = target_write_u32(target, NUMICRO_FLASH_ISPCON, (status | ISPCON_ISPFF)); + retval = target_write_u32(target, + NUMICRO_FLASH_ISPCON - m_address_bias_offset, + (status | ISPCON_ISPFF)); if (retval != ERROR_OK) return retval; } else { @@ -1637,8 +1029,9 @@ static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_ uint32_t part_id; int retval = ERROR_OK; + numicro_get_arm_arch(target); /* Read NuMicro PartID */ - retval = target_read_u32(target, NUMICRO_SYS_BASE, &part_id); + retval = target_read_u32(target, NUMICRO_SYS_BASE - m_address_bias_offset, &part_id); if (retval != ERROR_OK) { LOG_WARNING("NuMicro flash driver: Failed to Get PartID\n"); return ERROR_FLASH_OPERATION_FAILED; @@ -1690,7 +1083,7 @@ static int numicro_probe(struct flash_bank *bank) return ERROR_FLASH_OPERATION_FAILED; } - num_pages = flash_size / NUMICRO_PAGESIZE; + num_pages = flash_size / m_page_size; bank->num_sectors = num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); @@ -1698,10 +1091,10 @@ static int numicro_probe(struct flash_bank *bank) for (int i = 0; i < num_pages; i++) { bank->sectors[i].offset = offset; - bank->sectors[i].size = NUMICRO_PAGESIZE; + bank->sectors[i].size = m_page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; - offset += NUMICRO_PAGESIZE; + offset += m_page_size; } struct numicro_flash_bank *numicro_info = bank->driver_priv; @@ -1740,7 +1133,6 @@ FLASH_BANK_COMMAND_HANDLER(numicro_flash_bank_command) bank->write_start_alignment = bank->write_end_alignment = 4; return ERROR_OK; - } COMMAND_HANDLER(numicro_handle_read_isp_command) @@ -1756,6 +1148,7 @@ COMMAND_HANDLER(numicro_handle_read_isp_command) struct target *target = get_current_target(CMD_CTX); + numicro_get_arm_arch(target); retval = numicro_init_isp(target); if (retval != ERROR_OK) return retval; @@ -1783,6 +1176,7 @@ COMMAND_HANDLER(numicro_handle_write_isp_command) struct target *target = get_current_target(CMD_CTX); + numicro_get_arm_arch(target); retval = numicro_init_isp(target); if (retval != ERROR_OK) return retval; @@ -1805,6 +1199,7 @@ COMMAND_HANDLER(numicro_handle_chip_erase_command) struct target *target = get_current_target(CMD_CTX); + numicro_get_arm_arch(target); retval = numicro_init_isp(target); if (retval != ERROR_OK) return retval; diff --git a/src/flash/nor/ocl.c b/src/flash/nor/ocl.c index 813537d446..e00c365edd 100644 --- a/src/flash/nor/ocl.c +++ b/src/flash/nor/ocl.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/ocl.h b/src/flash/nor/ocl.h index b1fe308f26..4c864956f9 100644 --- a/src/flash/nor/ocl.h +++ b/src/flash/nor/ocl.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_OCL_H diff --git a/src/flash/nor/pic32mx.c b/src/flash/nor/pic32mx.c index 31433e03fc..0f3937cfc2 100644 --- a/src/flash/nor/pic32mx.c +++ b/src/flash/nor/pic32mx.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by John McCarthy * * jgmcc@magma.ca * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -770,7 +759,7 @@ static int pic32mx_probe(struct flash_bank *bank) } } - LOG_INFO("flash size = %" PRIu32 "kbytes", num_pages / 1024); + LOG_INFO("flash size = %" PRIu32 " KiB", num_pages / 1024); free(bank->sectors); @@ -877,10 +866,8 @@ COMMAND_HANDLER(pic32mx_handle_unlock_command) struct mips_ejtag *ejtag_info; int timeout = 10; - if (CMD_ARGC < 1) { - command_print(CMD, "pic32mx unlock <bank>"); + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); @@ -943,7 +930,7 @@ static const struct command_registration pic32mx_exec_command_handlers[] = { .name = "unlock", .handler = pic32mx_handle_unlock_command, .mode = COMMAND_EXEC, - .usage = "[bank_id]", + .usage = "bank_id", .help = "Unlock/Erase entire device.", }, COMMAND_REGISTRATION_DONE diff --git a/src/flash/nor/psoc4.c b/src/flash/nor/psoc4.c index 0a2702ab5d..1064fa93d3 100644 --- a/src/flash/nor/psoc4.c +++ b/src/flash/nor/psoc4.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -10,19 +12,6 @@ * * * Copyright (C) 2014 by Tomas Vanek (PSoC 4 support derived from STM32) * * vanekt@fbl.cz * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -662,9 +651,6 @@ static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer, if (row_offset) memset(row_buffer, bank->default_padded_value, row_offset); - bool save_poll = jtag_poll_get_enabled(); - jtag_poll_set_enabled(false); - while (count) { uint32_t chunk_size = psoc4_info->row_size - row_offset; if (chunk_size > count) { @@ -704,8 +690,6 @@ static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer, } cleanup: - jtag_poll_set_enabled(save_poll); - free(sysrq_buffer); return retval; } @@ -785,7 +769,7 @@ static int psoc4_probe(struct flash_bank *bank) num_macros++; } - LOG_DEBUG("SPCIF geometry: %" PRIu32 " kb flash, row %" PRIu32 " bytes.", + LOG_DEBUG("SPCIF geometry: %" PRIu32 " KiB flash, row %" PRIu32 " bytes.", flash_size_in_kb, row_size); /* if the user sets the size manually then ignore the probed value @@ -795,11 +779,11 @@ static int psoc4_probe(struct flash_bank *bank) flash_size_in_kb = psoc4_info->user_bank_size / 1024; } - char macros_txt[20] = ""; + char macros_txt[22] = ""; if (num_macros > 1) snprintf(macros_txt, sizeof(macros_txt), " in %" PRIu32 " macros", num_macros); - LOG_INFO("flash size = %" PRIu32 " kbytes%s", flash_size_in_kb, macros_txt); + LOG_INFO("flash size = %" PRIu32 " KiB%s", flash_size_in_kb, macros_txt); /* calculate number of pages */ uint32_t num_rows = flash_size_in_kb * 1024 / row_size; diff --git a/src/flash/nor/psoc5lp.c b/src/flash/nor/psoc5lp.c index f383213ba6..407efbcab3 100644 --- a/src/flash/nor/psoc5lp.c +++ b/src/flash/nor/psoc5lp.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * PSoC 5LP flash driver * * Copyright (c) 2016 Andreas Färber - * - * 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/>. */ #ifdef HAVE_CONFIG_H @@ -822,24 +811,8 @@ FLASH_BANK_COMMAND_HANDLER(psoc5lp_nvl_flash_bank_command) return ERROR_OK; } -static const struct command_registration psoc5lp_nvl_exec_command_handlers[] = { - COMMAND_REGISTRATION_DONE -}; - -static const struct command_registration psoc5lp_nvl_command_handlers[] = { - { - .name = "psoc5lp_nvl", - .mode = COMMAND_ANY, - .help = "PSoC 5LP NV Latch command group", - .usage = "", - .chain = psoc5lp_nvl_exec_command_handlers, - }, - COMMAND_REGISTRATION_DONE -}; - const struct flash_driver psoc5lp_nvl_flash = { .name = "psoc5lp_nvl", - .commands = psoc5lp_nvl_command_handlers, .flash_bank_command = psoc5lp_nvl_flash_bank_command, .info = psoc5lp_nvl_get_info_command, .probe = psoc5lp_nvl_probe, @@ -1021,24 +994,8 @@ FLASH_BANK_COMMAND_HANDLER(psoc5lp_eeprom_flash_bank_command) return ERROR_OK; } -static const struct command_registration psoc5lp_eeprom_exec_command_handlers[] = { - COMMAND_REGISTRATION_DONE -}; - -static const struct command_registration psoc5lp_eeprom_command_handlers[] = { - { - .name = "psoc5lp_eeprom", - .mode = COMMAND_ANY, - .help = "PSoC 5LP EEPROM command group", - .usage = "", - .chain = psoc5lp_eeprom_exec_command_handlers, - }, - COMMAND_REGISTRATION_DONE -}; - const struct flash_driver psoc5lp_eeprom_flash = { .name = "psoc5lp_eeprom", - .commands = psoc5lp_eeprom_command_handlers, .flash_bank_command = psoc5lp_eeprom_flash_bank_command, .info = psoc5lp_eeprom_get_info_command, .probe = psoc5lp_eeprom_probe, diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c index c6166aff8f..b7ba1027ed 100644 --- a/src/flash/nor/psoc6.c +++ b/src/flash/nor/psoc6.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * * * Copyright (C) 2018 by Bohdan Tymkiv * * bohdan.tymkiv@cypress.com bohdan200@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -602,8 +591,7 @@ static int psoc6_probe(struct flash_bank *bank) unsigned int num_sectors = bank_size / row_sz; bank->size = bank_size; - bank->chip_width = 4; - bank->bus_width = 4; + bank->erased_value = 0; bank->default_padded_value = 0; diff --git a/src/flash/nor/qn908x.c b/src/flash/nor/qn908x.c new file mode 100644 index 0000000000..8cd7a2f04a --- /dev/null +++ b/src/flash/nor/qn908x.c @@ -0,0 +1,1197 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*************************************************************************** + * Copyright (C) 2020 iosabi * + * iosabi <iosabi@protonmail.com> * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" + +#include <helper/binarybuffer.h> +#include <helper/bits.h> +#include <helper/crc32.h> +#include <helper/time_support.h> +#include <helper/types.h> + +/* The QN908x has two flash regions, one is the main flash region holding the + * user code and the second one is a small (0x800 bytes) "Flash information + * page" that can't be written to by the user. This page contains information + * programmed at the factory. + * + * The main flash region is normally 512 KiB, there's a field in the "Flash + * information page" that allows to specify for 256 KiB size chips. However, at + * the time of writing, none of the variants in the market have 256 KiB. + * + * The flash is divided into blocks of 256 KiB each, therefore containing two + * blocks. A block is subdivided into pages, of 2048 bytes. A page is the + * smallest region that can be erased or protected independently, although it + * is also possible to erase a whole block or both blocks. A page is subdivided + * into 8 rows of 64 words (32-bit words). The word subdivision is only + * relevant because DMA can write multiple words in the same row in the same + * flash program operation. + * + * For the Flash information page we are only interested in the last + * 0x100 bytes which contain a CRC-32 checksum of that 0x100 bytes long region + * and a field stating the size of the flash. This is also a good check that + * we are dealing with the right chip/flash configuration and is used in the + * probe() function. + */ +#define QN908X_FLASH_BASE 0x01000000 + +#define QN908X_FLASH_PAGE_SIZE 2048 +#define QN908X_FLASH_PAGES_PER_BLOCK 128 +#define QN908X_FLASH_MAX_BLOCKS 2 +#define QN908X_FLASH_BLOCK_SIZE \ + (QN908X_FLASH_PAGES_PER_BLOCK * QN908X_FLASH_PAGE_SIZE) +#define QN908X_FLASH_IRQ_VECTOR_CHECKSUM_POS 0x1c +#define QN908X_FLASH_IRQ_VECTOR_CHECKSUM_SIZE 4 +#define QN908X_FLASH_IRQ_VECTOR_CHECKSUM_END \ + (QN908X_FLASH_IRQ_VECTOR_CHECKSUM_POS + QN908X_FLASH_IRQ_VECTOR_CHECKSUM_SIZE) + + +/* Flash information page memory fields. */ +#define QN908X_INFO_PAGE_BASE 0x210b0000u +#define QN908X_INFO_PAGE_CRC32 (QN908X_INFO_PAGE_BASE + 0x700) +#define QN908X_INFO_PAGE_CRC_START (QN908X_INFO_PAGE_BASE + 0x704) +#define QN908X_INFO_PAGE_BOOTLOADER_VER (QN908X_INFO_PAGE_BASE + 0x704) +#define QN908X_INFO_PAGE_FLASH_SIZE (QN908X_INFO_PAGE_BASE + 0x708) +#define QN908X_INFO_PAGE_BLUETOOTH_ADDR (QN908X_INFO_PAGE_BASE + 0x7fa) +#define QN908X_INFO_PAGE_CRC_END (QN908X_INFO_PAGE_BASE + 0x800) + + +/* Possible values of the QN908X_INFO_PAGE_FLASH_SIZE field. */ +enum qn908x_info_page_flash_size { + QN908X_FLASH_SIZE_512K = 0xfffff0ff, + QN908X_FLASH_SIZE_256K = 0xffffe0ff, +}; + +/* QN908x "Flash memory controller", described in section 28 of the user + * manual. In the NXP SDK this peripheral is called "FLASH", however we use the + * name "FMC" (Flash Memory Controller) here when referring to the controller + * to avoid confusion with other "flash" terms in OpenOCD. */ +#define QN908X_FMC_BASE 0x40081000u +#define QN908X_FMC_INI_RD_EN (QN908X_FMC_BASE + 0x00) +#define QN908X_FMC_ERASE_CTRL (QN908X_FMC_BASE + 0x04) +#define QN908X_FMC_ERASE_TIME (QN908X_FMC_BASE + 0x08) +#define QN908X_FMC_TIME_CTRL (QN908X_FMC_BASE + 0x0c) +#define QN908X_FMC_SMART_CTRL (QN908X_FMC_BASE + 0x10) +#define QN908X_FMC_INT_STAT (QN908X_FMC_BASE + 0x18) +#define QN908X_FMC_LOCK_STAT_0 (QN908X_FMC_BASE + 0x20) +#define QN908X_FMC_LOCK_STAT_1 (QN908X_FMC_BASE + 0x24) +#define QN908X_FMC_LOCK_STAT_2 (QN908X_FMC_BASE + 0x28) +#define QN908X_FMC_LOCK_STAT_3 (QN908X_FMC_BASE + 0x2c) +#define QN908X_FMC_LOCK_STAT_4 (QN908X_FMC_BASE + 0x30) +#define QN908X_FMC_LOCK_STAT_5 (QN908X_FMC_BASE + 0x34) +#define QN908X_FMC_LOCK_STAT_6 (QN908X_FMC_BASE + 0x38) +#define QN908X_FMC_LOCK_STAT_7 (QN908X_FMC_BASE + 0x3c) +#define QN908X_FMC_LOCK_STAT_8 (QN908X_FMC_BASE + 0x40) +#define QN908X_FMC_STATUS1 (QN908X_FMC_BASE + 0x48) +#define QN908X_FMC_DEBUG_PASSWORD (QN908X_FMC_BASE + 0xa8) +#define QN908X_FMC_ERASE_PASSWORD (QN908X_FMC_BASE + 0xac) + +#define QN908X_FMC_INI_RD_EN_INI_RD_EN_MASK BIT(0) + +#define QN908X_FMC_STATUS1_FSH_ERA_BUSY_L_MASK BIT(9) +#define QN908X_FMC_STATUS1_FSH_WR_BUSY_L_MASK BIT(10) +#define QN908X_FMC_STATUS1_FSH_ERA_BUSY_H_MASK BIT(12) +#define QN908X_FMC_STATUS1_FSH_WR_BUSY_H_MASK BIT(13) +#define QN908X_FMC_STATUS1_INI_RD_DONE_MASK BIT(15) +#define QN908X_FMC_STATUS1_FSH_STA_MASK BIT(26) + +#define QN908X_FMC_ERASE_CTRL_PAGE_IDXL_SHIFT 0 +#define QN908X_FMC_ERASE_CTRL_PAGE_IDXH_SHIFT 8 +#define QN908X_FMC_ERASE_CTRL_HALF_ERASEL_EN_SHIFT 28 +#define QN908X_FMC_ERASE_CTRL_HALF_ERASEH_EN_SHIFT 29 +#define QN908X_FMC_ERASE_CTRL_PAGE_ERASEL_EN_SHIFT 30 +#define QN908X_FMC_ERASE_CTRL_PAGE_ERASEH_EN_SHIFT 31 + +#define QN908X_FMC_INT_STAT_AHBL_INT_MASK BIT(0) +#define QN908X_FMC_INT_STAT_LOCKL_INT_MASK BIT(1) +#define QN908X_FMC_INT_STAT_ERASEL_INT_MASK BIT(2) +#define QN908X_FMC_INT_STAT_WRITEL_INT_MASK BIT(3) +#define QN908X_FMC_INT_STAT_WR_BUFL_INT_MASK BIT(4) +#define QN908X_FMC_INT_STAT_WRITE_FAIL_L_INT_MASK BIT(5) +#define QN908X_FMC_INT_STAT_ERASE_FAIL_L_INT_MASK BIT(6) +#define QN908X_FMC_INT_STAT_AHBH_INT_MASK BIT(8) +#define QN908X_FMC_INT_STAT_LOCKH_INT_MASK BIT(9) +#define QN908X_FMC_INT_STAT_ERASEH_INT_MASK BIT(10) +#define QN908X_FMC_INT_STAT_WRITEH_INT_MASK BIT(11) +#define QN908X_FMC_INT_STAT_WR_BUFH_INT_MASK BIT(12) +#define QN908X_FMC_INT_STAT_WRITE_FAIL_H_INT_MASK BIT(13) +#define QN908X_FMC_INT_STAT_ERASE_FAIL_H_INT_MASK BIT(14) + +#define QN908X_FMC_SMART_CTRL_PRGML_EN_MASK BIT(0) +#define QN908X_FMC_SMART_CTRL_PRGMH_EN_MASK BIT(1) +#define QN908X_FMC_SMART_CTRL_SMART_WRITEL_EN_MASK BIT(2) +#define QN908X_FMC_SMART_CTRL_SMART_WRITEH_EN_MASK BIT(3) +#define QN908X_FMC_SMART_CTRL_SMART_ERASEL_EN_MASK BIT(4) +#define QN908X_FMC_SMART_CTRL_SMART_ERASEH_EN_MASK BIT(5) +#define QN908X_FMC_SMART_CTRL_MAX_WRITE_MASK 0xf00u +#define QN908X_FMC_SMART_CTRL_MAX_WRITE_SHIFT 8u +#define QN908X_FMC_SMART_CTRL_MAX_WRITE(x) \ + (((uint32_t)(((uint32_t)(x)) << QN908X_FMC_SMART_CTRL_MAX_WRITE_SHIFT)) \ + & QN908X_FMC_SMART_CTRL_MAX_WRITE_MASK) +#define QN908X_FMC_SMART_CTRL_MAX_ERASE_MASK 0x3f000u +#define QN908X_FMC_SMART_CTRL_MAX_ERASE_SHIFT 12u +#define QN908X_FMC_SMART_CTRL_MAX_ERASE(x) \ + (((uint32_t)(((uint32_t)(x)) << QN908X_FMC_SMART_CTRL_MAX_ERASE_SHIFT)) \ + & QN908X_FMC_SMART_CTRL_MAX_ERASE_MASK) + +#define QN908X_FMC_SMART_CTRL_MAX_ERASE_RETRIES 9 +#define QN908X_FMC_SMART_CTRL_MAX_WRITE_RETRIES 9 + +#define QN908X_FMC_TIME_CTRL_PRGM_CYCLE_MASK 0xfffu +#define QN908X_FMC_TIME_CTRL_PRGM_CYCLE_SHIFT 0u +#define QN908X_FMC_TIME_CTRL_PRGM_CYCLE(x) \ + (((uint32_t)(((uint32_t)(x)) << QN908X_FMC_TIME_CTRL_PRGM_CYCLE_SHIFT)) \ + & QN908X_FMC_TIME_CTRL_PRGM_CYCLE_MASK) +#define QN908X_FMC_TIME_CTRL_TIME_BASE_MASK 0xff000u +#define QN908X_FMC_TIME_CTRL_TIME_BASE_SHIFT 12u +#define QN908X_FMC_TIME_CTRL_TIME_BASE(x) \ + (((uint32_t)(((uint32_t)(x)) << QN908X_FMC_TIME_CTRL_TIME_BASE_SHIFT)) \ + & QN908X_FMC_TIME_CTRL_TIME_BASE_MASK) + +#define QN908X_FMC_LOCK_STAT_8_MASS_ERASE_LOCK_EN BIT(0) +#define QN908X_FMC_LOCK_STAT_8_FSH_PROTECT_EN BIT(1) +#define QN908X_FMC_LOCK_STAT_8_MEM_PROTECT_EN BIT(2) +#define QN908X_FMC_LOCK_STAT_8_PROTECT_ANY (BIT(1) | BIT(2)) + +/* See Table 418 "Flash lock and protect description" in the user manual */ +#define QN908X_FLASH_LOCK_ADDR (QN908X_FLASH_BASE + 0x7f820) +/* Allow mass erase */ +#define QN908X_FLASH_LOCK_ENABLE_MASS_ERASE BIT(0) +/* disallow flash access from SWD */ +#define QN908X_FLASH_LOCK_ENABLE_FLASH_PROTECTION BIT(1) +/* disallow SRAM access from SWD */ +#define QN908X_FLASH_LOCK_ENABLE_MEMORY_PROTECTION BIT(2) + +/* Page lock information located at the beginning of the last page. */ +struct qn908x_flash_page_lock { + uint8_t bits[QN908X_FLASH_MAX_BLOCKS * QN908X_FLASH_PAGES_PER_BLOCK / 8]; + uint8_t protection; + uint8_t _reserved[3]; + /* nvds_size is unused here, but we need to preserve it across erases + * when locking and unlocking pages. */ + uint8_t nvds_size[4]; +} __attribute__ ((packed)); + +/* Clock configuration is stored in the SYSCON. */ +#define QN908X_SYSCON_BASE 0x40000000u +#define QN908X_SYSCON_CLK_EN (QN908X_SYSCON_BASE + 0x00cu) +#define QN908X_SYSCON_CLK_CTRL (QN908X_SYSCON_BASE + 0x010u) +#define QN908X_SYSCON_CHIP_ID (QN908X_SYSCON_BASE + 0x108u) +#define QN908X_SYSCON_XTAL_CTRL (QN908X_SYSCON_BASE + 0x180u) + +/* Internal 16MHz / 8MHz clock used by the erase operation. */ +#define QN908X_SYSCON_CLK_EN_CLK_DP_EN_MASK BIT(21) + +#define SYSCON_XTAL_CTRL_XTAL_DIV_MASK BIT(31) + +#define SYSCON_CLK_CTRL_AHB_DIV_MASK 0x1FFF0u +#define SYSCON_CLK_CTRL_AHB_DIV_SHIFT 4u +#define SYSCON_CLK_CTRL_CLK_XTAL_SEL_MASK BIT(19) +#define SYSCON_CLK_CTRL_CLK_OSC32M_DIV_MASK BIT(20) +#define SYSCON_CLK_CTRL_SYS_CLK_SEL_MASK 0xC0000000u +#define SYSCON_CLK_CTRL_SYS_CLK_SEL_SHIFT 30u + +#define CLOCK_16MHZ 16000000u +#define CLOCK_32MHZ 32000000u +#define CLOCK_32KHZ 32000u + +/* Watchdog block registers */ +#define QN908X_WDT_BASE 0x40001000u +#define QN908X_WDT_CTRL (QN908X_WDT_BASE + 0x08u) +#define QN908X_WDT_LOCK (QN908X_WDT_BASE + 0x20u) + +struct qn908x_flash_bank { + /* The number of flash blocks. Initially set to zero until the flash + * is probed. This determines the size of the flash. */ + unsigned int num_blocks; + + unsigned int user_bank_size; + bool calc_checksum; + + /* Whether we allow to flash an image that disables SWD access, potentially + * bricking the device since the image can't be reflashed from SWD. */ + bool allow_swd_disabled; + + bool page_lock_loaded; + struct qn908x_flash_page_lock page_lock; +}; + +/* 500 ms timeout. */ +#define QN908X_DEFAULT_TIMEOUT_MS 500 + +/* Forward declaration of commands. */ +static int qn908x_probe(struct flash_bank *bank); +static int qn908x_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count); + +/* Update the value of a register with a mask. This helper allows to read a + * register, modify a subset of the bits and write back the value, which is a + * common operation when modifying only a bit filed in a register. */ +static int qn908x_update_reg(struct target *target, target_addr_t reg, + uint32_t mask, uint32_t value) +{ + uint32_t orig_value = 0; + uint32_t new_value; + int retval; + if (mask != 0xffffffff) { + /* No need to read the old value if we request a mask of 32 bits. */ + retval = target_read_u32(target, reg, &orig_value); + if (retval != ERROR_OK) { + LOG_DEBUG("Error reading reg at " TARGET_ADDR_FMT + ": %d", reg, retval); + return retval; + } + } + new_value = (orig_value & ~mask) | (value & mask); + retval = target_write_u32(target, reg, new_value); + if (retval != ERROR_OK) { + LOG_DEBUG("Error writing reg at " TARGET_ADDR_FMT " with 0x%08" + PRIx32 ": %d", reg, new_value, retval); + return retval; + } + if (mask == 0xffffffff) { + LOG_DEBUG("Updated reg at " TARGET_ADDR_FMT ": ?? -> 0x%.08" + PRIx32 "", reg, new_value); + } else { + LOG_DEBUG("Updated reg at " TARGET_ADDR_FMT ": 0x%.08" PRIx32 + " -> 0x%.08" PRIx32, reg, orig_value, new_value); + } + return ERROR_OK; +} + +/* Load lock bit and protection bit and load redundancy page info. + * This populates the LOCK_STAT_n registers with the values from the lock page, + * making protection bit changes to the last page effective. */ +static int qn908x_load_lock_stat(struct target *target) +{ + int retval = target_write_u32(target, QN908X_FMC_INI_RD_EN, + QN908X_FMC_INI_RD_EN_INI_RD_EN_MASK); + if (retval != ERROR_OK) + return retval; + + uint32_t status1; + const uint32_t status_mask = QN908X_FMC_STATUS1_FSH_STA_MASK + | QN908X_FMC_STATUS1_INI_RD_DONE_MASK; + do { + retval = target_read_u32(target, QN908X_FMC_STATUS1, &status1); + if (retval != ERROR_OK) + return retval; + } while ((status1 & status_mask) != QN908X_FMC_STATUS1_INI_RD_DONE_MASK); + + for (int i = 0; i <= 8; i++) { + uint32_t addr = QN908X_FMC_LOCK_STAT_0 + i * 4; + uint32_t lock_stat; + if (target_read_u32(target, addr, &lock_stat) == ERROR_OK) + LOG_DEBUG("LOCK_STAT_%d = 0x%08" PRIx32, i, lock_stat); + } + return ERROR_OK; +} + +/* Initializes the FMC controller registers for allowing writing. */ +static int qn908x_init_flash(struct target *target) +{ + /* Determine the current clock configuration. */ + uint32_t clk_ctrl; + int retval = target_read_u32(target, QN908X_SYSCON_CLK_CTRL, &clk_ctrl); + if (retval != ERROR_OK) + return retval; + + uint32_t clk_sel = (clk_ctrl & SYSCON_CLK_CTRL_SYS_CLK_SEL_MASK) + >> SYSCON_CLK_CTRL_SYS_CLK_SEL_SHIFT; + LOG_DEBUG("Clock clk_sel=0x%08" PRIu32, clk_sel); + + /* Core clock frequency. */ + uint32_t core_freq = 0; + switch (clk_sel) { + case 0: /* RCO 32 MHz */ + core_freq = (clk_ctrl & SYSCON_CLK_CTRL_CLK_OSC32M_DIV_MASK) ? + CLOCK_16MHZ : CLOCK_32MHZ; + break; + case 1: /* Xin frequency */ + { + uint32_t clk_xtal; + retval = target_read_u32(target, QN908X_SYSCON_XTAL_CTRL, &clk_xtal); + if (retval != ERROR_OK) + return retval; + core_freq = (clk_ctrl & SYSCON_CLK_CTRL_CLK_XTAL_SEL_MASK) + && (clk_xtal & SYSCON_XTAL_CTRL_XTAL_DIV_MASK) + ? CLOCK_32MHZ : CLOCK_16MHZ; + } + break; + case 2: /* 32 Kz */ + core_freq = CLOCK_32KHZ; + break; + default: + return ERROR_FAIL; + } + + uint32_t ahb_div = (clk_ctrl & SYSCON_CLK_CTRL_AHB_DIV_MASK) + >> SYSCON_CLK_CTRL_AHB_DIV_SHIFT; + uint32_t ahb_freq = core_freq / (ahb_div + 1); + + LOG_DEBUG("Core freq: %" PRIu32 " Hz | AHB freq: %" PRIu32 " Hz", + core_freq, ahb_freq); + + /* TIME_BASE is 2uS at the current AHB clock speed. */ + retval = target_write_u32(target, QN908X_FMC_TIME_CTRL, + QN908X_FMC_TIME_CTRL_TIME_BASE(2 * ahb_freq / 1000000) | + QN908X_FMC_TIME_CTRL_PRGM_CYCLE(30)); + if (retval != ERROR_OK) + return retval; + + return qn908x_load_lock_stat(target); +} + +/* flash bank qn908x <base> <size> 0 0 <target#> [calc_checksum] */ +FLASH_BANK_COMMAND_HANDLER(qn908x_flash_bank_command) +{ + struct qn908x_flash_bank *qn908x_info; + + if (CMD_ARGC < 6 || CMD_ARGC > 7) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (bank->base != QN908X_FLASH_BASE) { + LOG_ERROR("Address " TARGET_ADDR_FMT + " is an invalid bank address (try 0x%08" PRIx32 ")", + bank->base, QN908X_FLASH_BASE); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + qn908x_info = malloc(sizeof(struct qn908x_flash_bank)); + + if (!qn908x_info) + return ERROR_FAIL; + + bank->driver_priv = qn908x_info; + qn908x_info->num_blocks = 0; + qn908x_info->user_bank_size = bank->size; + qn908x_info->page_lock_loaded = false; + qn908x_info->allow_swd_disabled = false; + + qn908x_info->calc_checksum = false; + if (CMD_ARGC == 7) { + if (strcmp(CMD_ARGV[6], "calc_checksum")) { + free(qn908x_info); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + qn908x_info->calc_checksum = true; + } + + return ERROR_OK; +} + +static int qn908x_read_page_lock(struct flash_bank *bank) +{ + struct qn908x_flash_bank *qn908x_info = bank->driver_priv; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* The last page of the flash contains the "Flash lock and protect" + * information. It is not clear where this is located on chips with only + * one block. */ + uint32_t prot_offset = qn908x_info->num_blocks * QN908X_FLASH_BLOCK_SIZE + - QN908X_FLASH_PAGE_SIZE; + + int retval = target_read_memory(bank->target, bank->base + prot_offset, 4, + sizeof(qn908x_info->page_lock) / 4, + (void *)(&qn908x_info->page_lock)); + if (retval != ERROR_OK) + return retval; + LOG_DEBUG("Flash protection = 0x%02" PRIx8, + qn908x_info->page_lock.protection); + + qn908x_info->page_lock_loaded = true; + return ERROR_OK; +} + +static int qn908x_busy_check(struct target *target) +{ + uint32_t status1; + int retval = target_read_u32(target, QN908X_FMC_STATUS1, &status1); + if (retval != ERROR_OK) + return retval; + + if ((status1 & (QN908X_FMC_STATUS1_FSH_ERA_BUSY_L_MASK + | QN908X_FMC_STATUS1_FSH_WR_BUSY_L_MASK + | QN908X_FMC_STATUS1_FSH_ERA_BUSY_H_MASK + | QN908X_FMC_STATUS1_FSH_WR_BUSY_H_MASK))) + return ERROR_FLASH_BUSY; + return ERROR_OK; +} + +static int qn908x_status_check(struct target *target) +{ + uint32_t int_stat; + int retval = target_read_u32(target, QN908X_FMC_INT_STAT, &int_stat); + if (retval != ERROR_OK) + return retval; + + /* The error bits for block 0 and block 1 have the exact same layout, only + * that block 1 error bits are shifted by 8 bits. We use this fact to + * loop over the blocks */ + for (unsigned int block = 0; block <= 1; block++) { + unsigned int shift = (block) ? 8 : 0; + if (int_stat & (QN908X_FMC_INT_STAT_AHBL_INT_MASK << shift)) { + LOG_ERROR("AHB error on block %u", block); + return ERROR_FAIL; + } + + if (int_stat & (QN908X_FMC_INT_STAT_LOCKL_INT_MASK << shift)) { + LOG_ERROR("Locked page being accessed error on block %u", block); + return ERROR_FAIL; + } + + if (int_stat & (QN908X_FMC_INT_STAT_WRITE_FAIL_L_INT_MASK << shift)) { + LOG_ERROR("Smart write on block %u failed", block); + return ERROR_FAIL; + } + + if ((int_stat & (QN908X_FMC_INT_STAT_ERASE_FAIL_L_INT_MASK << shift)) + || (int_stat & (QN908X_FMC_INT_STAT_ERASE_FAIL_H_INT_MASK << shift))) { + LOG_ERROR("Smart erase on block %u failed", block); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +static int qn908x_wait_for_idle(struct target *target, int64_t timeout_ms) +{ + int64_t ms_start = timeval_ms(); + + int busy = ERROR_FLASH_BUSY; + while (busy != ERROR_OK) { + busy = qn908x_busy_check(target); + if (busy != ERROR_OK && busy != ERROR_FLASH_BUSY) + return busy; + if (timeval_ms() - ms_start > timeout_ms) { + LOG_ERROR("Timeout waiting to be idle."); + return ERROR_TIMEOUT_REACHED; + } + } + return ERROR_OK; +} + +/* Set up the chip to perform an erase (page or block) operation. */ +static int qn908x_setup_erase(struct target *target) +{ + int retval; + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* Enable 8MHz clock. */ + retval = qn908x_update_reg(target, QN908X_SYSCON_CLK_EN, + QN908X_SYSCON_CLK_EN_CLK_DP_EN_MASK, + QN908X_SYSCON_CLK_EN_CLK_DP_EN_MASK); + if (retval != ERROR_OK) + return retval; + + /* Set ERASE_TIME to 2ms for smart erase. */ + retval = qn908x_update_reg(target, QN908X_FMC_ERASE_TIME, + (1u << 20) - 1, + 2000 * 8); /* 2000 uS * 8 MHz = x cycles */ + if (retval != ERROR_OK) + return retval; + + /* Set up smart erase. SWD can only perform smart erase. */ + uint32_t ctrl_val = QN908X_FMC_SMART_CTRL_SMART_ERASEH_EN_MASK + | QN908X_FMC_SMART_CTRL_SMART_ERASEL_EN_MASK + | QN908X_FMC_SMART_CTRL_MAX_ERASE(QN908X_FMC_SMART_CTRL_MAX_ERASE_RETRIES) + | QN908X_FMC_SMART_CTRL_MAX_WRITE(QN908X_FMC_SMART_CTRL_MAX_WRITE_RETRIES); + retval = target_write_u32(target, QN908X_FMC_SMART_CTRL, ctrl_val); + if (retval != ERROR_OK) + return retval; + + retval = qn908x_wait_for_idle(target, QN908X_DEFAULT_TIMEOUT_MS); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int qn908x_erase(struct flash_bank *bank, unsigned int first, + unsigned int last) +{ + struct qn908x_flash_bank *qn908x_info = bank->driver_priv; + int retval = ERROR_OK; + + if (!qn908x_info->num_blocks) { + if (qn908x_probe(bank) != ERROR_OK) + return ERROR_FLASH_BANK_NOT_PROBED; + } + + retval = qn908x_setup_erase(bank->target); + if (retval != ERROR_OK) + return retval; + + for (unsigned int i = first; i <= last; i++) { + if (i >= bank->num_sectors) + return ERROR_FLASH_SECTOR_INVALID; + uint32_t block_idx = i / QN908X_FLASH_PAGES_PER_BLOCK; + uint32_t page_idx = i % QN908X_FLASH_PAGES_PER_BLOCK; + if (block_idx >= qn908x_info->num_blocks) + return ERROR_FLASH_SECTOR_INVALID; + + LOG_DEBUG("Erasing page %" PRIu32 " of block %" PRIu32, + page_idx, block_idx); + + /* Depending on the block the page we are erasing is located we + * need to use a different set of bits in the registers. */ + uint32_t ctrl_page_idx_shift = block_idx ? + QN908X_FMC_ERASE_CTRL_PAGE_IDXH_SHIFT : + QN908X_FMC_ERASE_CTRL_PAGE_IDXL_SHIFT; + uint32_t ctrl_erase_en_shift = block_idx ? + QN908X_FMC_ERASE_CTRL_PAGE_ERASEH_EN_SHIFT : + QN908X_FMC_ERASE_CTRL_PAGE_ERASEL_EN_SHIFT; + + retval = target_write_u32(bank->target, QN908X_FMC_ERASE_CTRL, + BIT(ctrl_erase_en_shift) | (page_idx << ctrl_page_idx_shift)); + if (retval != ERROR_OK) + return retval; + + retval = qn908x_wait_for_idle(bank->target, QN908X_DEFAULT_TIMEOUT_MS); + if (retval != ERROR_OK) + return retval; + + retval = qn908x_status_check(bank->target); + if (retval != ERROR_OK) + return retval; + } + + return retval; +} + +static int qn908x_protect(struct flash_bank *bank, int set, unsigned int first, + unsigned int last) +{ + struct qn908x_flash_bank *qn908x_info = bank->driver_priv; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!qn908x_info->page_lock_loaded) { + int retval = qn908x_read_page_lock(bank); + if (retval != ERROR_OK) + return retval; + } + + /* Use [first, last) interval open on the right side from now on. */ + last++; + /* We use sectors as prot_blocks. */ + bool needs_update = false; + for (unsigned int i = first; i < last; i++) { + if (set != (((qn908x_info->page_lock.bits[i / 8] >> (i % 8)) & 1) ^ 1)) + needs_update = true; + } + + /* Check that flash protection still allows SWD access to flash and RAM, + * otherwise we won't be able to re-flash this chip from SWD unless we do a + * mass erase. */ + if (qn908x_info->page_lock.protection & QN908X_FMC_LOCK_STAT_8_PROTECT_ANY) { + LOG_WARNING("SWD flash/RAM access disabled in the Flash lock and " + "protect descriptor. You might need to issue a mass_erase to " + "regain SWD access to this chip after reboot."); + } + + if (!needs_update) + return ERROR_OK; + + int last_page = qn908x_info->num_blocks * QN908X_FLASH_PAGES_PER_BLOCK - 1; + int retval; + + if (qn908x_info->page_lock.bits[sizeof(qn908x_info->page_lock.bits) - 1] & 0x80) { + /* A bit 1 in the MSB in the page_lock.bits array means that the last + * page is unlocked, so we can just erase it. */ + retval = qn908x_erase(bank, last_page, last_page); + if (retval != ERROR_OK) + return retval; + } else { + /* TODO: The last page is locked and we can't erase unless we use the + * ERASE_PASSWORD from code running on the device. For this we need to + * copy a little program to RAM and execute the erase command from + * there since there's no way to override the page protection from + * SWD. */ + LOG_ERROR("Unprotecting the last page is not supported. Issue a " + "\"qn908x mass_erase\" command to erase the whole flash, " + "including the last page and its protection."); + return ERROR_FAIL; + } + + for (unsigned int i = first / 8; i < (last + 7) / 8; i++) { + /* first_mask contains a bit set if the bit corresponds to a block id + * that is larger or equal than first. This is basically 0xff in all + * cases except potentially the first iteration. */ + uint8_t first_mask = (first <= i * 8) + ? 0xff : 0xff ^ ((1u << (first - i * 8)) - 1); + /* Similar to first_mask, this contains a bit set if the corresponding + * is smaller than last. */ + uint8_t last_mask = (i * 8 + 8 <= last) + ? 0xff : ((1u << (last - i * 8)) - 1); + + uint8_t mask = first_mask & last_mask; + LOG_DEBUG("protect set=%d bits[%d] with mask=0x%02x", set, i, mask); + /* To "set" the protection bit means to clear the bit in the page_lock + * bit array. */ + if (set) + qn908x_info->page_lock.bits[i] &= ~mask; + else + qn908x_info->page_lock.bits[i] |= mask; + } + + retval = qn908x_write(bank, (void *)(&qn908x_info->page_lock), + last_page * QN908X_FLASH_PAGE_SIZE, sizeof(qn908x_info->page_lock)); + if (retval != ERROR_OK) + return retval; + + /* Reload the lock_stat to make the changes effective. */ + retval = qn908x_load_lock_stat(bank->target); + if (retval != ERROR_OK) + return retval; + + for (unsigned int i = first; i < last; i++) + bank->sectors[i].is_protected = set; + + return ERROR_OK; +} + +static int qn908x_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct qn908x_flash_bank *qn908x_info = bank->driver_priv; + int retval = ERROR_OK; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* The flash infrastructure was requested to align writes to 32 bit */ + assert(((offset % 4) == 0) && ((count % 4) == 0)); + + /* Compute the calc_checksum even if it wasn't requested. */ + uint32_t checksum = 0; + if (offset == 0 && count >= 0x20) { + for (int i = 0; i < 7; i++) + checksum += buf_get_u32(buffer + (i * 4), 0, 32); + checksum = 0 - checksum; + LOG_DEBUG("computed image checksum: 0x%8.8" PRIx32, checksum); + uint32_t stored_checksum = buf_get_u32(buffer + 7 * 4, 0, 32); + if (checksum != stored_checksum) { + LOG_WARNING("Image vector table checksum mismatch: expected 0x%08" + PRIx32 " but found 0x%08" PRIx32, + checksum, stored_checksum); + if (!qn908x_info->calc_checksum) + LOG_WARNING("This device will not boot, use calc_checksum in " + "the flash bank."); + else + LOG_WARNING("Updating checksum, verification will fail."); + } + } + + /* Check the Code Read Protection (CRP) word for invalid values or not + * allowed ones. */ + if (offset <= 0x20 && offset + count >= 0x24) { + uint32_t crp = buf_get_u32(buffer + 0x20 - offset, 0, 32); + /* 2-bit fields at bits 10, 12, 14, 16 and 18 must not be 00 or 11. */ + for (int i = 10; i <= 18; i += 2) { + uint32_t field = (crp >> i) & 3; + if (field == 0 || field == 3) { + LOG_DEBUG("Code Read Protection = 0x%08" PRIx32, crp); + LOG_ERROR("The Code Read Protection (CRP) field at bit %d is " + "invalid (%" PRIu32 "). An invalid value could make " + "the flash inaccessible.", i, field); + return ERROR_FAIL; + } + } + + uint32_t swd_allowed = (crp >> 18) & 3; + if (swd_allowed != 2) { + LOG_WARNING("The Code Read Protection (CRP) in this image " + "(0x%08" PRIx32 ") is disabling the SWD access, which is " + "currently used by OpenOCD to flash this device. After " + "reboot, this device will not be accessible to OpenOCD " + "anymore.", crp); + if (!qn908x_info->allow_swd_disabled) { + LOG_ERROR("Disabling SWD is not allowed, run " + "\"qn908x allow_brick\" before if you really want to " + "disable SWD. You won't be able to access this chip " + "anymore from OpenOCD."); + return ERROR_FAIL; + } + } + } + + retval = qn908x_wait_for_idle(bank->target, QN908X_DEFAULT_TIMEOUT_MS); + if (retval != ERROR_OK) + return retval; + + uint32_t smart_ctrl = QN908X_FMC_SMART_CTRL_SMART_WRITEL_EN_MASK + | QN908X_FMC_SMART_CTRL_PRGML_EN_MASK + | QN908X_FMC_SMART_CTRL_MAX_WRITE(QN908X_FMC_SMART_CTRL_MAX_WRITE_RETRIES); + if (qn908x_info->num_blocks > 1) { + smart_ctrl |= QN908X_FMC_SMART_CTRL_SMART_WRITEH_EN_MASK + | QN908X_FMC_SMART_CTRL_PRGMH_EN_MASK; + } + retval = target_write_u32(bank->target, QN908X_FMC_SMART_CTRL, smart_ctrl); + if (retval != ERROR_OK) + return retval; + + /* Write data page-wise, as suggested in the examples in section + * 28.5.2 "Flash write" of user manual UM11023 in revision 1.1 + * (February 2018). */ + while (count > 0) { + uint32_t next_offset = (offset & ~(QN908X_FLASH_PAGE_SIZE - 1)) + QN908X_FLASH_PAGE_SIZE; + uint32_t chunk_len = next_offset - offset; + if (chunk_len > count) + chunk_len = count; + + if (offset == 0 + && chunk_len >= QN908X_FLASH_IRQ_VECTOR_CHECKSUM_END + && qn908x_info->calc_checksum) { + /* write data prior to checksum */ + retval = target_write_buffer(bank->target, bank->base, + QN908X_FLASH_IRQ_VECTOR_CHECKSUM_POS, buffer); + if (retval != ERROR_OK) + return retval; + + /* write computed crc checksum instead of provided data */ + retval = target_write_u32(bank->target, bank->base + QN908X_FLASH_IRQ_VECTOR_CHECKSUM_POS, checksum); + if (retval != ERROR_OK) + return retval; + + retval = target_write_buffer(bank->target, + bank->base + QN908X_FLASH_IRQ_VECTOR_CHECKSUM_END, + chunk_len - QN908X_FLASH_IRQ_VECTOR_CHECKSUM_END, + buffer + QN908X_FLASH_IRQ_VECTOR_CHECKSUM_END); + } else { + retval = target_write_buffer(bank->target, bank->base + offset, + chunk_len, buffer); + } + + if (retval != ERROR_OK) + return retval; + + keep_alive(); + buffer += chunk_len; + count -= chunk_len; + offset = next_offset; + + /* Wait for FMC to complete write */ + retval = qn908x_wait_for_idle(bank->target, QN908X_DEFAULT_TIMEOUT_MS); + if (retval != ERROR_OK) + return retval; + + /* Check if FMC reported any errors */ + retval = qn908x_status_check(bank->target); + if (retval != ERROR_OK) + return retval; + } + + return retval; +} + +static int is_flash_protected(struct flash_bank *bank, bool *is_protected) +{ + int retval; + uint32_t lock_stat; + retval = target_read_u32(bank->target, QN908X_FMC_LOCK_STAT_8, &lock_stat); + if (retval) + return retval; + + *is_protected = false; + if (lock_stat & QN908X_FMC_LOCK_STAT_8_PROTECT_ANY) + *is_protected = true; + + return ERROR_OK; +} + +static int qn908x_probe(struct flash_bank *bank) +{ + int retval; + struct qn908x_flash_bank *qn908x_info = bank->driver_priv; + uint8_t info_page[QN908X_INFO_PAGE_CRC_END - QN908X_INFO_PAGE_CRC_START]; + qn908x_info->num_blocks = 0; + + /* When the SWD access to the RAM is locked by the LOCK_STAT_8 register we + * can't access the info page to verify the chip/bank version and it will + * read all zeros. This situation prevents the bank from being initialized + * at all so no other operation can be performed. The only option to + * re-flash the chip is to perform a mass_erase from SWD, which can be + * performed even if the mass_erase operation is locked as well. + * We attempt to read the info page and redirect the user to perform a + * mass_erase if we detect this situation. */ + retval = target_read_memory(bank->target, QN908X_INFO_PAGE_CRC_START, + sizeof(uint32_t), sizeof(info_page) / sizeof(uint32_t), + info_page); + if (retval != ERROR_OK) + return retval; + + const uint32_t crc_seed = 0xffffffff; + /* The QN908x uses the standard little endian CRC32 polynomial and all ones + * as seed. The CRC32 is however finalized by one last xor operation that + * is not part of the common CRC32 implementation, so we do that by hand */ + uint32_t computed_crc = crc32_le(CRC32_POLY_LE, crc_seed, + info_page, sizeof(info_page)); + computed_crc ^= crc_seed; + uint32_t read_crc; + retval = target_read_u32(bank->target, QN908X_INFO_PAGE_CRC32, &read_crc); + if (retval != ERROR_OK) + return retval; + + if (computed_crc != read_crc) { + uint32_t info_page_or = 0; + for (unsigned int i = 0; i < sizeof(info_page); i++) + info_page_or |= info_page[i]; + bool is_protected; + retval = is_flash_protected(bank, &is_protected); + if (retval != ERROR_OK) + return retval; + + if (info_page_or == 0 && is_protected) { + LOG_ERROR("The flash or memory in this chip is protected and " + "cannot be accessed from the SWD interface. However, a " + "\"qn908x mass_erase\" can erase the device and lift this " + "protection."); + return ERROR_FAIL; + } + + LOG_ERROR("Flash information page CRC32 mismatch, found 0x%08" + PRIx32 " but computed 0x%08" PRIx32 ". Flash size unknown", + read_crc, computed_crc); + return ERROR_FAIL; + } + + uint32_t flash_size_fld = target_buffer_get_u32(bank->target, + info_page + (QN908X_INFO_PAGE_FLASH_SIZE - QN908X_INFO_PAGE_CRC_START)); + + switch (flash_size_fld) { + case QN908X_FLASH_SIZE_512K: + qn908x_info->num_blocks = 2; + break; + case QN908X_FLASH_SIZE_256K: + qn908x_info->num_blocks = 1; + break; + default: + LOG_ERROR("Unknown Flash size field: 0x%08" PRIx32, + flash_size_fld); + return ERROR_FAIL; + } + + bank->size = qn908x_info->num_blocks * QN908X_FLASH_BLOCK_SIZE; + bank->write_start_alignment = 4; + bank->write_end_alignment = 4; + + /* The flash supports erasing and protecting individual pages. */ + bank->num_sectors = qn908x_info->num_blocks * + QN908X_FLASH_PAGES_PER_BLOCK; + bank->sectors = alloc_block_array(0, QN908X_FLASH_PAGE_SIZE, + bank->num_sectors); + if (!bank->sectors) + return ERROR_FAIL; + + retval = qn908x_init_flash(bank->target); + if (retval != ERROR_OK) + return retval; + + LOG_INFO("Detected flash size: %d KiB", bank->size / 1024); + + return ERROR_OK; +} + +static int qn908x_auto_probe(struct flash_bank *bank) +{ + struct qn908x_flash_bank *qn908x_info = bank->driver_priv; + if (qn908x_info->num_blocks != 0) + return ERROR_OK; + LOG_DEBUG("auto_probe"); + return qn908x_probe(bank); +} + +static int qn908x_protect_check(struct flash_bank *bank) +{ + struct qn908x_flash_bank *qn908x_info = bank->driver_priv; + + int retval = qn908x_read_page_lock(bank); + if (retval != ERROR_OK) + return retval; + + for (uint32_t i = 0; + i < qn908x_info->num_blocks * QN908X_FLASH_PAGES_PER_BLOCK; + i++) { + /* A bit 0 in page_lock means page is locked. */ + bank->sectors[i].is_protected = + ((qn908x_info->page_lock.bits[i / 8] >> (i % 8)) & 1) ^ 1; + } + return ERROR_OK; +} + +static int qn908x_get_info(struct flash_bank *bank, + struct command_invocation *cmd) +{ + uint32_t bootloader_version; + uint32_t chip_id; + uint8_t bluetooth[6]; + int retval; + struct qn908x_flash_bank *qn908x_info = bank->driver_priv; + + retval = target_read_u32(bank->target, QN908X_SYSCON_CHIP_ID, &chip_id); + if (retval != ERROR_OK) { + command_print_sameline(cmd, "Cannot read QN908x chip ID."); + return retval; + } + retval = target_read_u32(bank->target, QN908X_INFO_PAGE_BOOTLOADER_VER, + &bootloader_version); + if (retval != ERROR_OK) { + command_print_sameline(cmd, "Cannot read from QN908x info page."); + return retval; + } + + retval = target_read_memory(bank->target, QN908X_INFO_PAGE_BLUETOOTH_ADDR, + 1, sizeof(bluetooth), bluetooth); + if (retval != ERROR_OK) { + command_print_sameline(cmd, "Cannot read QN908x bluetooth L2 address."); + return retval; + } + + command_print_sameline(cmd, "qn908x: chip id: 0x%" PRIx32, chip_id); + + command_print_sameline(cmd, " bdaddr: " + "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 + ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8, + bluetooth[0], bluetooth[1], bluetooth[2], + bluetooth[3], bluetooth[4], bluetooth[5]); + + command_print_sameline(cmd, " bootloader: %08" PRIx32, bootloader_version); + + command_print_sameline(cmd, " blocks: %" PRIu32, qn908x_info->num_blocks); + + return ERROR_OK; +} + +COMMAND_HANDLER(qn908x_handle_allow_brick_command) +{ + int retval; + + struct target *target = get_current_target(CMD_CTX); + struct flash_bank *bank = NULL; + + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + retval = get_flash_bank_by_addr(target, QN908X_FLASH_BASE, true, &bank); + if (retval != ERROR_OK) + return retval; + + /* If get_flash_bank_by_addr() did not find the flash bank, it should have + * returned and error code instead of ERROR_OK */ + assert(bank); + struct qn908x_flash_bank *qn908x_info = bank->driver_priv; + + LOG_WARNING("Flashing images that disable SWD in qn908x is now allowed."); + qn908x_info->allow_swd_disabled = true; + + return ERROR_OK; +} + +COMMAND_HANDLER(qn908x_handle_disable_wdog_command) +{ + int retval; + struct target *target = get_current_target(CMD_CTX); + + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (target->state != TARGET_HALTED) { + command_print(CMD, "Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* To change any value in the watchdog block (WDT) we need to first write + * 0x1ACCE551 to the LOCK register, and we can then set it back to any other + * value to prevent accidental changes to the watchdog. */ + retval = target_write_u32(target, QN908X_WDT_LOCK, 0x1ACCE551); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, QN908X_WDT_CTRL, 0); + if (retval != ERROR_OK) + return retval; + + return target_write_u32(target, QN908X_WDT_LOCK, 0); +} + +COMMAND_HANDLER(qn908x_handle_mass_erase_command) +{ + int retval; + bool keep_lock = false; + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + if (CMD_ARGC == 1) { + if (strcmp("keep_lock", CMD_ARGV[0])) + return ERROR_COMMAND_ARGUMENT_INVALID; + keep_lock = true; + } + + /* This operation can be performed without probing the bank since it is the + * only way to unlock a chip when the flash and ram have been locked. */ + struct target *target = get_current_target(CMD_CTX); + + retval = qn908x_setup_erase(target); + if (retval != ERROR_OK) + return retval; + + /* Check the mass-erase locking status for information purposes only. This + * lock applies to both the SWD and the code running in the core but can be + * bypassed in either case. */ + uint32_t lock_stat_8; + retval = target_read_u32(target, QN908X_FMC_LOCK_STAT_8, &lock_stat_8); + LOG_DEBUG("LOCK_STAT_8 before erasing: 0x%" PRIx32, lock_stat_8); + if (retval != ERROR_OK) + return retval; + if ((lock_stat_8 & QN908X_FMC_LOCK_STAT_8_MASS_ERASE_LOCK_EN) == 0) { + LOG_INFO("mass_erase disabled by Flash lock and protection, forcing " + "mass_erase."); + } + /* Set the DEBUG_PASSWORD so we can force the mass erase from the SWD. We do + * this regardless of the lock status. */ + retval = target_write_u32(target, QN908X_FMC_DEBUG_PASSWORD, 0xCA1E093F); + if (retval != ERROR_OK) + return retval; + + /* Erase both halves of the flash at the same time. These are actually done + * sequentially but we need to send the command to erase both blocks since + * doing so in a locked flash will change the LOCK_STAT_8 register to 0x01, + * allowing us to access the (now erase) flash an memory. Erasing only one + * block at a time does not reset the LOCK_STAT_8 register and therefore + * will not grant access to program the chip. */ + uint32_t erase_cmd = (1u << QN908X_FMC_ERASE_CTRL_HALF_ERASEH_EN_SHIFT) | + (1u << QN908X_FMC_ERASE_CTRL_HALF_ERASEL_EN_SHIFT); + LOG_DEBUG("Erasing both blocks with command 0x%" PRIx32, erase_cmd); + + retval = target_write_u32(target, QN908X_FMC_ERASE_CTRL, erase_cmd); + if (retval != ERROR_OK) + return retval; + + retval = qn908x_wait_for_idle(target, QN908X_DEFAULT_TIMEOUT_MS); + if (retval != ERROR_OK) + return retval; + + retval = qn908x_status_check(target); + if (retval != ERROR_OK) + return retval; + + /* Set the debug password back to 0 to avoid accidental mass_erase. */ + retval = target_write_u32(target, QN908X_FMC_DEBUG_PASSWORD, 0); + if (retval != ERROR_OK) + return retval; + + /* At this point the flash is erased and we are able to write to the flash + * since the LOCK_STAT_8 gets updated to 0x01 after the mass_erase. However, + * after a hard reboot this value will be realoaded from flash which after + * an erase is 0xff. This means that after flashing an image that doesn't + * set the protection bits we end up with a chip that we can't debug. We + * update this value to 0x01 unless "keep_lock" is passed to allow the SWD + * interface to debug the flash and RAM after a hard reset. */ + if (keep_lock) + return retval; + + retval = qn908x_init_flash(target); + if (retval != ERROR_OK) + return retval; + + /* Unlock access to RAM and FLASH in the last page of the flash and + * reloading */ + retval = qn908x_wait_for_idle(target, QN908X_DEFAULT_TIMEOUT_MS); + if (retval != ERROR_OK) + return retval; + + uint32_t smart_ctrl = QN908X_FMC_SMART_CTRL_SMART_WRITEH_EN_MASK | + QN908X_FMC_SMART_CTRL_PRGMH_EN_MASK; + retval = target_write_u32(target, QN908X_FMC_SMART_CTRL, smart_ctrl); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, QN908X_FLASH_LOCK_ADDR, + QN908X_FLASH_LOCK_ENABLE_MASS_ERASE); + if (retval != ERROR_OK) + return retval; + + retval = qn908x_wait_for_idle(target, QN908X_DEFAULT_TIMEOUT_MS); + if (retval != ERROR_OK) + return retval; + + /* Force a page_lock reload after the mass_erase . */ + retval = qn908x_load_lock_stat(target); + if (retval != ERROR_OK) + return retval; + + return retval; +} + +static const struct command_registration qn908x_exec_command_handlers[] = { + { + .name = "allow_brick", + .handler = qn908x_handle_allow_brick_command, + .mode = COMMAND_EXEC, + .help = "Allow writing images that disable SWD access in their " + "Code Read Protection (CRP) word. Warning: This can make your " + "chip inaccessible from OpenOCD or any other SWD debugger.", + .usage = "", + }, + { + .name = "disable_wdog", + .handler = qn908x_handle_disable_wdog_command, + .mode = COMMAND_EXEC, + .help = "Disabled the watchdog (WDT).", + .usage = "", + }, + { + .name = "mass_erase", + .handler = qn908x_handle_mass_erase_command, + .mode = COMMAND_EXEC, + .help = "Erase the whole flash chip.", + .usage = "[keep_lock]", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration qn908x_command_handlers[] = { + { + .name = "qn908x", + .mode = COMMAND_ANY, + .help = "qn908x flash controller commands", + .usage = "", + .chain = qn908x_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +const struct flash_driver qn908x_flash = { + .name = "qn908x", + .commands = qn908x_command_handlers, + .flash_bank_command = qn908x_flash_bank_command, + .info = qn908x_get_info, + .erase = qn908x_erase, + .protect = qn908x_protect, + .write = qn908x_write, + .read = default_flash_read, + .probe = qn908x_probe, + .auto_probe = qn908x_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = qn908x_protect_check, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/renesas_rpchf.c b/src/flash/nor/renesas_rpchf.c index f99749f3dd..6c51b8f670 100644 --- a/src/flash/nor/renesas_rpchf.c +++ b/src/flash/nor/renesas_rpchf.c @@ -1,4 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Renesas RCar Gen3 RPC Hyperflash driver * Based on U-Boot RPC Hyperflash driver diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index fb34172d20..b2ebd9c49e 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later #ifdef HAVE_CONFIG_H #include "config.h" @@ -50,6 +50,10 @@ struct rp2040_flash_bank { const struct flash_device *dev; }; +/* guessed SPI flash description if autodetection disabled (same as win w25q16jv) */ +static const struct flash_device rp2040_default_spi_device = + FLASH_ID("autodetect disabled", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0, 0x100, 0x10000, 0); + static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16_t *symbol) { uint32_t magic; @@ -87,7 +91,7 @@ static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16 } static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank *priv, - uint16_t func_offset, uint32_t argdata[], unsigned int n_args) + uint16_t func_offset, uint32_t argdata[], unsigned int n_args, unsigned int timeout_ms) { char *regnames[4] = { "r0", "r1", "r2", "r3" }; @@ -99,8 +103,7 @@ static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank } target_addr_t stacktop = priv->stack->address + priv->stack->size; - LOG_DEBUG("Calling ROM func @0x%" PRIx16 " with %d arguments", func_offset, n_args); - LOG_DEBUG("Calling on core \"%s\"", target->cmd_name); + LOG_TARGET_DEBUG(target, "Calling ROM func @0x%" PRIx16 " with %u arguments", func_offset, n_args); struct reg_param args[ARRAY_SIZE(regnames) + 2]; struct armv7m_algorithm alg_info; @@ -112,11 +115,12 @@ static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank /* Pass function pointer in r7 */ init_reg_param(&args[n_args], "r7", 32, PARAM_OUT); buf_set_u32(args[n_args].value, 0, 32, func_offset); + /* Setup stack */ init_reg_param(&args[n_args + 1], "sp", 32, PARAM_OUT); buf_set_u32(args[n_args + 1].value, 0, 32, stacktop); + unsigned int n_reg_params = n_args + 2; /* User arguments + r7 + sp */ - - for (unsigned int i = 0; i < n_args + 2; ++i) + for (unsigned int i = 0; i < n_reg_params; ++i) LOG_DEBUG("Set %s = 0x%" PRIx32, args[i].reg_name, buf_get_u32(args[i].value, 0, 32)); /* Actually call the function */ @@ -125,42 +129,82 @@ static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank int err = target_run_algorithm( target, 0, NULL, /* No memory arguments */ - n_args + 1, args, /* User arguments + r7 */ + n_reg_params, args, /* User arguments + r7 + sp */ priv->jump_debug_trampoline, priv->jump_debug_trampoline_end, - 3000, /* 3s timeout */ + timeout_ms, &alg_info ); - for (unsigned int i = 0; i < n_args + 2; ++i) + + for (unsigned int i = 0; i < n_reg_params; ++i) destroy_reg_param(&args[i]); + if (err != ERROR_OK) - LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16 "\n", func_offset); + LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16, func_offset); + return err; +} + +/* Finalize flash write/erase/read ID + * - flush cache + * - enters memory-mapped (XIP) mode to make flash data visible + * - deallocates target ROM func stack if previously allocated + */ +static int rp2040_finalize_stack_free(struct flash_bank *bank) +{ + struct rp2040_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; + + /* Always flush before returning to execute-in-place, to invalidate stale + * cache contents. The flush call also restores regular hardware-controlled + * chip select following a rp2040_flash_exit_xip(). + */ + LOG_DEBUG("Flushing flash cache after write behind"); + int err = rp2040_call_rom_func(target, priv, priv->jump_flush_cache, NULL, 0, 1000); + if (err != ERROR_OK) { + LOG_ERROR("Failed to flush flash cache"); + /* Intentionally continue after error and try to setup xip anyway */ + } + + LOG_DEBUG("Configuring SSI for execute-in-place"); + err = rp2040_call_rom_func(target, priv, priv->jump_enter_cmd_xip, NULL, 0, 1000); + if (err != ERROR_OK) + LOG_ERROR("Failed to set SSI to XIP mode"); + target_free_working_area(target, priv->stack); + priv->stack = NULL; + return err; } -static int stack_grab_and_prep(struct flash_bank *bank) +/* Prepare flash write/erase/read ID + * - allocates a stack for target ROM func + * - switches the SPI interface from memory-mapped mode to direct command mode + * Always pair with a call of rp2040_finalize_stack_free() + * after flash operation finishes or fails. + */ +static int rp2040_stack_grab_and_prep(struct flash_bank *bank) { struct rp2040_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; /* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */ const int STACK_SIZE = 256; - int err = target_alloc_working_area(bank->target, STACK_SIZE, &priv->stack); + int err = target_alloc_working_area(target, STACK_SIZE, &priv->stack); if (err != ERROR_OK) { LOG_ERROR("Could not allocate stack for flash programming code"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } LOG_DEBUG("Connecting internal flash"); - err = rp2040_call_rom_func(bank->target, priv, priv->jump_connect_internal_flash, NULL, 0); + err = rp2040_call_rom_func(target, priv, priv->jump_connect_internal_flash, NULL, 0, 1000); if (err != ERROR_OK) { - LOG_ERROR("RP2040 erase: failed to connect internal flash"); + LOG_ERROR("Failed to connect internal flash"); return err; } LOG_DEBUG("Kicking flash out of XIP mode"); - err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_exit_xip, NULL, 0); + err = rp2040_call_rom_func(target, priv, priv->jump_flash_exit_xip, NULL, 0, 1000); if (err != ERROR_OK) { - LOG_ERROR("RP2040 erase: failed to exit flash XIP mode"); + LOG_ERROR("Failed to exit flash XIP mode"); return err; } @@ -173,16 +217,27 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui struct rp2040_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; - struct working_area *bounce; - int err = stack_grab_and_prep(bank); - if (err != ERROR_OK) - return err; + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + struct working_area *bounce = NULL; - const unsigned int chunk_size = target_get_working_area_avail(target); - if (target_alloc_working_area(target, chunk_size, &bounce) != ERROR_OK) { + int err = rp2040_stack_grab_and_prep(bank); + if (err != ERROR_OK) + goto cleanup; + + unsigned int avail_pages = target_get_working_area_avail(target) / priv->dev->pagesize; + /* We try to allocate working area rounded down to device page size, + * al least 1 page, at most the write data size + */ + unsigned int chunk_size = MIN(MAX(avail_pages, 1) * priv->dev->pagesize, count); + err = target_alloc_working_area(target, chunk_size, &bounce); + if (err != ERROR_OK) { LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + goto cleanup; } LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address); @@ -200,7 +255,8 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui bounce->address, /* data */ write_size /* count */ }; - err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program, args, ARRAY_SIZE(args)); + err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program, + args, ARRAY_SIZE(args), 3000); if (err != ERROR_OK) { LOG_ERROR("Failed to invoke flash programming code on target"); break; @@ -210,36 +266,32 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui offset += write_size; count -= write_size; } + +cleanup: target_free_working_area(target, bounce); - if (err != ERROR_OK) - return err; + rp2040_finalize_stack_free(bank); - /* Flash is successfully programmed. We can now do a bit of poking to make the flash - contents visible to us via memory-mapped (XIP) interface in the 0x1... memory region */ - LOG_DEBUG("Flushing flash cache after write behind"); - err = rp2040_call_rom_func(bank->target, priv, priv->jump_flush_cache, NULL, 0); - if (err != ERROR_OK) { - LOG_ERROR("RP2040 write: failed to flush flash cache"); - return err; - } - LOG_DEBUG("Configuring SSI for execute-in-place"); - err = rp2040_call_rom_func(bank->target, priv, priv->jump_enter_cmd_xip, NULL, 0); - if (err != ERROR_OK) - LOG_ERROR("RP2040 write: failed to flush flash cache"); return err; } static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct rp2040_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + uint32_t start_addr = bank->sectors[first].offset; uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr; LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr); - int err = stack_grab_and_prep(bank); + int err = rp2040_stack_grab_and_prep(bank); if (err != ERROR_OK) - return err; + goto cleanup; LOG_DEBUG("Remote call flash_range_erase"); @@ -257,10 +309,15 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig https://github.com/raspberrypi/pico-bootrom/blob/master/bootrom/program_flash_generic.c In theory, the function algorithm provides for erasing both a smaller "sector" (4096 bytes) and - an optional larger "block" (size and command provided in args). OpenOCD's spi.c only uses "block" sizes. + an optional larger "block" (size and command provided in args). */ - err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args)); + unsigned int timeout_ms = 2000 * (last - first) + 1000; + err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_erase, + args, ARRAY_SIZE(args), timeout_ms); + +cleanup: + rp2040_finalize_stack_free(bank); return err; } @@ -289,11 +346,46 @@ static int rp2040_ssel_active(struct target *target, bool active) return ERROR_OK; } +static int rp2040_spi_read_flash_id(struct target *target, uint32_t *devid) +{ + uint32_t device_id = 0; + const target_addr_t ssi_dr0 = 0x18000060; + + int err = rp2040_ssel_active(target, true); + + /* write RDID request into SPI peripheral's FIFO */ + for (int count = 0; (count < 4) && (err == ERROR_OK); count++) + err = target_write_u32(target, ssi_dr0, SPIFLASH_READ_ID); + + /* by this time, there is a receive FIFO entry for every write */ + for (int count = 0; (count < 4) && (err == ERROR_OK); count++) { + uint32_t status; + err = target_read_u32(target, ssi_dr0, &status); + + device_id >>= 8; + device_id |= (status & 0xFF) << 24; + } + + if (err == ERROR_OK) + *devid = device_id >> 8; + + int err2 = rp2040_ssel_active(target, false); + if (err2 != ERROR_OK) + LOG_ERROR("SSEL inactive failed"); + + return err; +} + static int rp2040_flash_probe(struct flash_bank *bank) { struct rp2040_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + int err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE, &priv->jump_debug_trampoline); if (err != ERROR_OK) { LOG_ERROR("Debug trampoline not found in RP2040 ROM."); @@ -344,59 +436,48 @@ static int rp2040_flash_probe(struct flash_bank *bank) return err; } - err = stack_grab_and_prep(bank); - if (err != ERROR_OK) - return err; + if (bank->size) { + /* size overridden, suppress reading SPI flash ID */ + priv->dev = &rp2040_default_spi_device; + LOG_DEBUG("SPI flash autodetection disabled, using configured size"); - uint32_t device_id = 0; - const target_addr_t ssi_dr0 = 0x18000060; - - err = rp2040_ssel_active(target, true); + } else { + /* zero bank size in cfg, read SPI flash ID and autodetect */ + err = rp2040_stack_grab_and_prep(bank); - /* write RDID request into SPI peripheral's FIFO */ - for (int count = 0; (count < 4) && (err == ERROR_OK); count++) - err = target_write_u32(target, ssi_dr0, SPIFLASH_READ_ID); + uint32_t device_id = 0; + if (err == ERROR_OK) + err = rp2040_spi_read_flash_id(target, &device_id); - /* by this time, there is a receive FIFO entry for every write */ - for (int count = 0; (count < 4) && (err == ERROR_OK); count++) { - uint32_t status; - err = target_read_u32(target, ssi_dr0, &status); + rp2040_finalize_stack_free(bank); - device_id >>= 8; - device_id |= (status & 0xFF) << 24; - } - device_id >>= 8; - - err = rp2040_ssel_active(target, false); - if (err != ERROR_OK) { - LOG_ERROR("SSEL inactive failed"); - return err; - } + if (err != ERROR_OK) + return err; - /* search for a SPI flash Device ID match */ - priv->dev = NULL; - for (const struct flash_device *p = flash_devices; p->name ; p++) - if (p->device_id == device_id) { - priv->dev = p; - break; + /* search for a SPI flash Device ID match */ + priv->dev = NULL; + for (const struct flash_device *p = flash_devices; p->name ; p++) + if (p->device_id == device_id) { + priv->dev = p; + break; + } + + if (!priv->dev) { + LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", device_id); + return ERROR_FAIL; } + LOG_INFO("Found flash device '%s' (ID 0x%08" PRIx32 ")", + priv->dev->name, priv->dev->device_id); - if (!priv->dev) { - LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", device_id); - return ERROR_FAIL; + bank->size = priv->dev->size_in_bytes; } - LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")", - priv->dev->name, priv->dev->device_id); - /* the Boot ROM flash_range_program() routine requires page alignment */ bank->write_start_alignment = priv->dev->pagesize; bank->write_end_alignment = priv->dev->pagesize; - bank->size = priv->dev->size_in_bytes; - bank->num_sectors = bank->size / priv->dev->sectorsize; - LOG_INFO("RP2040 B0 Flash Probe: %d bytes @" TARGET_ADDR_FMT ", in %d sectors\n", + LOG_INFO("RP2040 B0 Flash Probe: %" PRIu32 " bytes @" TARGET_ADDR_FMT ", in %u sectors\n", bank->size, bank->base, bank->num_sectors); bank->sectors = alloc_block_array(0, priv->dev->sectorsize, bank->num_sectors); if (!bank->sectors) @@ -439,7 +520,7 @@ FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command) return ERROR_OK; } -struct flash_driver rp2040_flash = { +const struct flash_driver rp2040_flash = { .name = "rp2040_flash", .flash_bank_command = rp2040_flash_bank_command, .erase = rp2040_flash_erase, diff --git a/src/flash/nor/rsl10.c b/src/flash/nor/rsl10.c new file mode 100644 index 0000000000..c286e9ac88 --- /dev/null +++ b/src/flash/nor/rsl10.c @@ -0,0 +1,845 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Toms StÅ«rmanis * + * toms.sturmanis@gmail.com * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdint.h> + +#include <helper/binarybuffer.h> +#include <helper/bits.h> + +#include <target/algorithm.h> +#include <target/arm_adi_v5.h> +#include <target/armv7m.h> +#include <target/cortex_m.h> + +#include "imp.h" + +#define RSL10_FLASH_ADDRESS_MAIN 0x00100000 +#define RSL10_FLASH_ADDRESS_NVR1 0x00080000 +#define RSL10_FLASH_ADDRESS_NVR2 0x00080800 +#define RSL10_FLASH_ADDRESS_NVR3 0x00081000 +#define RSL10_FLASH_ADDRESS_NVR4 0x00081800 +#define RSL10_FLASH_ADDRESS_LOCK_INFO_SETTING 0x00081040 + +#define RSL10_REG_ID 0x1FFFFFFC + +#define RSL10_FLASH_REG_MAIN_WRITE_UNLOCK 0x40000504 +#define RSL10_FLASH_REG_MAIN_CTRL 0x40000508 +#define RSL10_FLASH_REG_IF_STATUS 0x40000538 +#define RSL10_FLASH_REG_NVR_WRITE_UNLOCK 0x40000548 +#define RSL10_FLASH_REG_NVR_CTRL 0x4000054C + +#define RSL10_FLASH_REG_DEBUG_UNLOCK_KEY1 0x400000F0 +#define RSL10_FLASH_REG_DEBUG_UNLOCK_KEY2 0x400000F4 +#define RSL10_FLASH_REG_DEBUG_UNLOCK_KEY3 0x400000F8 +#define RSL10_FLASH_REG_DEBUG_UNLOCK_KEY4 0x400000FC + +#define RSL10_NVR3_USER_KEY_OFFSET 0x40 + +#define RSL10_ID 0x09010106 +#define RSL10_FLASH_KEY_MAIN 0xDBC8264E +#define RSL10_FLASH_KEY_NVR 0x71B371F5 +#define RSL10_KEY_DEBUG_LOCK 0x4C6F634B + +#define RSL10_FLASH_REG_MAIN_CTRL_LOW_W_ENABLE BIT(0) +#define RSL10_FLASH_REG_MAIN_CTRL_MIDDLE_W_ENABLE BIT(1) +#define RSL10_FLASH_REG_MAIN_CTRL_HIGH_W_ENABLE BIT(2) + +#define RSL10_FLASH_REG_NVR_CTRL_NVR1_W_ENABLE BIT(1) +#define RSL10_FLASH_REG_NVR_CTRL_NVR2_W_ENABLE BIT(2) +#define RSL10_FLASH_REG_NVR_CTRL_NVR3_W_ENABLE BIT(3) + +#define RSL10_FLASH_REG_STATUS_LOW_W_UNLOCKED BIT(0) +#define RSL10_FLASH_REG_STATUS_MIDDLE_W_UNLOCKED BIT(1) +#define RSL10_FLASH_REG_STATUS_HIGH_W_UNLOCKED BIT(2) +#define RSL10_FLASH_REG_STATUS_NVR1_W_UNLOCKED BIT(4) +#define RSL10_FLASH_REG_STATUS_NVR2_W_UNLOCKED BIT(5) +#define RSL10_FLASH_REG_STATUS_NVR3_W_UNLOCKED BIT(6) + +#define RSL10_ROM_CMD_WRITE_WORD_PAIR 0x3C +#define RSL10_ROM_CMD_WRITE_BUFFER 0x40 +#define RSL10_ROM_CMD_ERASE_SECTOR 0x44 +#define RSL10_ROM_CMD_ERASE_ALL 0x48 + +#define FLASH_SECTOR_SIZE 0x2000 + +#define RSL10_ROM_CMD_WRITE_BUFFER_MAX_SIZE FLASH_SECTOR_SIZE + +#define ALGO_STACK_POINTER_ADDR 0x20002000 + +/* Used to launch flash related functions from ROM + * Params : + * r0-r2 = arguments + * r3 = target address in rom + */ +static const uint8_t rsl10_rom_launcher_code[] = { +#include "../../../contrib/loaders/flash/rsl10/rom_launcher.inc" +}; + +enum rsl10_flash_status { + RSL10_FLASH_ERR_NONE = 0x0, + RSL10_FLASH_ERR_GENERAL_FAILURE = 0x1, + RSL10_FLASH_ERR_WRITE_NOT_ENABLED = 0x2, + RSL10_FLASH_ERR_BAD_ADDRESS = 0x3, + RSL10_FLASH_ERR_ERASE_FAILED = 0x4, + RSL10_FLASH_ERR_BAD_LENGTH = 0x5, + RSL10_FLASH_ERR_INACCESSIBLE = 0x6, + RSL10_FLASH_ERR_COPIER_BUSY = 0x7, + RSL10_FLASH_ERR_PROG_FAILED = 0x8, + RSL10_FLASH_MAX_ERR_CODES /* must be the last one */ +}; + +static const char *const rsl10_error_list[] = { + [RSL10_FLASH_ERR_GENERAL_FAILURE] = "general failure", + [RSL10_FLASH_ERR_WRITE_NOT_ENABLED] = "write not enabled, protected", + [RSL10_FLASH_ERR_BAD_ADDRESS] = "bad address", + [RSL10_FLASH_ERR_ERASE_FAILED] = "erase failed", + [RSL10_FLASH_ERR_BAD_LENGTH] = "bad length", + [RSL10_FLASH_ERR_INACCESSIBLE] = "inaccessible: not powered up, or isolated", + [RSL10_FLASH_ERR_COPIER_BUSY] = "copier busy", + [RSL10_FLASH_ERR_PROG_FAILED] = "prog failed", +}; + +static const char *rsl10_error(enum rsl10_flash_status x) +{ + if (x >= RSL10_FLASH_MAX_ERR_CODES || !rsl10_error_list[x]) + return "unknown"; + return rsl10_error_list[x]; +} + +const struct flash_driver rsl10_flash; + +struct rsl10_info { + unsigned int refcount; + + struct rsl10_bank { + struct rsl10_info *chip; + bool probed; + } bank[5]; + struct target *target; + + unsigned int flash_size_kb; +}; + +static bool rsl10_bank_is_probed(const struct flash_bank *bank) +{ + struct rsl10_bank *nbank = bank->driver_priv; + assert(nbank); + return nbank->probed; +} + +static int rsl10_probe(struct flash_bank *bank); + +static int rsl10_get_probed_chip_if_halted(struct flash_bank *bank, struct rsl10_info **chip) +{ + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + struct rsl10_bank *nbank = bank->driver_priv; + *chip = nbank->chip; + + if (rsl10_bank_is_probed(bank)) + return ERROR_OK; + + return rsl10_probe(bank); +} + +static int rsl10_protect_check(struct flash_bank *bank) +{ + struct rsl10_bank *nbank = bank->driver_priv; + struct rsl10_info *chip = nbank->chip; + + assert(chip); + + uint32_t status; + + int retval = target_read_u32(bank->target, RSL10_FLASH_REG_IF_STATUS, &status); + if (retval != ERROR_OK) + return retval; + + if (bank->base == RSL10_FLASH_ADDRESS_MAIN) { + for (unsigned int i = 0; i < bank->num_prot_blocks; i++) + bank->prot_blocks[i].is_protected = (status & (1 << i)) ? 0 : 1; + + } else { + uint32_t test_bit = 0; + switch (bank->base) { + case RSL10_FLASH_ADDRESS_NVR1: + test_bit = RSL10_FLASH_REG_STATUS_NVR1_W_UNLOCKED; + break; + case RSL10_FLASH_ADDRESS_NVR2: + test_bit = RSL10_FLASH_REG_STATUS_NVR2_W_UNLOCKED; + break; + case RSL10_FLASH_ADDRESS_NVR3: + test_bit = RSL10_FLASH_REG_STATUS_NVR3_W_UNLOCKED; + break; + default: + break; + } + + bank->sectors[0].is_protected = (status & test_bit) ? 0 : 1; + } + return ERROR_OK; +} + +static int rsl10_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) +{ + + struct rsl10_info *chip; + int retval = rsl10_get_probed_chip_if_halted(bank, &chip); + if (retval != ERROR_OK) + return retval; + + if (bank->base == RSL10_FLASH_ADDRESS_MAIN) { + uint32_t status; + retval = target_read_u32(bank->target, RSL10_FLASH_REG_MAIN_CTRL, &status); + if (retval != ERROR_OK) + return retval; + + for (unsigned int i = first; i <= last; i++) { + if (set) + status &= ~(1 << i); + else + status |= (1 << i); + } + + retval = target_write_u32(bank->target, RSL10_FLASH_REG_MAIN_CTRL, status); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(bank->target, RSL10_FLASH_REG_MAIN_WRITE_UNLOCK, RSL10_FLASH_KEY_MAIN); + if (retval != ERROR_OK) + return retval; + } else { + uint32_t bit = 0; + switch (bank->base) { + case RSL10_FLASH_ADDRESS_NVR1: + bit = RSL10_FLASH_REG_NVR_CTRL_NVR1_W_ENABLE; + break; + case RSL10_FLASH_ADDRESS_NVR2: + bit = RSL10_FLASH_REG_NVR_CTRL_NVR2_W_ENABLE; + break; + case RSL10_FLASH_ADDRESS_NVR3: + bit = RSL10_FLASH_REG_NVR_CTRL_NVR3_W_ENABLE; + break; + default: + break; + } + + uint32_t status; + retval = target_read_u32(bank->target, RSL10_FLASH_REG_NVR_CTRL, &status); + if (retval != ERROR_OK) + return retval; + + if (set) + status &= ~bit; + else + status |= bit; + + retval = target_write_u32(bank->target, RSL10_FLASH_REG_NVR_CTRL, status); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(bank->target, RSL10_FLASH_REG_NVR_WRITE_UNLOCK, RSL10_FLASH_KEY_NVR); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +static int rsl10_check_device(struct flash_bank *bank) +{ + uint32_t configid; + int retval = target_read_u32(bank->target, RSL10_REG_ID, &configid); + if (retval != ERROR_OK) + return retval; + + if (configid != RSL10_ID) { + LOG_ERROR("This is not supported (RSL10) device, use other flash driver!!!"); + return ERROR_TARGET_INVALID; + } + return ERROR_OK; +} + +static int rsl10_probe(struct flash_bank *bank) +{ + struct rsl10_bank *nbank = bank->driver_priv; + struct rsl10_info *chip = nbank->chip; + + int retval = rsl10_check_device(bank); + if (retval != ERROR_OK) + return retval; + + unsigned int bank_id; + unsigned int num_prot_blocks = 0; + switch (bank->base) { + case RSL10_FLASH_ADDRESS_MAIN: + bank_id = 0; + num_prot_blocks = 3; + break; + case RSL10_FLASH_ADDRESS_NVR1: + bank_id = 1; + break; + case RSL10_FLASH_ADDRESS_NVR2: + bank_id = 2; + break; + case RSL10_FLASH_ADDRESS_NVR3: + bank_id = 3; + break; + default: + return ERROR_FAIL; + } + + uint32_t flash_page_size = 2048; + + bank->write_start_alignment = 8; + bank->write_end_alignment = 8; + + bank->num_sectors = bank->size / flash_page_size; + chip->flash_size_kb = bank->size / 1024; + + free(bank->sectors); + bank->sectors = NULL; + + bank->sectors = alloc_block_array(0, flash_page_size, bank->num_sectors); + if (!bank->sectors) + return ERROR_FAIL; + + free(bank->prot_blocks); + bank->prot_blocks = NULL; + + if (num_prot_blocks > 0) { + bank->num_prot_blocks = num_prot_blocks; + bank->prot_blocks = alloc_block_array(0, bank->num_sectors / 3 * flash_page_size, bank->num_prot_blocks); + if (!bank->prot_blocks) + return ERROR_FAIL; + } + + chip->bank[bank_id].probed = true; + return ERROR_OK; +} + +static int rsl10_auto_probe(struct flash_bank *bank) +{ + if (rsl10_bank_is_probed(bank)) + return ERROR_OK; + + return rsl10_probe(bank); +} + +static int rsl10_ll_flash_erase(struct rsl10_info *chip, uint32_t address) +{ + struct target *target = chip->target; + struct working_area *write_algorithm; + + LOG_DEBUG("erasing buffer flash address=0x%" PRIx32, address); + + int retval = target_alloc_working_area(target, sizeof(rsl10_rom_launcher_code), &write_algorithm); + if (retval != ERROR_OK) { + LOG_ERROR("Current working area 0x%x is too small! Increase working area size!", target->working_area_size); + return ERROR_FAIL; + } + + retval = + target_write_buffer(target, write_algorithm->address, sizeof(rsl10_rom_launcher_code), rsl10_rom_launcher_code); + if (retval != ERROR_OK) + goto free_algorithm; + + struct reg_param reg_params[3]; + struct armv7m_algorithm armv7m_info; + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* address */ + init_reg_param(®_params[1], "r3", 32, PARAM_OUT); /* cmd */ + init_reg_param(®_params[2], "sp", 32, PARAM_OUT); /* stack pointer */ + + buf_set_u32(reg_params[0].value, 0, 32, address); + uint32_t cmd; + retval = target_read_u32(target, RSL10_ROM_CMD_ERASE_SECTOR, &cmd); + if (retval != ERROR_OK) + goto free_reg_params; + buf_set_u32(reg_params[1].value, 0, 32, cmd); + buf_set_u32(reg_params[2].value, 0, 32, ALGO_STACK_POINTER_ADDR); + + retval = target_run_algorithm( + target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, write_algorithm->address, + write_algorithm->address + sizeof(rsl10_rom_launcher_code) - 2, 1000, &armv7m_info + ); + if (retval != ERROR_OK) + goto free_reg_params; + + int algo_ret = buf_get_u32(reg_params[0].value, 0, 32); + if (algo_ret != RSL10_FLASH_ERR_NONE) { + LOG_ERROR("RSL10 ERASE ERROR: '%s' (%d)", rsl10_error(algo_ret), algo_ret); + retval = ERROR_FLASH_SECTOR_NOT_ERASED; + } + +free_reg_params: + for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) + destroy_reg_param(®_params[i]); + +free_algorithm: + target_free_working_area(target, write_algorithm); + return retval; +} + +static int rsl10_ll_flash_write(struct rsl10_info *chip, uint32_t address, const uint8_t *buffer, uint32_t bytes) +{ + struct target *target = chip->target; + struct working_area *write_algorithm; + + if (bytes == 8) { + uint32_t data; + data = buf_get_u32(buffer, 0, 32); + LOG_DEBUG("Writing 0x%" PRIx32 " to flash address=0x%" PRIx32 " bytes=0x%" PRIx32, data, address, bytes); + } else + LOG_DEBUG("Writing buffer to flash address=0x%" PRIx32 " bytes=0x%" PRIx32, address, bytes); + + /* allocate working area with flash programming code */ + int retval = target_alloc_working_area(target, sizeof(rsl10_rom_launcher_code), &write_algorithm); + if (retval != ERROR_OK) { + LOG_ERROR("Current working area 0x%x is too small! Increase working area size!", target->working_area_size); + return ERROR_FAIL; + } + + retval = + target_write_buffer(target, write_algorithm->address, sizeof(rsl10_rom_launcher_code), rsl10_rom_launcher_code); + if (retval != ERROR_OK) + goto free_algorithm; + + /* memory buffer, rounded down, to be multiple of 8 */ + uint32_t buffer_avail = target_get_working_area_avail(target) & ~7; + uint32_t buffer_size = MIN(RSL10_ROM_CMD_WRITE_BUFFER_MAX_SIZE, buffer_avail); + struct working_area *source; + retval = target_alloc_working_area(target, buffer_size, &source); + if (retval != ERROR_OK) { + LOG_ERROR("Current working area 0x%x is too small! Increase working area size!", target->working_area_size); + goto free_algorithm; + } + + struct reg_param reg_params[5]; + struct armv7m_algorithm armv7m_info; + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* start addr, return value */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* length */ + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* data */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* cmd */ + init_reg_param(®_params[4], "sp", 32, PARAM_OUT); /* stack pointer */ + buf_set_u32(reg_params[4].value, 0, 32, ALGO_STACK_POINTER_ADDR); + + uint32_t cmd = 0; + uint32_t sent_bytes = 0; + uint32_t write_address = 0; + uint32_t bytes_to_send = 0; + uint32_t remaining_bytes = 0; + + retval = target_read_u32(target, RSL10_ROM_CMD_WRITE_BUFFER, &cmd); + if (retval != ERROR_OK) + goto free_everything; + + while (sent_bytes < bytes) { + remaining_bytes = bytes - sent_bytes; + bytes_to_send = remaining_bytes >= buffer_size ? buffer_size : remaining_bytes; + + retval = target_write_buffer(target, source->address, bytes_to_send, buffer + sent_bytes); + if (retval != ERROR_OK) + goto free_everything; + + write_address = address + sent_bytes; + + LOG_DEBUG( + "write_address: 0x%" PRIx32 ", words: 0x%" PRIx32 ", source: 0x%" PRIx64 ", cmd: 0x%" PRIx32, write_address, + bytes_to_send / 4, source->address, cmd + ); + buf_set_u32(reg_params[0].value, 0, 32, write_address); + buf_set_u32(reg_params[1].value, 0, 32, bytes_to_send / 4); + buf_set_u32(reg_params[2].value, 0, 32, source->address); + buf_set_u32(reg_params[3].value, 0, 32, cmd); + + retval = target_run_algorithm( + target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, write_algorithm->address, + write_algorithm->address + sizeof(rsl10_rom_launcher_code) - 2, 1000, &armv7m_info + ); + if (retval != ERROR_OK) + goto free_everything; + + int algo_ret = buf_get_u32(reg_params[0].value, 0, 32); + if (algo_ret != RSL10_FLASH_ERR_NONE) { + LOG_ERROR("RSL10 WRITE ERROR: '%s' (%d)", rsl10_error(algo_ret), algo_ret); + retval = ERROR_FLASH_OPERATION_FAILED; + goto free_everything; + } + + sent_bytes += bytes_to_send; + } + +free_everything: + target_free_working_area(target, source); + + for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) + destroy_reg_param(®_params[i]); + +free_algorithm: + target_free_working_area(target, write_algorithm); + + return retval; +} + +static int rsl10_mass_erase(struct target *target) +{ + struct working_area *write_algorithm; + + int retval = target_alloc_working_area(target, sizeof(rsl10_rom_launcher_code), &write_algorithm); + if (retval != ERROR_OK) { + LOG_ERROR("Current working area 0x%x is too small! Increase working area size!", target->working_area_size); + return ERROR_FAIL; + } + + retval = + target_write_buffer(target, write_algorithm->address, sizeof(rsl10_rom_launcher_code), rsl10_rom_launcher_code); + if (retval != ERROR_OK) + goto free_algorithm; + + struct reg_param reg_params[3]; + struct armv7m_algorithm armv7m_info; + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* return value */ + init_reg_param(®_params[1], "r3", 32, PARAM_OUT); /* cmd */ + init_reg_param(®_params[2], "sp", 32, PARAM_OUT); /* stack pointer */ + + uint32_t cmd; + retval = target_read_u32(target, RSL10_ROM_CMD_ERASE_ALL, &cmd); + if (retval != ERROR_OK) + goto free_reg_params; + buf_set_u32(reg_params[1].value, 0, 32, cmd); + buf_set_u32(reg_params[2].value, 0, 32, ALGO_STACK_POINTER_ADDR); + + retval = target_run_algorithm( + target, 0, NULL, ARRAY_SIZE(reg_params), reg_params, write_algorithm->address, + write_algorithm->address + sizeof(rsl10_rom_launcher_code) - 2, 1000, &armv7m_info + ); + if (retval != ERROR_OK) + goto free_reg_params; + + int algo_ret = buf_get_u32(reg_params[0].value, 0, 32); + if (algo_ret != RSL10_FLASH_ERR_NONE) { + LOG_ERROR("RSL10 MASS ERASE ERROR: '%s' (%d)", rsl10_error(algo_ret), algo_ret); + retval = ERROR_FLASH_OPERATION_FAILED; + } + +free_reg_params: + for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) + destroy_reg_param(®_params[i]); + +free_algorithm: + target_free_working_area(target, write_algorithm); + return retval; +} + +static int rsl10_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) +{ + struct rsl10_info *chip; + + int retval = rsl10_get_probed_chip_if_halted(bank, &chip); + if (retval != ERROR_OK) + return retval; + + return rsl10_ll_flash_write(chip, bank->base + offset, buffer, count); +} + +static int rsl10_erase(struct flash_bank *bank, unsigned int first, unsigned int last) +{ + LOG_INFO("erase bank: %x, %x", first, last); + int retval; + struct rsl10_info *chip; + + retval = rsl10_get_probed_chip_if_halted(bank, &chip); + if (retval != ERROR_OK) + return retval; + + for (unsigned int i = first; i <= last; i++) { + retval = rsl10_ll_flash_erase(chip, bank->base + i * 0x800); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +static void rsl10_free_driver_priv(struct flash_bank *bank) +{ + struct rsl10_bank *nbank = bank->driver_priv; + struct rsl10_info *chip = nbank->chip; + if (!chip) + return; + + chip->refcount--; + if (chip->refcount == 0) { + free(chip); + bank->driver_priv = NULL; + } +} + +static struct rsl10_info *rsl10_get_chip(struct target *target) +{ + struct flash_bank *bank_iter; + + /* iterate over rsl10 banks of same target */ + for (bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) { + if (bank_iter->driver != &rsl10_flash) + continue; + + if (bank_iter->target != target) + continue; + + struct rsl10_bank *nbank = bank_iter->driver_priv; + if (!nbank) + continue; + + if (nbank->chip) + return nbank->chip; + } + return NULL; +} + +FLASH_BANK_COMMAND_HANDLER(rsl10_flash_bank_command) +{ + struct rsl10_info *chip = NULL; + struct rsl10_bank *nbank = NULL; + LOG_INFO("Creating flash @ " TARGET_ADDR_FMT, bank->base); + + switch (bank->base) { + case RSL10_FLASH_ADDRESS_MAIN: + case RSL10_FLASH_ADDRESS_NVR1: + case RSL10_FLASH_ADDRESS_NVR2: + case RSL10_FLASH_ADDRESS_NVR3: + case RSL10_FLASH_ADDRESS_NVR4: + break; + default: + LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base); + return ERROR_FAIL; + } + + chip = rsl10_get_chip(bank->target); + if (!chip) { + chip = calloc(1, sizeof(*chip)); + if (!chip) + return ERROR_FAIL; + + chip->target = bank->target; + } + + switch (bank->base) { + case RSL10_FLASH_ADDRESS_MAIN: + nbank = &chip->bank[0]; + break; + case RSL10_FLASH_ADDRESS_NVR1: + nbank = &chip->bank[1]; + break; + case RSL10_FLASH_ADDRESS_NVR2: + nbank = &chip->bank[2]; + break; + case RSL10_FLASH_ADDRESS_NVR3: + nbank = &chip->bank[3]; + break; + case RSL10_FLASH_ADDRESS_NVR4: + nbank = &chip->bank[4]; + break; + } + assert(nbank); + + chip->refcount++; + nbank->chip = chip; + nbank->probed = false; + bank->driver_priv = nbank; + + return ERROR_OK; +} + +COMMAND_HANDLER(rsl10_lock_command) +{ + struct target *target = get_current_target(CMD_CTX); + + if (CMD_ARGC != 4) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = get_flash_bank_by_addr(target, RSL10_FLASH_ADDRESS_NVR3, true, &bank); + if (retval != ERROR_OK) + return retval; + + LOG_INFO("Keys used: %s %s %s %s", CMD_ARGV[0], CMD_ARGV[1], CMD_ARGV[2], CMD_ARGV[3]); + + uint32_t user_key[4]; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], user_key[0]); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], user_key[1]); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], user_key[2]); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], user_key[3]); + + uint8_t write_buffer[6 * 4]; + target_buffer_set_u32(target, write_buffer, RSL10_KEY_DEBUG_LOCK); + target_buffer_set_u32_array(target, &write_buffer[4], 4, user_key); + /* pad the end to 64-bit word boundary */ + memset(&write_buffer[5 * 4], bank->default_padded_value, 4); + + retval = rsl10_erase(bank, 0, 0); + if (retval != ERROR_OK) + return retval; + + retval = rsl10_write(bank, write_buffer, RSL10_NVR3_USER_KEY_OFFSET, sizeof(write_buffer)); + if (retval != ERROR_OK) { + /* erase sector, if write fails, otherwise it can lock debug with wrong keys */ + return rsl10_erase(bank, 0, 0); + } + + command_print( + CMD, "****** WARNING ******\n" + "rsl10 device has been successfully prepared to lock.\n" + "Debug port is locked after restart.\n" + "Unlock with 'rsl10_unlock key0 key1 key2 key3'\n" + "****** ....... ******\n" + ); + + return rsl10_protect(bank, true, 0, 0); +} + +COMMAND_HANDLER(rsl10_unlock_command) +{ + if (CMD_ARGC != 4) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + struct cortex_m_common *cortex_m = target_to_cm(target); + + struct adiv5_dap *dap = cortex_m->armv7m.arm.dap; + struct adiv5_ap *ap = dap_get_ap(dap, 0); + + uint32_t user_key[4]; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], user_key[0]); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], user_key[1]); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], user_key[2]); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], user_key[3]); + + uint8_t write_buffer1[4 * 4]; + target_buffer_set_u32_array(target, write_buffer1, 4, user_key); + int retval = mem_ap_write_buf(ap, write_buffer1, 4, 4, RSL10_FLASH_REG_DEBUG_UNLOCK_KEY1); + if (retval != ERROR_OK) { + dap_put_ap(ap); + return retval; + } + + dap_put_ap(ap); + + uint32_t key; + retval = mem_ap_read_atomic_u32(ap, RSL10_FLASH_ADDRESS_LOCK_INFO_SETTING, &key); + if (retval != ERROR_OK) + return retval; + LOG_INFO("mem read: 0x%08" PRIx32, key); + + if (key == RSL10_KEY_DEBUG_LOCK) { + retval = command_run_line(CMD_CTX, "reset init"); + if (retval != ERROR_OK) + return retval; + + struct flash_bank *bank; + retval = get_flash_bank_by_addr(target, RSL10_FLASH_ADDRESS_NVR3, true, &bank); + if (retval != ERROR_OK) + return retval; + + retval = rsl10_protect(bank, false, 0, 0); + if (retval != ERROR_OK) + return retval; + + uint8_t write_buffer2[4 * 2]; + target_buffer_set_u32(target, write_buffer2, 0x1); + /* pad the end to 64-bit word boundary */ + memset(&write_buffer2[4], bank->default_padded_value, 4); + + /* let it fail, because sector is not erased, maybe just erase all? */ + (void)rsl10_write(bank, write_buffer2, RSL10_NVR3_USER_KEY_OFFSET, sizeof(write_buffer2)); + command_print(CMD, "Debug port is unlocked!"); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(rsl10_mass_erase_command) +{ + if (CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + + int retval = rsl10_mass_erase(target); + if (retval != ERROR_OK) + return retval; + + command_print(CMD, "Mass erase was succesfull!"); + return ERROR_OK; +} + +static const struct command_registration rsl10_exec_command_handlers[] = { + { + .name = "lock", + .handler = rsl10_lock_command, + .mode = COMMAND_EXEC, + .help = "Lock rsl10 debug, with passed keys", + .usage = "key1 key2 key3 key4", + }, + { + .name = "unlock", + .handler = rsl10_unlock_command, + .mode = COMMAND_EXEC, + .help = "Unlock rsl10 debug, with passed keys", + .usage = "key1 key2 key3 key4", + }, + { + .name = "mass_erase", + .handler = rsl10_mass_erase_command, + .mode = COMMAND_EXEC, + .help = "Mass erase all unprotected flash areas", + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration rsl10_command_handlers[] = { + { + .name = "rsl10", + .mode = COMMAND_ANY, + .help = "rsl10 flash command group", + .usage = "", + .chain = rsl10_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +const struct flash_driver rsl10_flash = { + .name = "rsl10", + .commands = rsl10_command_handlers, + .flash_bank_command = rsl10_flash_bank_command, + .erase = rsl10_erase, + .protect = rsl10_protect, + .write = rsl10_write, + .read = default_flash_read, + .probe = rsl10_probe, + .auto_probe = rsl10_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = rsl10_protect_check, + .free_driver_priv = rsl10_free_driver_priv, +}; diff --git a/src/flash/nor/sfdp.c b/src/flash/nor/sfdp.c index 88d3b96f43..5bfb541946 100644 --- a/src/flash/nor/sfdp.c +++ b/src/flash/nor/sfdp.c @@ -1,17 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2019 by Andreas Bolsch <andreas.bolsch@mni.thm.de * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/sfdp.h b/src/flash/nor/sfdp.h index f924a4e55d..1c9af326b3 100644 --- a/src/flash/nor/sfdp.h +++ b/src/flash/nor/sfdp.h @@ -1,17 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2019 by Andreas Bolsch <andreas.bolsch@mni.thm.de * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_SFDP_H diff --git a/src/flash/nor/sh_qspi.c b/src/flash/nor/sh_qspi.c index 02af17acd6..e8ca626df0 100644 --- a/src/flash/nor/sh_qspi.c +++ b/src/flash/nor/sh_qspi.c @@ -1,4 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +// SPDX-License-Identifier: GPL-2.0-only + /* * SH QSPI (Quad SPI) driver * Copyright (C) 2019 Marek Vasut <marek.vasut@gmail.com> diff --git a/src/flash/nor/sim3x.c b/src/flash/nor/sim3x.c index 891383860a..42550d06bc 100644 --- a/src/flash/nor/sim3x.c +++ b/src/flash/nor/sim3x.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2014 by Ladislav Bábel * * ladababel@seznam.cz * * * * Copyright (C) 2015 by Andreas Bomholtz * * andreas@seluxit.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -872,16 +861,23 @@ static int sim3x_flash_info(struct flash_bank *bank, struct command_invocation * */ static int ap_write_register(struct adiv5_dap *dap, unsigned reg, uint32_t value) { - int retval; LOG_DEBUG("DAP_REG[0x%02x] <- %08" PRIX32, reg, value); - retval = dap_queue_ap_write(dap_ap(dap, SIM3X_AP), reg, value); + struct adiv5_ap *ap = dap_get_ap(dap, SIM3X_AP); + if (!ap) { + LOG_DEBUG("DAP: failed to get AP"); + return ERROR_FAIL; + } + + int retval = dap_queue_ap_write(ap, reg, value); if (retval != ERROR_OK) { LOG_DEBUG("DAP: failed to queue a write request"); + dap_put_ap(ap); return retval; } retval = dap_run(dap); + dap_put_ap(ap); if (retval != ERROR_OK) { LOG_DEBUG("DAP: dap_run failed"); return retval; @@ -892,15 +888,21 @@ static int ap_write_register(struct adiv5_dap *dap, unsigned reg, uint32_t value static int ap_read_register(struct adiv5_dap *dap, unsigned reg, uint32_t *result) { - int retval; + struct adiv5_ap *ap = dap_get_ap(dap, SIM3X_AP); + if (!ap) { + LOG_DEBUG("DAP: failed to get AP"); + return ERROR_FAIL; + } - retval = dap_queue_ap_read(dap_ap(dap, SIM3X_AP), reg, result); + int retval = dap_queue_ap_read(ap, reg, result); if (retval != ERROR_OK) { LOG_DEBUG("DAP: failed to queue a read request"); + dap_put_ap(ap); return retval; } retval = dap_run(dap); + dap_put_ap(ap); if (retval != ERROR_OK) { LOG_DEBUG("DAP: dap_run failed"); return retval; diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index 16b23a6175..bf654f9f6b 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2018 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2010 by Antonio Borneo * * borneo.antonio@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -33,8 +22,27 @@ /* Shared table of known SPI flash devices for SPI-based flash drivers. Taken * from device datasheets and Linux SPI flash drivers. */ const struct flash_device flash_devices[] = { - /* name, read_cmd, qread_cmd, pprog_cmd, erase_cmd, chip_erase_cmd, device_id, - * pagesize, sectorsize, size_in_bytes */ + /* Note: device_id is usually 3 bytes long, however the unused highest byte counts + * continuation codes for manufacturer id as per JEP106xx. + * + * All sizes (page, sector/block and flash) are in bytes. + * + * Guide to select a proper erase command (if both sector and block erase cmds are available): + * Use 4kbit sector erase cmd and set erase size to the size of sector for small devices + * (4Mbit and less, size <= 0x80000) to prevent too raw erase granularity. + * Use 64kbit block erase cmd and set erase size to the size of block for bigger devices + * (8Mbit and more, size >= 0x100000) to keep erase speed reasonable. + * If the device implements also 32kbit block erase, use it for 8Mbit, size == 0x100000. + */ + /* name read qread page erase chip device_id page erase flash + * _cmd _cmd _prog _cmd* _erase size size* size + * _cmd _cmd + */ + FLASH_ID("st m25pe10", 0x03, 0x00, 0x02, 0xd8, 0x00, 0x00118020, 0x100, 0x10000, 0x20000), + FLASH_ID("st m25pe20", 0x03, 0x00, 0x02, 0xd8, 0x00, 0x00128020, 0x100, 0x10000, 0x40000), + FLASH_ID("st m25pe40", 0x03, 0x00, 0x02, 0xd8, 0x00, 0x00138020, 0x100, 0x10000, 0x80000), + FLASH_ID("st m25pe80", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00148020, 0x100, 0x10000, 0x100000), + FLASH_ID("st m25pe16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00158020, 0x100, 0x10000, 0x200000), FLASH_ID("st m25p05", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000), FLASH_ID("st m25p10", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000), FLASH_ID("st m25p20", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000), @@ -62,12 +70,28 @@ const struct flash_device flash_devices[] = { FLASH_ID("cyp s25fl064l", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00176001, 0x100, 0x10000, 0x800000), FLASH_ID("cyp s25fl128l", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00186001, 0x100, 0x10000, 0x1000000), FLASH_ID("cyp s25fl256l", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x00196001, 0x100, 0x10000, 0x2000000), + FLASH_ID("cyp s28hl256t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x00195a34, 0x100, 0x40000, 0x2000000), /* page! */ + FLASH_ID("cyp s28hs256t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x00195b34, 0x100, 0x40000, 0x2000000), /* page! */ + FLASH_ID("cyp s28hl512t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a5a34, 0x100, 0x40000, 0x4000000), /* page! */ + FLASH_ID("cyp s28hs512t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a5b34, 0x100, 0x40000, 0x4000000), /* page! */ + FLASH_ID("cyp s28hl01gt", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001b5a34, 0x100, 0x40000, 0x8000000), /* page! */ + FLASH_ID("cyp s28hs01gt", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001b5b34, 0x100, 0x40000, 0x8000000), /* page! */ FLASH_ID("atmel 25f512", 0x03, 0x00, 0x02, 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000), FLASH_ID("atmel 25f1024", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000), FLASH_ID("atmel 25f2048", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000), FLASH_ID("atmel 25f4096", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000), FLASH_ID("atmel 25fs040", 0x03, 0x00, 0x02, 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000), + FLASH_ID("adesto 25sf041b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001841f, 0x100, 0x10000, 0x80000), FLASH_ID("adesto 25df081a", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001451f, 0x100, 0x10000, 0x100000), + FLASH_ID("adesto 25sf081b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001851f, 0x100, 0x10000, 0x100000), + FLASH_ID("adesto 25sf161b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001861f, 0x100, 0x10000, 0x200000), + FLASH_ID("adesto 25df321b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001471f, 0x100, 0x10000, 0x400000), + FLASH_ID("adesto 25sf321b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001871f, 0x100, 0x10000, 0x400000), + FLASH_ID("adesto 25xf641b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001881f, 0x100, 0x10000, 0x800000), /* sf/qf */ + FLASH_ID("adesto 25xf128a", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001891f, 0x100, 0x10000, 0x1000000), /* sf/qf */ + FLASH_ID("adesto xp032", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0700a743, 0x100, 0x10000, 0x400000), /* 4-byte */ + FLASH_ID("adesto xp064b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0001a81f, 0x100, 0x10000, 0x800000), /* 4-byte */ + FLASH_ID("adesto xp128", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0000a91f, 0x100, 0x10000, 0x1000000), /* 4-byte */ FLASH_ID("mac 25l512", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000), FLASH_ID("mac 25l1005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000), FLASH_ID("mac 25l2005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000), @@ -89,6 +113,9 @@ const struct flash_device flash_devices[] = { FLASH_ID("mac 25r3235f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001628c2, 0x100, 0x10000, 0x400000), FLASH_ID("mac 25r6435f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001728c2, 0x100, 0x10000, 0x800000), FLASH_ID("mac 25u1635e", 0x03, 0xeb, 0x02, 0x20, 0xc7, 0x003525c2, 0x100, 0x1000, 0x100000), + FLASH_ID("mac 66l1g45g", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001b20c2, 0x100, 0x10000, 0x8000000), + FLASH_ID("mac 66um1g45g", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x003b80c2, 0x100, 0x10000, 0x8000000), + FLASH_ID("mac 66lm1g45g", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x003b85c2, 0x100, 0x10000, 0x8000000), FLASH_ID("micron n25q032", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0016ba20, 0x100, 0x10000, 0x400000), FLASH_ID("micron n25q064", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000), FLASH_ID("micron n25q128", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000), @@ -98,7 +125,6 @@ const struct flash_device flash_devices[] = { FLASH_ID("micron mt25ql01", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0021ba20, 0x100, 0x10000, 0x8000000), FLASH_ID("micron mt25qu01", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0021bb20, 0x100, 0x10000, 0x8000000), FLASH_ID("micron mt25ql02", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0022ba20, 0x100, 0x10000, 0x10000000), - FLASH_ID("micron mt25qu01", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0021bb20, 0x100, 0x10000, 0x8000000), FLASH_ID("win w25q80bv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000), FLASH_ID("win w25q16jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001540ef, 0x100, 0x10000, 0x200000), FLASH_ID("win w25q16jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001570ef, 0x100, 0x10000, 0x200000), /* QPI / DTR */ @@ -114,6 +140,10 @@ const struct flash_device flash_devices[] = { FLASH_ID("win w25q256fv/jv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001940ef, 0x100, 0x10000, 0x2000000), FLASH_ID("win w25q256fv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001960ef, 0x100, 0x10000, 0x2000000), /* QPI mode */ FLASH_ID("win w25q256jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001970ef, 0x100, 0x10000, 0x2000000), + FLASH_ID("win w25q512jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x002040ef, 0x100, 0x10000, 0x4000000), + FLASH_ID("win w25q01jv", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x002140ef, 0x100, 0x10000, 0x8000000), + FLASH_ID("win w25q01jv-dtr", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x002170ef, 0x100, 0x10000, 0x8000000), + FLASH_ID("win w25q02jv-dtr", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x002270ef, 0x100, 0x10000, 0x10000000), FLASH_ID("gd gd25q512", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001040c8, 0x100, 0x1000, 0x10000), FLASH_ID("gd gd25q10", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001140c8, 0x100, 0x1000, 0x20000), FLASH_ID("gd gd25q20", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001240c8, 0x100, 0x1000, 0x40000), @@ -121,9 +151,18 @@ const struct flash_device flash_devices[] = { FLASH_ID("gd gd25q16c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000), FLASH_ID("gd gd25q32c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000), FLASH_ID("gd gd25q64c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001740c8, 0x100, 0x10000, 0x800000), - FLASH_ID("gd gd25q128c", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000), + FLASH_ID("gd gd25q128c", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000), FLASH_ID("gd gd25q256c", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x001940c8, 0x100, 0x10000, 0x2000000), FLASH_ID("gd gd25q512mc", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x002040c8, 0x100, 0x10000, 0x4000000), + FLASH_ID("gd gd25lx256e", 0x13, 0x0c, 0x12, 0xdc, 0xc7, 0x001968c8, 0x100, 0x10000, 0x2000000), + FLASH_ID("zbit zb25vq16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0015605e, 0x100, 0x10000, 0x200000), + FLASH_ID("zbit zb25vq32", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016405e, 0x100, 0x10000, 0x400000), + FLASH_ID("zbit zb25vq32", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016605e, 0x100, 0x10000, 0x400000), /* QPI mode */ + FLASH_ID("zbit zb25vq64", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017405e, 0x100, 0x10000, 0x800000), + FLASH_ID("zbit zb25vq64", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017605e, 0x100, 0x10000, 0x800000), /* QPI mode */ + FLASH_ID("zbit zb25vq128", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018405e, 0x100, 0x10000, 0x1000000), + FLASH_ID("zbit zb25vq128", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018605e, 0x100, 0x10000, 0x1000000), /* QPI mode */ + FLASH_ID("issi is25lq040b", 0x03, 0xeb, 0x02, 0x20, 0xc7, 0x0013409d, 0x100, 0x1000, 0x80000), FLASH_ID("issi is25lp032", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0016609d, 0x100, 0x10000, 0x400000), FLASH_ID("issi is25lp064", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0017609d, 0x100, 0x10000, 0x800000), FLASH_ID("issi is25lp128d", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018609d, 0x100, 0x10000, 0x1000000), @@ -132,8 +171,26 @@ const struct flash_device flash_devices[] = { FLASH_ID("issi is25wp256d", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019709d, 0x100, 0x10000, 0x2000000), FLASH_ID("issi is25lp512m", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a609d, 0x100, 0x10000, 0x4000000), FLASH_ID("issi is25wp512m", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a709d, 0x100, 0x10000, 0x4000000), + FLASH_ID("xtx xt25f02e", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0012400b, 0x100, 0x10000, 0x40000), + FLASH_ID("xtx xt25f04d", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0013400b, 0x100, 0x10000, 0x80000), + FLASH_ID("xtx xt25f08b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0014400b, 0x100, 0x10000, 0x100000), + FLASH_ID("xtx xt25f16b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0015400b, 0x100, 0x10000, 0x200000), + FLASH_ID("xtx xt25f32b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016400b, 0x100, 0x10000, 0x200000), + FLASH_ID("xtx xt25f64b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017400b, 0x100, 0x10000, 0x400000), + FLASH_ID("xtx xt25f128b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018400b, 0x100, 0x10000, 0x800000), + FLASH_ID("xtx xt25q08d", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0014600b, 0x100, 0x10000, 0x100000), + FLASH_ID("xtx xt25q16b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0015600b, 0x100, 0x10000, 0x200000), + FLASH_ID("xtx xt25q32b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016600b, 0x100, 0x10000, 0x400000), /* exists ? */ + FLASH_ID("xtx xt25q64b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017600b, 0x100, 0x10000, 0x800000), + FLASH_ID("xtx xt25q128b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018600b, 0x100, 0x10000, 0x1000000), + FLASH_ID("zetta zd25q16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001560ba, 0x100, 0x10000, 0x200000), /* FRAM, no erase commands, no write page or sectors */ + + /* name read qread page device_id total + * _cmd _cmd _prog size + * _cmd + */ FRAM_ID("fu mb85rs16n", 0x03, 0, 0x02, 0x00010104, 0x800), FRAM_ID("fu mb85rs32v", 0x03, 0, 0x02, 0x00010204, 0x1000), /* exists ? */ FRAM_ID("fu mb85rs64v", 0x03, 0, 0x02, 0x00020304, 0x2000), @@ -142,13 +199,30 @@ const struct flash_device flash_devices[] = { FRAM_ID("fu mb85rs512t", 0x03, 0, 0x02, 0x00032604, 0x10000), FRAM_ID("fu mb85rs1mt", 0x03, 0, 0x02, 0x00032704, 0x20000), FRAM_ID("fu mb85rs2mta", 0x03, 0, 0x02, 0x00034804, 0x40000), - FRAM_ID("cyp fm25v01a", 0x03, 0, 0x02, 0x000821c2, 0x4000), - FRAM_ID("cyp fm25v02", 0x03, 0, 0x02, 0x000022c2, 0x8000), - FRAM_ID("cyp fm25v02a", 0x03, 0, 0x02, 0x000822c2, 0x8000), - FRAM_ID("cyp fm25v05", 0x03, 0, 0x02, 0x000023c2, 0x10000), - FRAM_ID("cyp fm25v10", 0x03, 0, 0x02, 0x000024c2, 0x20000), - FRAM_ID("cyp fm25v20a", 0x03, 0, 0x02, 0x000825c2, 0x40000), - FRAM_ID("cyp fm25v40", 0x03, 0, 0x02, 0x004026c2, 0x80000), + FRAM_ID("cyp fm25v01a", 0x03, 0, 0x02, 0x060821c2, 0x4000), + FRAM_ID("cyp fm25v02", 0x03, 0, 0x02, 0x060022c2, 0x8000), + FRAM_ID("cyp fm25v02a", 0x03, 0, 0x02, 0x060822c2, 0x8000), + FRAM_ID("cyp fm25v05", 0x03, 0, 0x02, 0x060023c2, 0x10000), + FRAM_ID("cyp fm25v10", 0x03, 0, 0x02, 0x060024c2, 0x20000), + FRAM_ID("cyp fm25v20a", 0x03, 0, 0x02, 0x060825c2, 0x40000), + FRAM_ID("cyp fm25v40", 0x03, 0, 0x02, 0x064026c2, 0x80000), + FRAM_ID("cyp cy15b102qn", 0x03, 0, 0x02, 0x06002ac2, 0x40000), + FRAM_ID("cyp cy15v102qn", 0x03, 0, 0x02, 0x06042ac2, 0x40000), + FRAM_ID("cyp cy15b104qi", 0x03, 0, 0x02, 0x06012dc2, 0x80000), + FRAM_ID("cyp cy15b104qi", 0x03, 0, 0x02, 0x06a12dc2, 0x80000), + FRAM_ID("cyp cy15v104qi", 0x03, 0, 0x02, 0x06052dc2, 0x80000), + FRAM_ID("cyp cy15v104qi", 0x03, 0, 0x02, 0x06a52dc2, 0x80000), + FRAM_ID("cyp cy15b104qn", 0x03, 0, 0x02, 0x06402cc2, 0x80000), + FRAM_ID("cyp cy15b108qi", 0x03, 0, 0x02, 0x06012fc2, 0x100000), + FRAM_ID("cyp cy15b108qi", 0x03, 0, 0x02, 0x06a12fc2, 0x100000), + FRAM_ID("cyp cy15v108qi", 0x03, 0, 0x02, 0x06052fc2, 0x100000), + FRAM_ID("cyp cy15v108qi", 0x03, 0, 0x02, 0x06a52fc2, 0x100000), + FRAM_ID("cyp cy15b108qn", 0x03, 0, 0x02, 0x06012ec2, 0x100000), + FRAM_ID("cyp cy15b108qn", 0x03, 0, 0x02, 0x06032ec2, 0x100000), + FRAM_ID("cyp cy15b108qn", 0x03, 0, 0x02, 0x06a12ec2, 0x100000), + FRAM_ID("cyp cy15v108qn", 0x03, 0, 0x02, 0x06052ec2, 0x100000), + FRAM_ID("cyp cy15v108qn", 0x03, 0, 0x02, 0x06072ec2, 0x100000), + FRAM_ID("cyp cy15v108qn", 0x03, 0, 0x02, 0x06a52ec2, 0x100000), FLASH_ID(NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0) }; diff --git a/src/flash/nor/spi.h b/src/flash/nor/spi.h index f8a0a65801..807af12e78 100644 --- a/src/flash/nor/spi.h +++ b/src/flash/nor/spi.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2018-2019 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2010 by Antonio Borneo * * borneo.antonio@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_SPI_H diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index 6135c95745..972686e3f3 100644 --- a/src/flash/nor/stellaris.c +++ b/src/flash/nor/stellaris.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ /*************************************************************************** @@ -1353,7 +1342,7 @@ COMMAND_HANDLER(stellaris_handle_recover_command) * cycle to recover. */ - Jim_Eval_Named(CMD_CTX->interp, "catch { hla_command \"debug unlock\" }", 0, 0); + Jim_Eval_Named(CMD_CTX->interp, "catch { hla_command \"debug unlock\" }", NULL, 0); if (!strcmp(Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL), "0")) { retval = ERROR_OK; goto user_action; diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index b5b10af4c0..5a3c2da663 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2011 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * - * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -484,7 +473,7 @@ static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buff /* memory buffer */ buffer_size = target_get_working_area_avail(target); - buffer_size = MIN(hwords_count * 2, MAX(buffer_size, 256)); + buffer_size = MIN(hwords_count * 2 + 8, MAX(buffer_size, 256)); /* Normally we allocate all available working area. * MIN shrinks buffer_size if the size of the written block is smaller. * MAX prevents using async algo if the available working area is smaller @@ -754,8 +743,9 @@ static int stm32x_get_property_addr(struct target *target, struct stm32x_propert return ERROR_TARGET_NOT_EXAMINED; } - switch (cortex_m_get_partno_safe(target)) { + switch (cortex_m_get_impl_part(target)) { case CORTEX_M0_PARTNO: /* STM32F0x devices */ + case CORTEX_M0P_PARTNO: /* APM32F0x devices */ addr->device_id = 0x40015800; addr->flash_size = 0x1FFFF7CC; return ERROR_OK; @@ -1017,7 +1007,7 @@ static int stm32x_probe(struct flash_bank *bank) flash_size_in_kb = stm32x_info->user_bank_size / 1024; } - LOG_INFO("flash size = %dkbytes", flash_size_in_kb); + LOG_INFO("flash size = %d KiB", flash_size_in_kb); /* did we assign flash size? */ assert(flash_size_in_kb != 0xffff); @@ -1751,55 +1741,3 @@ const struct flash_driver stm32f1x_flash = { .info = get_stm32x_info, .free_driver_priv = default_flash_free_driver_priv, }; - -/* flash bank gd32vf103 <base> <size> 0 0 <target#> - */ -FLASH_BANK_COMMAND_HANDLER(gd32vf103_flash_bank_command) -{ - struct stm32x_flash_bank *stm32x_info; - - LOG_WARNING("DEPRECATED: The gd32vf103 flash target will be removed in June of 2023, please use stm32f1x instead."); - /* The reset code are just copy from stm32x_flash_bank_command function */ - if (CMD_ARGC < 6) - return ERROR_COMMAND_SYNTAX_ERROR; - - stm32x_info = malloc(sizeof(struct stm32x_flash_bank)); - - bank->driver_priv = stm32x_info; - stm32x_info->probed = false; - stm32x_info->has_dual_banks = false; - stm32x_info->can_load_options = false; - stm32x_info->register_base = FLASH_REG_BASE_B0; - stm32x_info->user_bank_size = bank->size; - - /* The flash write must be aligned to a halfword boundary */ - bank->write_start_alignment = bank->write_end_alignment = 2; - return ERROR_OK; -} - -static const struct command_registration gd32vf103_command_handlers[] = { - { - .name = "gd32vf103", - .mode = COMMAND_ANY, - .help = "gd32vf103 flash command group (identical to flash commands from stm32f1x)", - .usage = "", - .chain = stm32f1x_exec_command_handlers, - }, - COMMAND_REGISTRATION_DONE -}; - -const struct flash_driver gd32vf103_flash = { - .name = "gd32vf103", - .commands = gd32vf103_command_handlers, - .flash_bank_command = gd32vf103_flash_bank_command, - .erase = stm32x_erase, - .protect = stm32x_protect, - .write = stm32x_write, - .read = default_flash_read, - .probe = stm32x_probe, - .auto_probe = stm32x_auto_probe, - .erase_check = default_flash_blank_check, - .protect_check = stm32x_protect_check, - .info = get_stm32x_info, - .free_driver_priv = default_flash_free_driver_priv, -}; diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 622ef34235..4e0f731827 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2011 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -241,11 +230,11 @@ static int stm32x_otp_enable(struct flash_bank *bank) struct stm32x_flash_bank *stm32x_info = bank->driver_priv; if (!stm32x_info->otp_unlocked) { - LOG_INFO("OTP memory bank #%u is is enabled for write commands.", + LOG_INFO("OTP memory bank #%u is enabled for write commands.", bank->bank_number); stm32x_info->otp_unlocked = true; } else { - LOG_WARNING("OTP memory bank #%u is is already enabled for write commands.", + LOG_WARNING("OTP memory bank #%u is already enabled for write commands.", bank->bank_number); } return ERROR_OK; @@ -670,8 +659,10 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, } if (stm32x_is_otp(bank)) { - if (!set) + if (!set) { + LOG_ERROR("OTP protection can only be enabled"); return ERROR_COMMAND_ARGUMENT_INVALID; + } return stm32x_otp_protect(bank, first, last); } @@ -970,7 +961,7 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) return retval; if ((*device_id & 0xfff) == 0x411 - && cortex_m_get_partno_safe(target) == CORTEX_M4_PARTNO) { + && cortex_m_get_impl_part(target) == CORTEX_M4_PARTNO) { *device_id &= ~((0xFFFF << 16) | 0xfff); *device_id |= (0x1000 << 16) | 0x413; LOG_INFO("stm32f4x errata detected - fixing incorrect MCU_IDCODE"); @@ -1136,7 +1127,7 @@ static int stm32x_probe(struct flash_bank *bank) flash_size_in_kb = stm32x_info->user_bank_size / 1024; } - LOG_INFO("flash size = %" PRIu16 " kbytes", flash_size_in_kb); + LOG_INFO("flash size = %" PRIu16 " KiB", flash_size_in_kb); /* did we assign flash size? */ assert(flash_size_in_kb != 0xffff); @@ -1549,10 +1540,8 @@ static int stm32x_mass_erase(struct flash_bank *bank) COMMAND_HANDLER(stm32x_handle_mass_erase_command) { - if (CMD_ARGC < 1) { - command_print(CMD, "stm32x mass_erase <bank>"); + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); @@ -1575,10 +1564,8 @@ COMMAND_HANDLER(stm32f2x_handle_options_read_command) struct flash_bank *bank; struct stm32x_flash_bank *stm32x_info = NULL; - if (CMD_ARGC != 1) { - command_print(CMD, "stm32f2x options_read <bank>"); + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - } retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) @@ -1621,10 +1608,8 @@ COMMAND_HANDLER(stm32f2x_handle_options_write_command) struct stm32x_flash_bank *stm32x_info = NULL; uint16_t user_options, boot_addr0, boot_addr1, options_mask; - if (CMD_ARGC < 1) { - command_print(CMD, "stm32f2x options_write <bank> ..."); + if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; - } retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) @@ -1636,19 +1621,14 @@ COMMAND_HANDLER(stm32f2x_handle_options_write_command) stm32x_info = bank->driver_priv; if (stm32x_info->has_boot_addr) { - if (CMD_ARGC != 4) { - command_print(CMD, "stm32f2x options_write <bank> <user_options>" - " <boot_addr0> <boot_addr1>"); + if (CMD_ARGC != 4) return ERROR_COMMAND_SYNTAX_ERROR; - } + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[2], boot_addr0); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[3], boot_addr1); stm32x_info->option_bytes.boot_addr = boot_addr0 | (((uint32_t) boot_addr1) << 16); - } else { - if (CMD_ARGC != 2) { - command_print(CMD, "stm32f2x options_write <bank> <user_options>"); - return ERROR_COMMAND_SYNTAX_ERROR; - } + } else if (CMD_ARGC != 2) { + return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], user_options); @@ -1683,10 +1663,8 @@ COMMAND_HANDLER(stm32f2x_handle_optcr2_write_command) struct stm32x_flash_bank *stm32x_info = NULL; uint32_t optcr2_pcrop; - if (CMD_ARGC != 2) { - command_print(CMD, "stm32f2x optcr2_write <bank> <optcr2_value>"); + if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; - } retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) @@ -1720,10 +1698,8 @@ COMMAND_HANDLER(stm32f2x_handle_optcr2_write_command) COMMAND_HANDLER(stm32x_handle_otp_command) { - if (CMD_ARGC < 2) { - command_print(CMD, "stm32x otp <bank> (enable|disable|show)"); + if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; - } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); @@ -1796,7 +1772,7 @@ static const struct command_registration stm32f2x_exec_command_handlers[] = { .name = "otp", .handler = stm32x_handle_otp_command, .mode = COMMAND_EXEC, - .usage = "bank_id", + .usage = "bank_id (enable|disable|show)", .help = "OTP (One Time Programmable) memory write enable/disable.", }, COMMAND_REGISTRATION_DONE diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index d2914eb39d..c02fae992c 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2017 by STMicroelectronics * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" @@ -806,7 +795,7 @@ static int stm32x_probe(struct flash_bank *bank) /* STM32H74x/H75x, the second core (Cortex-M4) cannot read the flash size */ retval = ERROR_FAIL; if (device_id == DEVID_STM32H74_H75XX - && cortex_m_get_partno_safe(target) == CORTEX_M4_PARTNO) + && cortex_m_get_impl_part(target) == CORTEX_M4_PARTNO) LOG_WARNING("%s cannot read the flash size register", target_name(target)); else retval = target_read_u16(target, stm32x_info->part_info->fsize_addr, &flash_size_in_kb); @@ -1091,10 +1080,8 @@ static int stm32x_mass_erase(struct flash_bank *bank) COMMAND_HANDLER(stm32x_handle_mass_erase_command) { - if (CMD_ARGC < 1) { - command_print(CMD, "stm32h7x mass_erase <bank>"); + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); @@ -1112,10 +1099,8 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command) COMMAND_HANDLER(stm32x_handle_option_read_command) { - if (CMD_ARGC < 2) { - command_print(CMD, "stm32h7x option_read <bank> <option_reg offset>"); + if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; - } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); @@ -1137,10 +1122,8 @@ COMMAND_HANDLER(stm32x_handle_option_read_command) COMMAND_HANDLER(stm32x_handle_option_write_command) { - if (CMD_ARGC < 3) { - command_print(CMD, "stm32h7x option_write <bank> <option_reg offset> <value> [mask]"); + if (CMD_ARGC != 3 && CMD_ARGC != 4) return ERROR_COMMAND_SYNTAX_ERROR; - } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 7b35a06353..039938512b 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2015 by Uwe Bonnes * * bon@elektron.ikp.physik.tu-darmstadt.de * * * * Copyright (C) 2019 by Tarek Bochkati for STMicroelectronics * * tarek.bouchkati@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -68,6 +57,9 @@ */ /* STM32WBxxx series for reference. + * + * RM0493 (STM32WBA52x) + * http://www.st.com/resource/en/reference_manual/dm00821869.pdf * * RM0434 (STM32WB55/WB35x) * http://www.st.com/resource/en/reference_manual/dm00318631.pdf @@ -91,6 +83,12 @@ * http://www.st.com/resource/en/reference_manual/dm00451556.pdf */ +/* STM32C0xxx series for reference. + * + * RM0490 (STM32C0x1) + * http://www.st.com/resource/en/reference_manual/dm00781702.pdf + */ + /* STM32G0xxx series for reference. * * RM0444 (STM32G0x1) @@ -274,7 +272,7 @@ struct stm32l4_wrp { }; /* human readable list of families this drivers supports (sorted alphabetically) */ -static const char *device_families = "STM32G0/G4/L4/L4+/L5/U5/WB/WL"; +static const char *device_families = "STM32C0/G0/G4/L4/L4+/L5/U5/WB/WL"; static const struct stm32l4_rev stm32l47_l48xx_revs[] = { { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" } @@ -284,6 +282,15 @@ static const struct stm32l4_rev stm32l43_l44xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; + +static const struct stm32l4_rev stm32c01xx_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, +}; + +static const struct stm32l4_rev stm32c03xx_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, +}; + static const struct stm32l4_rev stm32g05_g06xx_revs[] = { { 0x1000, "A" }, }; @@ -300,7 +307,7 @@ static const struct stm32l4_rev stm32l45_l46xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; -static const struct stm32l4_rev stm32l41_L42xx_revs[] = { +static const struct stm32l4_rev stm32l41_l42xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; @@ -322,6 +329,7 @@ static const struct stm32l4_rev stm32g47_g48xx_revs[] = { static const struct stm32l4_rev stm32l4r_l4sxx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x100F, "W" }, + { 0x101F, "V" }, }; static const struct stm32l4_rev stm32l4p_l4qxx_revs[] = { @@ -329,7 +337,7 @@ static const struct stm32l4_rev stm32l4p_l4qxx_revs[] = { }; static const struct stm32l4_rev stm32l55_l56xx_revs[] = { - { 0x1000, "A" }, { 0x2000, "B" }, + { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, }; static const struct stm32l4_rev stm32g49_g4axx_revs[] = { @@ -338,6 +346,11 @@ static const struct stm32l4_rev stm32g49_g4axx_revs[] = { static const struct stm32l4_rev stm32u57_u58xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2000, "B" }, + { 0x2001, "X" }, { 0x3000, "C" }, +}; + +static const struct stm32l4_rev stm32wba5x_revs[] = { + { 0x1000, "A" }, }; static const struct stm32l4_rev stm32wb1xx_revs[] = { @@ -381,6 +394,30 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_base = 0x1FFF7000, .otp_size = 1024, }, + { + .id = DEVID_STM32C01XX, + .revs = stm32c01xx_revs, + .num_revs = ARRAY_SIZE(stm32c01xx_revs), + .device_str = "STM32C01xx", + .max_flash_size_kb = 32, + .flags = F_NONE, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75A0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, + }, + { + .id = DEVID_STM32C03XX, + .revs = stm32c03xx_revs, + .num_revs = ARRAY_SIZE(stm32c03xx_revs), + .device_str = "STM32C03xx", + .max_flash_size_kb = 32, + .flags = F_NONE, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75A0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, + }, { .id = DEVID_STM32G05_G06XX, .revs = stm32g05_g06xx_revs, @@ -431,8 +468,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = { }, { .id = DEVID_STM32L41_L42XX, - .revs = stm32l41_L42xx_revs, - .num_revs = ARRAY_SIZE(stm32l41_L42xx_revs), + .revs = stm32l41_l42xx_revs, + .num_revs = ARRAY_SIZE(stm32l41_l42xx_revs), .device_str = "STM32L41/L42xx", .max_flash_size_kb = 128, .flags = F_NONE, @@ -549,6 +586,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_base = 0x0BFA0000, .otp_size = 512, }, + { + .id = DEVID_STM32WBA5X, + .revs = stm32wba5x_revs, + .num_revs = ARRAY_SIZE(stm32wba5x_revs), + .device_str = "STM32WBA5x", + .max_flash_size_kb = 1024, + .flags = F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x0FF907A0, + .otp_base = 0x0FF90000, + .otp_size = 512, + }, { .id = DEVID_STM32WB1XX, .revs = stm32wb1xx_revs, @@ -1078,7 +1127,7 @@ static int stm32l4_get_all_wrpxy(struct flash_bank *bank, enum stm32_bank_id dev if (dev_bank_id != STM32_BANK1 && stm32l4_info->dual_bank_mode) wrp2y_sectors_offset = stm32l4_info->bank1_sectors; - if (wrp2y_sectors_offset > -1) { + if (wrp2y_sectors_offset >= 0) { /* get WRP2AR */ ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP2AR_INDEX, wrp2y_sectors_offset); if (ret != ERROR_OK) @@ -1220,49 +1269,11 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first, return retval2; } -static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) +static int stm32l4_protect_same_bank(struct flash_bank *bank, enum stm32_bank_id bank_id, int set, + unsigned int first, unsigned int last) { - struct target *target = bank->target; - struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; - int ret = ERROR_OK; unsigned int i; - if (stm32l4_is_otp(bank)) { - LOG_ERROR("cannot protect/unprotect OTP memory"); - return ERROR_FLASH_OPER_UNSUPPORTED; - } - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* the requested sectors could be located into bank1 and/or bank2 */ - bool use_bank2 = false; - if (last >= stm32l4_info->bank1_sectors) { - if (first < stm32l4_info->bank1_sectors) { - /* the requested sectors for (un)protection are shared between - * bank 1 and 2, then split the operation */ - - /* 1- deal with bank 1 sectors */ - LOG_DEBUG("The requested sectors for %s are shared between bank 1 and 2", - set ? "protection" : "unprotection"); - ret = stm32l4_protect(bank, set, first, stm32l4_info->bank1_sectors - 1); - if (ret != ERROR_OK) - return ret; - - /* 2- then continue with bank 2 sectors */ - first = stm32l4_info->bank1_sectors; - } - - use_bank2 = true; - } - - /* refresh the sectors' protection */ - ret = stm32l4_protect_check(bank); - if (ret != ERROR_OK) - return ret; - /* check if the desired protection is already configured */ for (i = first; i <= last; i++) { if (bank->sectors[i].is_protected != set) @@ -1278,7 +1289,7 @@ static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int n_wrp; struct stm32l4_wrp wrpxy[4]; - ret = stm32l4_get_all_wrpxy(bank, use_bank2 ? STM32_BANK2 : STM32_BANK1, wrpxy, &n_wrp); + int ret = stm32l4_get_all_wrpxy(bank, bank_id, wrpxy, &n_wrp); if (ret != ERROR_OK) return ret; @@ -1349,6 +1360,40 @@ static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, return stm32l4_write_all_wrpxy(bank, wrpxy, n_wrp); } +static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) +{ + struct target *target = bank->target; + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + + if (stm32l4_is_otp(bank)) { + LOG_ERROR("cannot protect/unprotect OTP memory"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* refresh the sectors' protection */ + int ret = stm32l4_protect_check(bank); + if (ret != ERROR_OK) + return ret; + + /* the requested sectors could be located into bank1 and/or bank2 */ + if (last < stm32l4_info->bank1_sectors) { + return stm32l4_protect_same_bank(bank, STM32_BANK1, set, first, last); + } else if (first >= stm32l4_info->bank1_sectors) { + return stm32l4_protect_same_bank(bank, STM32_BANK2, set, first, last); + } else { + ret = stm32l4_protect_same_bank(bank, STM32_BANK1, set, first, stm32l4_info->bank1_sectors - 1); + if (ret != ERROR_OK) + return ret; + + return stm32l4_protect_same_bank(bank, STM32_BANK2, set, stm32l4_info->bank1_sectors, last); + } +} + /* count is the size divided by stm32l4_info->data_width */ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) @@ -1656,7 +1701,7 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) /* CPU2 (Cortex-M0+) is supported only with non-hla adapters because it is on AP1. * Using HLA adapters armv7m.debug_ap is null, and checking ap_num triggers a segfault */ - if (cortex_m_get_partno_safe(target) == CORTEX_M0P_PARTNO && + if (cortex_m_get_impl_part(target) == CORTEX_M0P_PARTNO && armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) { uint32_t uid64_ids; @@ -1755,7 +1800,8 @@ static int stm32l4_probe(struct flash_bank *bank) /* Set flash write alignment boundaries. * Ask the flash infrastructure to ensure required alignment */ - bank->write_start_alignment = bank->write_end_alignment = stm32l4_info->data_width; + bank->write_start_alignment = stm32l4_info->data_width; + bank->write_end_alignment = stm32l4_info->data_width; /* Initialize the flash registers layout */ if (part_info->flags & F_HAS_L5_FLASH_REGS) @@ -1831,7 +1877,7 @@ static int stm32l4_probe(struct flash_bank *bank) flash_size_kb = stm32l4_info->user_bank_size / 1024; } - LOG_INFO("flash size = %dkbytes", flash_size_kb); + LOG_INFO("flash size = %d KiB", flash_size_kb); /* did we assign a flash size? */ assert((flash_size_kb != 0xffff) && flash_size_kb); @@ -1868,6 +1914,8 @@ static int stm32l4_probe(struct flash_bank *bank) } break; case DEVID_STM32L43_L44XX: + case DEVID_STM32C01XX: + case DEVID_STM32C03XX: case DEVID_STM32G05_G06XX: case DEVID_STM32G07_G08XX: case DEVID_STM32L45_L46XX: @@ -1964,6 +2012,12 @@ static int stm32l4_probe(struct flash_bank *bank) stm32l4_info->bank1_sectors = num_pages / 2; } break; + case DEVID_STM32WBA5X: + /* single bank flash */ + page_size_kb = 8; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + break; case DEVID_STM32WB5XX: case DEVID_STM32WB3XX: /* single bank flash */ @@ -1987,6 +2041,15 @@ static int stm32l4_probe(struct flash_bank *bank) return ERROR_FAIL; } + /* ensure that at least there is 1 flash sector / page */ + if (num_pages == 0) { + if (stm32l4_info->user_bank_size) + LOG_ERROR("The specified flash size is less than page size"); + + LOG_ERROR("Flash pages count cannot be zero"); + return ERROR_FAIL; + } + LOG_INFO("flash mode : %s-bank", stm32l4_info->dual_bank_mode ? "dual" : "single"); const int gap_size_kb = stm32l4_info->hole_sectors * page_size_kb; @@ -2155,10 +2218,8 @@ static int stm32l4_mass_erase(struct flash_bank *bank) COMMAND_HANDLER(stm32l4_handle_mass_erase_command) { - if (CMD_ARGC < 1) { - command_print(CMD, "stm32l4x mass_erase <STM32L4 bank>"); + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); @@ -2176,10 +2237,8 @@ COMMAND_HANDLER(stm32l4_handle_mass_erase_command) COMMAND_HANDLER(stm32l4_handle_option_read_command) { - if (CMD_ARGC < 2) { - command_print(CMD, "stm32l4x option_read <STM32L4 bank> <option_reg offset>"); + if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; - } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); @@ -2203,10 +2262,8 @@ COMMAND_HANDLER(stm32l4_handle_option_read_command) COMMAND_HANDLER(stm32l4_handle_option_write_command) { - if (CMD_ARGC < 3) { - command_print(CMD, "stm32l4x option_write <STM32L4 bank> <option_reg offset> <value> [mask]"); + if (CMD_ARGC != 3 && CMD_ARGC != 4) return ERROR_COMMAND_SYNTAX_ERROR; - } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); @@ -2318,7 +2375,7 @@ COMMAND_HANDLER(stm32l4_handle_lock_command) { struct target *target = NULL; - if (CMD_ARGC < 1) + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; @@ -2353,7 +2410,7 @@ COMMAND_HANDLER(stm32l4_handle_unlock_command) { struct target *target = NULL; - if (CMD_ARGC < 1) + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; @@ -2457,7 +2514,7 @@ COMMAND_HANDLER(stm32l4_handle_wrp_info_command) COMMAND_HANDLER(stm32l4_handle_otp_command) { - if (CMD_ARGC < 2) + if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h index 4458c08756..3dc0909554 100644 --- a/src/flash/nor/stm32l4x.h +++ b/src/flash/nor/stm32l4x.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2015 by Uwe Bonnes * * bon@elektron.ikp.physik.tu-darmstadt.de * - * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_STM32L4X @@ -98,6 +87,8 @@ /* Supported device IDs */ #define DEVID_STM32L47_L48XX 0x415 #define DEVID_STM32L43_L44XX 0x435 +#define DEVID_STM32C01XX 0x443 +#define DEVID_STM32C03XX 0x453 #define DEVID_STM32G05_G06XX 0x456 #define DEVID_STM32G07_G08XX 0x460 #define DEVID_STM32L49_L4AXX 0x461 @@ -112,6 +103,7 @@ #define DEVID_STM32L55_L56XX 0x472 #define DEVID_STM32G49_G4AXX 0x479 #define DEVID_STM32U57_U58XX 0x482 +#define DEVID_STM32WBA5X 0x492 #define DEVID_STM32WB1XX 0x494 #define DEVID_STM32WB5XX 0x495 #define DEVID_STM32WB3XX 0x496 diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index f6a8ffceba..1459e942d1 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2011 by Clement Burin des Roziers * * clement.burin-des-roziers@hikob.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -143,7 +132,7 @@ static const struct stm32lx_rev stm32_417_revs[] = { { 0x1000, "A" }, { 0x1008, "Z" }, { 0x1018, "Y" }, { 0x1038, "X" } }; static const struct stm32lx_rev stm32_425_revs[] = { - { 0x1000, "A" }, { 0x2000, "B" }, { 0x2008, "Y" }, + { 0x1000, "A" }, { 0x2000, "B" }, { 0x2008, "Y" }, { 0x2018, "1, X" }, }; static const struct stm32lx_rev stm32_427_revs[] = { { 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" }, { 0x10f8, "V" }, @@ -152,7 +141,7 @@ static const struct stm32lx_rev stm32_429_revs[] = { { 0x1000, "A" }, { 0x1018, "Z" }, }; static const struct stm32lx_rev stm32_436_revs[] = { - { 0x1000, "A" }, { 0x1008, "Z" }, { 0x1018, "Y" }, + { 0x1000, "A" }, { 0x1008, "Z" }, { 0x1018, "Y" }, { 0x1038, "X" }, }; static const struct stm32lx_rev stm32_437_revs[] = { { 0x1000, "A" }, @@ -901,10 +890,11 @@ static int stm32lx_get_info(struct flash_bank *bank, struct command_invocation * if (rev_id == info->revs[i].rev) rev_str = info->revs[i].str; - if (rev_str) + if (rev_str) { command_print_sameline(cmd, "%s - Rev: %s", info->device_str, rev_str); - else + } else { command_print_sameline(cmd, "%s - Rev: unknown (0x%04x)", info->device_str, rev_id); + } return ERROR_OK; } diff --git a/src/flash/nor/stmqspi.c b/src/flash/nor/stmqspi.c index 8278601db2..a1e1d34116 100644 --- a/src/flash/nor/stmqspi.c +++ b/src/flash/nor/stmqspi.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2016 - 2019 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * * * * Copyright (C) 2010 by Antonio Borneo * * borneo.antonio@gmail.com * - * * - * 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/>. * ***************************************************************************/ /* STM QuadSPI (QSPI) and OctoSPI (OCTOSPI) controller are SPI bus controllers @@ -627,8 +616,6 @@ COMMAND_HANDLER(stmqspi_handle_set) LOG_DEBUG("%s", __func__); - dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; - /* chip_erase_cmd, sectorsize and erase_cmd are optional */ if ((CMD_ARGC < 7) || (CMD_ARGC > 10)) return ERROR_COMMAND_SYNTAX_ERROR; @@ -639,8 +626,9 @@ COMMAND_HANDLER(stmqspi_handle_set) target = bank->target; stmqspi_info = bank->driver_priv; + dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; - /* invalidate all old info */ + /* invalidate all flash device info */ if (stmqspi_info->probed) free(bank->sectors); bank->size = 0; @@ -658,21 +646,21 @@ COMMAND_HANDLER(stmqspi_handle_set) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], stmqspi_info->dev.size_in_bytes); if (log2u(stmqspi_info->dev.size_in_bytes) < 8) { command_print(CMD, "stmqspi: device size must be 2^n with n >= 8"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], stmqspi_info->dev.pagesize); if (stmqspi_info->dev.pagesize > stmqspi_info->dev.size_in_bytes || (log2u(stmqspi_info->dev.pagesize) < 0)) { command_print(CMD, "stmqspi: page size must be 2^n and <= device size"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.read_cmd); if ((stmqspi_info->dev.read_cmd != 0x03) && (stmqspi_info->dev.read_cmd != 0x13)) { command_print(CMD, "stmqspi: only 0x03/0x13 READ cmd allowed"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.qread_cmd); @@ -690,7 +678,7 @@ COMMAND_HANDLER(stmqspi_handle_set) (stmqspi_info->dev.qread_cmd != 0xEE)) { command_print(CMD, "stmqspi: only 0x0B/0x0C/0x3B/0x3C/" "0x6B/0x6C/0xBB/0xBC/0xEB/0xEC/0xEE QREAD allowed"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.pprog_cmd); @@ -698,7 +686,7 @@ COMMAND_HANDLER(stmqspi_handle_set) (stmqspi_info->dev.pprog_cmd != 0x12) && (stmqspi_info->dev.pprog_cmd != 0x32)) { command_print(CMD, "stmqspi: only 0x02/0x12/0x32 PPRG cmd allowed"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } if (index < CMD_ARGC) @@ -712,7 +700,7 @@ COMMAND_HANDLER(stmqspi_handle_set) (stmqspi_info->dev.sectorsize < stmqspi_info->dev.pagesize) || (log2u(stmqspi_info->dev.sectorsize) < 0)) { command_print(CMD, "stmqspi: sector size must be 2^n and <= device size"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } if (index < CMD_ARGC) @@ -732,10 +720,8 @@ COMMAND_HANDLER(stmqspi_handle_set) uint32_t dcr; retval = target_read_u32(target, io_base + SPI_DCR, &dcr); - if (retval != ERROR_OK) return retval; - fsize = (dcr >> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1); LOG_DEBUG("FSIZE = 0x%04x", fsize); @@ -765,13 +751,13 @@ COMMAND_HANDLER(stmqspi_handle_set) bank->sectors = sectors; stmqspi_info->dev.name = stmqspi_info->devname; if (stmqspi_info->dev.size_in_bytes / 4096) - LOG_INFO("flash \'%s\' id = unknown\nchip size = %" PRIu32 "kbytes," - " bank size = %" PRIu32 "kbytes", stmqspi_info->dev.name, + LOG_INFO("flash \'%s\' id = unknown\nchip size = %" PRIu32 " KiB," + " bank size = %" PRIu32 " KiB", stmqspi_info->dev.name, stmqspi_info->dev.size_in_bytes / 1024, (stmqspi_info->dev.size_in_bytes / 1024) << dual); else - LOG_INFO("flash \'%s\' id = unknown\nchip size = %" PRIu32 "bytes," - " bank size = %" PRIu32 "bytes", stmqspi_info->dev.name, + LOG_INFO("flash \'%s\' id = unknown\nchip size = %" PRIu32 " B," + " bank size = %" PRIu32 " B", stmqspi_info->dev.name, stmqspi_info->dev.size_in_bytes, stmqspi_info->dev.size_in_bytes << dual); @@ -800,7 +786,7 @@ COMMAND_HANDLER(stmqspi_handle_cmd) num_write = CMD_ARGC - 2; if (num_write > max) { LOG_ERROR("at most %d bytes may be sent", max); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); @@ -825,7 +811,7 @@ COMMAND_HANDLER(stmqspi_handle_cmd) if (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) { if ((num_write & 1) == 0) { LOG_ERROR("number of data bytes to write must be even in dual mode"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } } } else { @@ -833,12 +819,12 @@ COMMAND_HANDLER(stmqspi_handle_cmd) if (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) { if ((num_read & 1) != 0) { LOG_ERROR("number of bytes to read must be even in dual mode"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } } if ((num_write < 1) || (num_write > 5)) { LOG_ERROR("one cmd and up to four addr bytes must be send when reading"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } } @@ -1810,7 +1796,6 @@ static int find_sfdp_dummy(struct flash_bank *bank, int len) } } - retval = ERROR_FAIL; LOG_DEBUG("no start of SFDP header even after %u dummy bytes", count); err: @@ -2092,16 +2077,17 @@ static int stmqspi_probe(struct flash_bank *bank) bool octal_dtr; int retval; - if (stmqspi_info->probed) { - bank->size = 0; - bank->num_sectors = 0; + /* invalidate all flash device info */ + if (stmqspi_info->probed) free(bank->sectors); - bank->sectors = NULL; - memset(&stmqspi_info->dev, 0, sizeof(stmqspi_info->dev)); - stmqspi_info->sfdp_dummy1 = 0; - stmqspi_info->sfdp_dummy2 = 0; - stmqspi_info->probed = false; - } + bank->size = 0; + bank->num_sectors = 0; + bank->sectors = NULL; + stmqspi_info->sfdp_dummy1 = 0; + stmqspi_info->sfdp_dummy2 = 0; + stmqspi_info->probed = false; + memset(&stmqspi_info->dev, 0, sizeof(stmqspi_info->dev)); + stmqspi_info->dev.name = "unknown"; /* Abort any previous operation */ retval = stmqspi_abort(bank); @@ -2116,8 +2102,8 @@ static int stmqspi_probe(struct flash_bank *bank) /* check whether QSPI_ABR is writeable and readback returns the value written */ retval = target_write_u32(target, io_base + QSPI_ABR, magic); if (retval == ERROR_OK) { - retval = target_read_u32(target, io_base + QSPI_ABR, &data); - retval = target_write_u32(target, io_base + QSPI_ABR, 0); + (void)target_read_u32(target, io_base + QSPI_ABR, &data); + (void)target_write_u32(target, io_base + QSPI_ABR, 0); } if (data == magic) { @@ -2217,10 +2203,10 @@ static int stmqspi_probe(struct flash_bank *bank) memcpy(&stmqspi_info->dev, p, sizeof(stmqspi_info->dev)); if (p->size_in_bytes / 4096) LOG_INFO("flash1 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 - "kbytes", p->name, id1, p->size_in_bytes / 1024); + " KiB", p->name, id1, p->size_in_bytes / 1024); else LOG_INFO("flash1 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 - "bytes", p->name, id1, p->size_in_bytes); + " B", p->name, id1, p->size_in_bytes); break; } } @@ -2239,7 +2225,7 @@ static int stmqspi_probe(struct flash_bank *bank) if (retval == ERROR_OK) { LOG_INFO("flash1 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 - "kbytes", temp.name, id1, temp.size_in_bytes / 1024); + " KiB", temp.name, id1, temp.size_in_bytes / 1024); /* save info and retrieved *good* id as spi_sfdp clears all info */ memcpy(&stmqspi_info->dev, &temp, sizeof(stmqspi_info->dev)); stmqspi_info->dev.device_id = id1; @@ -2257,10 +2243,10 @@ static int stmqspi_probe(struct flash_bank *bank) if (p->device_id == id2) { if (p->size_in_bytes / 4096) LOG_INFO("flash2 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 - "kbytes", p->name, id2, p->size_in_bytes / 1024); + " KiB", p->name, id2, p->size_in_bytes / 1024); else LOG_INFO("flash2 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 - "bytes", p->name, id2, p->size_in_bytes); + " B", p->name, id2, p->size_in_bytes); if (!id1) memcpy(&stmqspi_info->dev, p, sizeof(stmqspi_info->dev)); @@ -2297,7 +2283,7 @@ static int stmqspi_probe(struct flash_bank *bank) if (retval == ERROR_OK) LOG_INFO("flash2 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 - "kbytes", temp.name, id2, temp.size_in_bytes / 1024); + " KiB", temp.name, id2, temp.size_in_bytes / 1024); else { /* even not identified by SFDP, then give up */ LOG_WARNING("Unknown flash2 device id = 0x%06" PRIx32 @@ -2403,22 +2389,22 @@ static int get_stmqspi_info(struct flash_bank *bank, struct command_invocation * } command_print_sameline(cmd, "flash%s%s \'%s\', device id = 0x%06" PRIx32 - ", flash size = %" PRIu32 "%sbytes\n(page size = %" PRIu32 + ", flash size = %" PRIu32 "%s B\n(page size = %" PRIu32 ", read = 0x%02" PRIx8 ", qread = 0x%02" PRIx8 ", pprog = 0x%02" PRIx8 ", mass_erase = 0x%02" PRIx8 - ", sector size = %" PRIu32 "%sbytes, sector_erase = 0x%02" PRIx8 ")", + ", sector size = %" PRIu32 " %sB, sector_erase = 0x%02" PRIx8 ")", ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) ? "1" : "", ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) ? "2" : "", stmqspi_info->dev.name, stmqspi_info->dev.device_id, bank->size / 4096 ? bank->size / 1024 : bank->size, - bank->size / 4096 ? "k" : "", stmqspi_info->dev.pagesize, + bank->size / 4096 ? "Ki" : "", stmqspi_info->dev.pagesize, stmqspi_info->dev.read_cmd, stmqspi_info->dev.qread_cmd, stmqspi_info->dev.pprog_cmd, stmqspi_info->dev.chip_erase_cmd, stmqspi_info->dev.sectorsize / 4096 ? stmqspi_info->dev.sectorsize / 1024 : stmqspi_info->dev.sectorsize, - stmqspi_info->dev.sectorsize / 4096 ? "k" : "", + stmqspi_info->dev.sectorsize / 4096 ? "Ki" : "", stmqspi_info->dev.erase_cmd); return ERROR_OK; @@ -2461,7 +2447,7 @@ static const struct command_registration stmqspi_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct flash_driver stmqspi_flash = { +const struct flash_driver stmqspi_flash = { .name = "stmqspi", .commands = stmqspi_command_handlers, .flash_bank_command = stmqspi_flash_bank_command, diff --git a/src/flash/nor/stmqspi.h b/src/flash/nor/stmqspi.h index 85da25f094..245df40b38 100644 --- a/src/flash/nor/stmqspi.h +++ b/src/flash/nor/stmqspi.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2016 - 2018 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_FLASH_NOR_STMQSPI_H diff --git a/src/flash/nor/stmsmi.c b/src/flash/nor/stmsmi.c index 553bf2924a..1aa244728f 100644 --- a/src/flash/nor/stmsmi.c +++ b/src/flash/nor/stmsmi.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> * - * * - * 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/>. * ***************************************************************************/ /* STM Serial Memory Interface (SMI) controller is a SPI bus controller diff --git a/src/flash/nor/str7x.c b/src/flash/nor/str7x.c index 9b977bf908..b91e22e044 100644 --- a/src/flash/nor/str7x.c +++ b/src/flash/nor/str7x.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2010 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/str9x.c b/src/flash/nor/str9x.c index 8f39d75fa5..1a26b839e9 100644 --- a/src/flash/nor/str9x.c +++ b/src/flash/nor/str9x.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * Copyright (C) 2008 by Oyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/str9xpec.c b/src/flash/nor/str9xpec.c index da66a99a82..c39eb3aa84 100644 --- a/src/flash/nor/str9xpec.c +++ b/src/flash/nor/str9xpec.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/swm050.c b/src/flash/nor/swm050.c index be7452b819..dcf59d380e 100644 --- a/src/flash/nor/swm050.c +++ b/src/flash/nor/swm050.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2019 Icenowy Zheng <icenowy@aosc.io> * * Copyright (C) 2019 Caleb Szalacinski <contact@skiboy.net> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -194,7 +183,7 @@ static const struct command_registration swm050_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct flash_driver swm050_flash = { +const struct flash_driver swm050_flash = { .name = "swm050", .commands = swm050_command_handlers, .flash_bank_command = swm050_flash_bank_command, diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index 05db31435c..1c4e154e5c 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * * Copyright (C) 2017-2018 Tomas Vanek <vanekt@fbl.cz> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" @@ -30,7 +19,7 @@ * Implements Tcl commands used to access NOR flash facilities. */ -static COMMAND_HELPER(flash_command_get_bank_maybe_probe, unsigned name_index, +COMMAND_HELPER(flash_command_get_bank_probe_optional, unsigned int name_index, struct flash_bank **bank, bool do_probe) { const char *name = CMD_ARGV[name_index]; @@ -62,7 +51,7 @@ static COMMAND_HELPER(flash_command_get_bank_maybe_probe, unsigned name_index, COMMAND_HELPER(flash_command_get_bank, unsigned name_index, struct flash_bank **bank) { - return CALL_COMMAND_HANDLER(flash_command_get_bank_maybe_probe, + return CALL_COMMAND_HANDLER(flash_command_get_bank_probe_optional, name_index, bank, true); } @@ -168,7 +157,7 @@ COMMAND_HANDLER(handle_flash_probe_command) if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - retval = CALL_COMMAND_HANDLER(flash_command_get_bank_maybe_probe, 0, &p, false); + retval = CALL_COMMAND_HANDLER(flash_command_get_bank_probe_optional, 0, &p, false); if (retval != ERROR_OK) return retval; @@ -826,6 +815,7 @@ COMMAND_HANDLER(handle_flash_write_bank_command) if (buf_cnt != length) { LOG_ERROR("Short read"); free(buffer); + fileio_close(fileio); return ERROR_FAIL; } @@ -1336,40 +1326,27 @@ COMMAND_HANDLER(handle_flash_banks_command) return ERROR_OK; } -static int jim_flash_list(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(handle_flash_list) { - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, - "no arguments to 'flash list' command"); - return JIM_ERR; - } - - Jim_Obj *list = Jim_NewListObj(interp, NULL, 0); + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; for (struct flash_bank *p = flash_bank_list(); p; p = p->next) { - Jim_Obj *elem = Jim_NewListObj(interp, NULL, 0); - - Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "name", -1)); - Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, p->name, -1)); - Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "driver", -1)); - Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, p->driver->name, -1)); - Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "base", -1)); - Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->base)); - Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "size", -1)); - Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->size)); - Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "bus_width", -1)); - Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->bus_width)); - Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "chip_width", -1)); - Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->chip_width)); - Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "target", -1)); - Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, target_name(p->target), -1)); - - Jim_ListAppendElement(interp, list, elem); + command_print(CMD, + "{\n" + " name %s\n" + " driver %s\n" + " base " TARGET_ADDR_FMT "\n" + " size 0x%" PRIx32 "\n" + " bus_width %u\n" + " chip_width %u\n" + " target %s\n" + "}", + p->name, p->driver->name, p->base, p->size, p->bus_width, p->chip_width, + target_name(p->target)); } - Jim_SetResult(interp, list); - - return JIM_OK; + return ERROR_OK; } COMMAND_HANDLER(handle_flash_init_command) @@ -1416,8 +1393,9 @@ static const struct command_registration flash_config_command_handlers[] = { { .name = "list", .mode = COMMAND_ANY, - .jim_handler = jim_flash_list, + .handler = handle_flash_list, .help = "Returns a list of details about the flash banks.", + .usage = "", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/flash/nor/tms470.c b/src/flash/nor/tms470.c index 37f0933966..e01d2df0a5 100644 --- a/src/flash/nor/tms470.c +++ b/src/flash/nor/tms470.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007,2008 by Christopher Kilgour * * techie |_at_| whiterocker |_dot_| com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -259,9 +248,6 @@ static int tms470_read_part_info(struct flash_bank *bank) target_write_u32(target, 0xFFFFFFE4, 0x00000000); target_write_u32(target, 0xFFFFFFE0, 0x00000000); - bank->chip_width = 32; - bank->bus_width = 32; - LOG_INFO("Identified %s, ver=%d, core=%s, nvmem=%s.", part_name, (int)(silicon_version), diff --git a/src/flash/nor/vexriscv_nor_spi.c b/src/flash/nor/vexriscv_nor_spi.c index 0c49920dc4..c077d4a1e5 100644 --- a/src/flash/nor/vexriscv_nor_spi.c +++ b/src/flash/nor/vexriscv_nor_spi.c @@ -433,7 +433,7 @@ static const struct command_registration vexriscv_nor_spi_command_handlers[] = { }; -struct flash_driver vexriscv_nor_spi = { +const struct flash_driver vexriscv_nor_spi = { .name = "vexriscv_nor_spi", .commands = vexriscv_nor_spi_command_handlers, .flash_bank_command = vexriscv_nor_spi_flash_bank_command, diff --git a/src/flash/nor/virtual.c b/src/flash/nor/virtual.c index 01a92478fc..c5e33385e6 100644 --- a/src/flash/nor/virtual.c +++ b/src/flash/nor/virtual.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/nor/w600.c b/src/flash/nor/w600.c index cd2aa01824..20968dcaaa 100644 --- a/src/flash/nor/w600.c +++ b/src/flash/nor/w600.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2018 by Simon Qian * * SimonQian@SimonQian.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -323,7 +312,7 @@ static int w600_probe(struct flash_bank *bank) flash_size = 1 << flash_size; } - LOG_INFO("flash size = %" PRIu32 "kbytes", flash_size / 1024); + LOG_INFO("flash size = %" PRIu32 " KiB", flash_size / 1024); /* calculate numbers of pages */ size_t num_pages = flash_size / W600_FLASH_SECSIZE; diff --git a/src/flash/nor/xcf.c b/src/flash/nor/xcf.c index c6de1aca11..c253b2264b 100644 --- a/src/flash/nor/xcf.c +++ b/src/flash/nor/xcf.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2016 by Uladzimir Pylinski aka barthess * * barthess@yandex.ru * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -608,7 +597,7 @@ static int xcf_probe(struct flash_bank *bank) } /* check idcode and alloc memory for sector table */ - if (!bank->target->tap->hasidcode) + if (!bank->target->tap->has_idcode) return ERROR_FLASH_OPERATION_FAILED; /* guess number of blocks using chip ID */ diff --git a/src/flash/nor/xmc1xxx.c b/src/flash/nor/xmc1xxx.c index 9e5f0a3ddd..6e30fc125c 100644 --- a/src/flash/nor/xmc1xxx.c +++ b/src/flash/nor/xmc1xxx.c @@ -1,9 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * XMC1000 flash driver * * Copyright (c) 2016 Andreas Färber - * - * License: GPL-2.0+ */ #ifdef HAVE_CONFIG_H @@ -520,24 +520,8 @@ FLASH_BANK_COMMAND_HANDLER(xmc1xxx_flash_bank_command) return ERROR_OK; } -static const struct command_registration xmc1xxx_exec_command_handlers[] = { - COMMAND_REGISTRATION_DONE -}; - -static const struct command_registration xmc1xxx_command_handlers[] = { - { - .name = "xmc1xxx", - .mode = COMMAND_ANY, - .help = "xmc1xxx flash command group", - .usage = "", - .chain = xmc1xxx_exec_command_handlers, - }, - COMMAND_REGISTRATION_DONE -}; - const struct flash_driver xmc1xxx_flash = { .name = "xmc1xxx", - .commands = xmc1xxx_command_handlers, .flash_bank_command = xmc1xxx_flash_bank_command, .info = xmc1xxx_get_info_command, .probe = xmc1xxx_probe, diff --git a/src/flash/nor/xmc4xxx.c b/src/flash/nor/xmc4xxx.c index 1668e8993d..54fd5a5867 100644 --- a/src/flash/nor/xmc4xxx.c +++ b/src/flash/nor/xmc4xxx.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /************************************************************************** * Copyright (C) 2015 Jeff Ciesielski <jeffciesielski@gmail.com> * -* * -* 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/flash/startup.tcl b/src/flash/startup.tcl index 16cbe19505..654f201a4e 100644 --- a/src/flash/startup.tcl +++ b/src/flash/startup.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Defines basic Tcl procs for OpenOCD flash module # diff --git a/src/hello.c b/src/hello.c index 9d078c0e77..4e27d4d68d 100644 --- a/src/hello.c +++ b/src/hello.c @@ -1,24 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <helper/log.h> +#include "hello.h" COMMAND_HANDLER(handle_foo_command) { diff --git a/src/hello.h b/src/hello.h index c88c89ddfa..1a087b1bad 100644 --- a/src/hello.h +++ b/src/hello.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_HELLO_H diff --git a/src/helper/Makefile.am b/src/helper/Makefile.am index 822578a766..39d93d66ac 100644 --- a/src/helper/Makefile.am +++ b/src/helper/Makefile.am @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libhelper.la %C%_libhelper_la_SOURCES = \ @@ -7,12 +9,14 @@ noinst_LTLIBRARIES += %D%/libhelper.la %D%/configuration.c \ %D%/log.c \ %D%/command.c \ + %D%/crc32.c \ %D%/time_support.c \ %D%/replacements.c \ %D%/fileio.c \ %D%/util.c \ %D%/jep106.c \ %D%/jim-nvp.c \ + %D%/nvp.c \ %D%/align.h \ %D%/binarybuffer.h \ %D%/bits.h \ @@ -22,6 +26,7 @@ noinst_LTLIBRARIES += %D%/libhelper.la %D%/types.h \ %D%/log.h \ %D%/command.h \ + %D%/crc32.h \ %D%/time_support.h \ %D%/replacements.h \ %D%/fileio.h \ @@ -30,7 +35,9 @@ noinst_LTLIBRARIES += %D%/libhelper.la %D%/jep106.inc \ %D%/jim-nvp.h \ %D%/base64.c \ - %D%/base64.h + %D%/base64.h \ + %D%/nvp.h \ + %D%/compiler.h STARTUP_TCL_SRCS += %D%/startup.tcl EXTRA_DIST += \ diff --git a/src/helper/bin2char.sh b/src/helper/bin2char.sh index 128ea9af6e..cf94bee29c 100755 --- a/src/helper/bin2char.sh +++ b/src/helper/bin2char.sh @@ -1,4 +1,5 @@ #!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later [ $# != 0 ] && { echo "Usage: $0" @@ -11,4 +12,4 @@ } echo "/* Autogenerated with $0 */" -od -v -A n -t x1 | sed 's/ *\(..\) */0x\1,/g' +od -v -A n -t x1 | sed 's/ *\(..\) */0x\1,/g;/^$/d' diff --git a/src/helper/binarybuffer.c b/src/helper/binarybuffer.c index e2dfa87b60..5f38b43ae1 100644 --- a/src/helper/binarybuffer.c +++ b/src/helper/binarybuffer.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/helper/binarybuffer.h b/src/helper/binarybuffer.h index 36d6adc6f2..a8a5ef8f3f 100644 --- a/src/helper/binarybuffer.h +++ b/src/helper/binarybuffer.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_HELPER_BINARYBUFFER_H diff --git a/src/helper/bits.h b/src/helper/bits.h index 6151b33401..4e2a3456cf 100644 --- a/src/helper/bits.h +++ b/src/helper/bits.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Copyright (C) 2018, STMicroelectronics - All Rights Reserved * Author(s): Antonio Borneo <borneo.antonio@gmail.com> for STMicroelectronics - * - * 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/>. */ /* diff --git a/src/helper/command.c b/src/helper/command.c index 1e769d7190..a775c730b8 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -10,28 +12,12 @@ * * * part of this file is taken from libcli (libcli.sourceforge.net) * * Copyright (C) David Parrish (david@dparrish.com) * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif -/* see Embedded-HOWTO.txt in Jim Tcl project hosted on BerliOS*/ -#define JIM_EMBEDDED - /* @todo the inclusion of target.h here is a layering violation */ #include <jtag/jtag.h> #include <target/target.h> @@ -113,8 +99,7 @@ static struct log_capture_state *command_log_capture_start(Jim_Interp *interp) * The tcl return value is empty for openocd commands that provide * progress output. * - * Therefore we set the tcl return value only if we actually - * captured output. + * For other commands, we prepend the logs to the tcl return value. */ static void command_log_capture_finish(struct log_capture_state *state) { @@ -123,15 +108,18 @@ static void command_log_capture_finish(struct log_capture_state *state) log_remove_callback(tcl_output, state); - int length; - Jim_GetString(state->output, &length); + int loglen; + const char *log_result = Jim_GetString(state->output, &loglen); + int reslen; + const char *cmd_result = Jim_GetString(Jim_GetResult(state->interp), &reslen); - if (length > 0) - Jim_SetResult(state->interp, state->output); - else { - /* No output captured, use tcl return value (which could - * be empty too). */ - } + // Just in case the log doesn't end with a newline, we add it + if (loglen != 0 && reslen != 0 && log_result[loglen - 1] != '\n') + Jim_AppendString(state->interp, state->output, "\n", 1); + + Jim_AppendString(state->interp, state->output, cmd_result, reslen); + + Jim_SetResult(state->interp, state->output); Jim_DecrRefCount(state->interp, state->output); free(state); @@ -157,8 +145,7 @@ static void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const char *dbg = alloc_printf("command -"); for (unsigned i = 0; i < argc; i++) { - int len; - const char *w = Jim_GetString(argv[i], &len); + const char *w = Jim_GetString(argv[i], NULL); char *t = alloc_printf("%s %s", dbg, w); free(dbg); dbg = t; @@ -167,34 +154,6 @@ static void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const free(dbg); } -static void script_command_args_free(char **words, unsigned nwords) -{ - for (unsigned i = 0; i < nwords; i++) - free(words[i]); - free(words); -} - -static char **script_command_args_alloc( - unsigned argc, Jim_Obj * const *argv, unsigned *nwords) -{ - char **words = malloc(argc * sizeof(char *)); - if (!words) - return NULL; - - unsigned i; - for (i = 0; i < argc; i++) { - int len; - const char *w = Jim_GetString(argv[i], &len); - words[i] = strdup(w); - if (!words[i]) { - script_command_args_free(words, i); - return NULL; - } - } - *nwords = i; - return words; -} - struct command_context *current_command_context(Jim_Interp *interp) { /* grab the command context from the associated data */ @@ -530,15 +489,29 @@ static bool command_can_run(struct command_context *cmd_ctx, struct command *c, return false; } -static int run_command(struct command_context *context, - struct command *c, const char **words, unsigned num_words) +static int exec_command(Jim_Interp *interp, struct command_context *context, + struct command *c, int argc, Jim_Obj * const *argv) { + if (c->jim_handler) + return c->jim_handler(interp, argc, argv); + + /* use c->handler */ + const char **words = malloc(argc * sizeof(char *)); + if (!words) { + LOG_ERROR("Out of memory"); + return JIM_ERR; + } + + for (int i = 0; i < argc; i++) + words[i] = Jim_GetString(argv[i], NULL); + struct command_invocation cmd = { .ctx = context, .current = c, .name = c->name, - .argc = num_words - 1, + .argc = argc - 1, .argv = words + 1, + .jimtcl_argv = argv + 1, }; cmd.output = Jim_NewEmptyStringObj(context->interp); @@ -554,12 +527,21 @@ static int run_command(struct command_context *context, if (retval != ERROR_OK) LOG_DEBUG("Command '%s' failed with error code %d", words[0], retval); - /* Use the command output as the Tcl result */ - Jim_SetResult(context->interp, cmd.output); + /* + * Use the command output as the Tcl result. + * Drop last '\n' to allow command output concatenation + * while keep using command_print() everywhere. + */ + const char *output_txt = Jim_String(cmd.output); + int len = strlen(output_txt); + if (len && output_txt[len - 1] == '\n') + --len; + Jim_SetResultString(context->interp, output_txt, len); } Jim_DecrRefCount(context->interp, cmd.output); - return retval; + free(words); + return command_retval_set(interp, retval); } int command_run_line(struct command_context *context, char *line) @@ -588,7 +570,7 @@ int command_run_line(struct command_context *context, char *line) Jim_DeleteAssocData(interp, "retval"); retcode = Jim_SetAssocData(interp, "retval", NULL, &retval); if (retcode == JIM_OK) { - retcode = Jim_Eval_Named(interp, line, 0, 0); + retcode = Jim_Eval_Named(interp, line, NULL, 0); Jim_DeleteAssocData(interp, "retval"); } @@ -668,19 +650,19 @@ void command_done(struct command_context *cmd_ctx) } /* find full path to file */ -static int jim_find(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_find) { - if (argc != 2) - return JIM_ERR; - const char *file = Jim_GetString(argv[1], NULL); - char *full_path = find_file(file); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + char *full_path = find_file(CMD_ARGV[0]); if (!full_path) - return JIM_ERR; - Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path)); + return ERROR_COMMAND_ARGUMENT_INVALID; + + command_print(CMD, "%s", full_path); free(full_path); - Jim_SetResult(interp, result); - return JIM_OK; + return ERROR_OK; } COMMAND_HANDLER(handle_echo) @@ -697,8 +679,8 @@ COMMAND_HANDLER(handle_echo) return ERROR_OK; } -/* Capture progress output and return as tcl return value. If the - * progress output was empty, return tcl return value. +/* Return both the progress output (LOG_INFO and higher) + * and the tcl return value of a command. */ static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { @@ -713,14 +695,12 @@ static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv) * This is necessary in order to avoid accidentally getting a non-empty * string for tcl fn's. */ - bool save_poll = jtag_poll_get_enabled(); - - jtag_poll_set_enabled(false); + bool save_poll_mask = jtag_poll_mask(); const char *str = Jim_GetString(argv[1], NULL); int retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__); - jtag_poll_set_enabled(save_poll); + jtag_poll_unmask(save_poll_mask); command_log_capture_finish(state); @@ -902,23 +882,6 @@ static char *alloc_concatenate_strings(int argc, Jim_Obj * const *argv) return all; } -static int exec_command(Jim_Interp *interp, struct command_context *cmd_ctx, - struct command *c, int argc, Jim_Obj * const *argv) -{ - if (c->jim_handler) - return c->jim_handler(interp, argc, argv); - - /* use c->handler */ - unsigned int nwords; - char **words = script_command_args_alloc(argc, argv, &nwords); - if (!words) - return JIM_ERR; - - int retval = run_command(cmd_ctx, c, (const char **)words, nwords); - script_command_args_free(words, nwords); - return command_retval_set(interp, retval); -} - static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { /* check subcommands */ @@ -949,7 +912,7 @@ static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *a if (!command_can_run(cmd_ctx, c, Jim_GetString(argv[0], NULL))) return JIM_ERR; - target_call_timer_callbacks_now(); + target_call_timer_callbacks(); /* * Black magic of overridden current target: @@ -1173,7 +1136,7 @@ static const struct command_registration command_builtin_handlers[] = { { .name = "ocd_find", .mode = COMMAND_ANY, - .jim_handler = jim_find, + .handler = handle_find, .help = "find full path to file", .usage = "file", }, diff --git a/src/helper/command.h b/src/helper/command.h index 796cd9d3b3..dc45070420 100644 --- a/src/helper/command.h +++ b/src/helper/command.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_HELPER_COMMAND_H @@ -90,6 +79,7 @@ struct command_invocation { const char *name; unsigned argc; const char **argv; + Jim_Obj * const *jimtcl_argv; Jim_Obj *output; }; @@ -164,6 +154,11 @@ void *jimcmd_privdata(Jim_Cmd *cmd); * rather than accessing the variable directly. It may be moved. */ #define CMD_ARGV (cmd->argv) +/** + * Use this macro to access the jimtcl arguments for the command being + * handled, rather than accessing the variable directly. It may be moved. + */ +#define CMD_JIMTCL_ARGV (cmd->jimtcl_argv) /** * Use this macro to access the name of the command being handled, * rather than accessing the variable directly. It may be moved. @@ -381,10 +376,21 @@ struct command_context *copy_command_context(struct command_context *cmd_ctx); */ void command_done(struct command_context *context); +/* + * command_print() and command_print_sameline() are used to produce the TCL + * output of OpenOCD commands. command_print() automatically adds a '\n' at + * the end or the format string. Use command_print_sameline() to avoid the + * trailing '\n', e.g. to concatenate the command output in the same line. + * The very last '\n' of the command is stripped away (see run_command()). + * For commands that strictly require a '\n' as last output character, add + * it explicitly with either an empty command_print() or with a '\n' in the + * last command_print() and add a comment to document it. + */ void command_print(struct command_invocation *cmd, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); void command_print_sameline(struct command_invocation *cmd, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); + int command_run_line(struct command_context *context, char *line); int command_run_linef(struct command_context *context, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); diff --git a/src/helper/compiler.h b/src/helper/compiler.h new file mode 100644 index 0000000000..312d261fc3 --- /dev/null +++ b/src/helper/compiler.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * This file contains compiler specific workarounds to handle different + * compilers and different compiler versions. + * Inspired by Linux's include/linux/compiler_attributes.h + * and file sys/cdefs.h in libc and newlib. + */ + +#ifndef OPENOCD_HELPER_COMPILER_H +#define OPENOCD_HELPER_COMPILER_H + +/* + * __has_attribute is supported on gcc >= 5, clang >= 2.9 and icc >= 17. + */ +#ifndef __has_attribute +# define __has_attribute(x) 0 +#endif + +/* + * The __returns_nonnull function attribute marks the return type of the function + * as always being non-null. + */ +#ifndef __returns_nonnull +# if __has_attribute(__returns_nonnull__) +# define __returns_nonnull __attribute__((__returns_nonnull__)) +# else +# define __returns_nonnull +# endif +#endif + +/* + * The __nonnull function attribute marks pointer parameters that + * must not be NULL. + * + * clang for Apple defines + * #define __nonnull _Nonnull + * that is a per argument attribute, incompatible with the gcc per function attribute __nonnull__. + * gcc for Apple includes sys/cdefs.h from MacOSX.sdk that defines + * #define __nonnull + * In both cases, undefine __nonnull to keep compatibility among compilers and platforms. + */ +#if defined(__APPLE__) +# undef __nonnull +#endif +#ifndef __nonnull +# if __has_attribute(__nonnull__) +# define __nonnull(params) __attribute__ ((__nonnull__ params)) +# else +# define __nonnull(params) +# endif +#endif + +#endif /* OPENOCD_HELPER_COMPILER_H */ diff --git a/src/helper/configuration.c b/src/helper/configuration.c index 7e791d0848..16732eb3dd 100644 --- a/src/helper/configuration.c +++ b/src/helper/configuration.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -148,6 +137,10 @@ int parse_config_file(struct command_context *cmd_ctx) char *get_home_dir(const char *append_path) { +#ifdef _WIN32 + char homepath[MAX_PATH]; +#endif + char *home = getenv("HOME"); if (!home) { @@ -156,8 +149,6 @@ char *get_home_dir(const char *append_path) home = getenv("USERPROFILE"); if (!home) { - - char homepath[MAX_PATH]; char *drive = getenv("HOMEDRIVE"); char *path = getenv("HOMEPATH"); if (drive && path) { diff --git a/src/helper/configuration.h b/src/helper/configuration.h index cc28efcdb7..295ea591d6 100644 --- a/src/helper/configuration.h +++ b/src/helper/configuration.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_HELPER_CONFIGURATION_H diff --git a/src/helper/crc32.c b/src/helper/crc32.c new file mode 100644 index 0000000000..441a46c57f --- /dev/null +++ b/src/helper/crc32.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2013-2014 by Franck Jullien * + * elec4fun@gmail.com * + * * + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg * + * marian.buschsieweke@ovgu.de * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "crc32.h" +#include <stdint.h> +#include <stddef.h> + +static uint32_t crc_le_step(uint32_t poly, uint32_t crc, uint32_t data_in, + unsigned int data_bits) +{ + for (unsigned int i = 0; i < data_bits; i++) { + uint32_t d, c; + d = ((data_in >> i) & 0x1) ? 0xffffffff : 0; + c = (crc & 0x1) ? 0xffffffff : 0; + crc = crc >> 1; + crc = crc ^ ((d ^ c) & poly); + } + + return crc; +} + +uint32_t crc32_le(uint32_t poly, uint32_t seed, const void *_data, + size_t data_len) +{ + if (((uintptr_t)_data & 0x3) || (data_len & 0x3)) { + /* data is unaligned, processing data one byte at a time */ + const uint8_t *data = _data; + for (size_t i = 0; i < data_len; i++) + seed = crc_le_step(poly, seed, data[i], 8); + } else { + /* data is aligned, processing 32 bit at a time */ + data_len >>= 2; + const uint32_t *data = _data; + for (size_t i = 0; i < data_len; i++) + seed = crc_le_step(poly, seed, data[i], 32); + } + + return seed; +} diff --git a/src/helper/crc32.h b/src/helper/crc32.h new file mode 100644 index 0000000000..8f077863a3 --- /dev/null +++ b/src/helper/crc32.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg * + * marian.buschsieweke@ovgu.de * + ***************************************************************************/ + +#ifndef OPENOCD_HELPER_CRC32_H +#define OPENOCD_HELPER_CRC32_H + +#include <stdint.h> +#include <stddef.h> + +/** @file + * A generic CRC32 implementation + */ + +/** + * CRC32 polynomial commonly used for little endian CRC32 + */ +#define CRC32_POLY_LE 0xedb88320 + +/** + * Calculate the CRC32 value of the given data + * @param poly The polynomial of the CRC + * @param seed The seed to use (mostly either `0` or `0xffffffff`) + * @param data The data to calculate the CRC32 of + * @param data_len The length of the data in @p data in bytes + * @return The CRC value of the first @p data_len bytes at @p data + * @note This function can be used to incrementally compute the CRC one + * chunk of data at a time by using the CRC32 of the previous chunk + * as @p seed for the next chunk. + */ +uint32_t crc32_le(uint32_t poly, uint32_t seed, const void *data, + size_t data_len); + +#endif /* OPENOCD_HELPER_CRC32_H */ diff --git a/src/helper/fileio.c b/src/helper/fileio.c index cec7dec52a..a290a5d2ff 100644 --- a/src/helper/fileio.c +++ b/src/helper/fileio.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/helper/fileio.h b/src/helper/fileio.h index 16c1046575..6b4be8ef56 100644 --- a/src/helper/fileio.h +++ b/src/helper/fileio.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_HELPER_FILEIO_H diff --git a/src/helper/jep106.c b/src/helper/jep106.c index 5cf769aabd..62d24a9b23 100644 --- a/src/helper/jep106.c +++ b/src/helper/jep106.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2015 Andreas Fritiofson * * andreas.fritiofson@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -37,7 +26,7 @@ const char *jep106_table_manufacturer(unsigned int bank, unsigned int id) /* index is zero based */ id--; - if (bank >= ARRAY_SIZE(jep106) || jep106[bank][id] == 0) + if (bank >= ARRAY_SIZE(jep106) || !jep106[bank][id]) return "<unknown>"; return jep106[bank][id]; diff --git a/src/helper/jep106.h b/src/helper/jep106.h index 61b177a2f9..c554daee27 100644 --- a/src/helper/jep106.h +++ b/src/helper/jep106.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2015 Andreas Fritiofson * * andreas.fritiofson@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_HELPER_JEP106_H diff --git a/src/helper/jep106.inc b/src/helper/jep106.inc index ccf65f7d8c..958dc4ea4d 100644 --- a/src/helper/jep106.inc +++ b/src/helper/jep106.inc @@ -1,9 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* - * Should be autogenerated with update_jep106.pl but latest - * file from JEDEC is only available in PDF form. The PDF - * also breaks the pdftotext flow due to embedded watermarks. - * Created with a mix of scripts and manual editing. + * The manufacturer's standard identification code list appears in JEP106. + * Copyright (c) 2024 JEDEC. All rights reserved. + * + * JEP106 is regularly updated. For the current manufacturer's standard + * identification code list, please visit the JEDEC website at www.jedec.org . */ + +/* This file is aligned to revision JEP106BI January 2024. */ + +/* "NXP (Philips)" is reported below, while missing since JEP106BG */ + [0][0x01 - 1] = "AMD", [0][0x02 - 1] = "AMI", [0][0x03 - 1] = "Fairchild", @@ -80,7 +88,7 @@ [0][0x4a - 1] = "Compaq", [0][0x4b - 1] = "Protocol Engines", [0][0x4c - 1] = "SCI", -[0][0x4d - 1] = "Seiko Instruments", +[0][0x4d - 1] = "ABLIC", [0][0x4e - 1] = "Samsung", [0][0x4f - 1] = "I3 Design System", [0][0x50 - 1] = "Klic", @@ -143,7 +151,7 @@ [1][0x0b - 1] = "Bestlink Systems", [1][0x0c - 1] = "Graychip", [1][0x0d - 1] = "GENNUM", -[1][0x0e - 1] = "VideoLogic", +[1][0x0e - 1] = "Imagination Technologies Limited", [1][0x0f - 1] = "Robert Bosch", [1][0x10 - 1] = "Chip Express", [1][0x11 - 1] = "DATARAM", @@ -966,7 +974,7 @@ [7][0x4e - 1] = "Mustang", [7][0x4f - 1] = "Orca Systems", [7][0x50 - 1] = "Passif Semiconductor", -[7][0x51 - 1] = "GigaDevice Semiconductor (Beijing) Inc", +[7][0x51 - 1] = "GigaDevice Semiconductor (Beijing)", [7][0x52 - 1] = "Memphis Electronic", [7][0x53 - 1] = "Beckhoff Automation GmbH", [7][0x54 - 1] = "Harmony Semiconductor Corp", @@ -1011,6 +1019,7 @@ [7][0x7b - 1] = "Gowe Technology Co Ltd", [7][0x7c - 1] = "Hermes Testing Solutions Inc", [7][0x7d - 1] = "Positivo BGH", +[7][0x7e - 1] = "Intelligence Silicon Technology", [8][0x01 - 1] = "3D PLUS", [8][0x02 - 1] = "Diehl Aerospace", [8][0x03 - 1] = "Fairchild", @@ -1366,7 +1375,7 @@ [10][0x65 - 1] = "Esperanto Technologies", [10][0x66 - 1] = "JinSheng Electronic (Shenzhen) Co Ltd", [10][0x67 - 1] = "Shenzhen Shi Bolunshuai Technology", -[10][0x68 - 1] = "Shanghai Rei Zuan Information Tech", +[10][0x68 - 1] = "Shanghai Rui Zuan Information Tech", [10][0x69 - 1] = "Fraunhofer IIS", [10][0x6a - 1] = "Kandou Bus SA", [10][0x6b - 1] = "Acer", @@ -1494,7 +1503,7 @@ [11][0x67 - 1] = "Guangzhou Shuvrwine Technology Co", [11][0x68 - 1] = "Shenzhen Hangshun Chip Technology", [11][0x69 - 1] = "Chengboliwei Electronic Business", -[11][0x6a - 1] = "Kowin Memory Technology Co Ltd", +[11][0x6a - 1] = "Kowin Technology HK Limited", [11][0x6b - 1] = "Euronet Technology Inc", [11][0x6c - 1] = "SCY", [11][0x6d - 1] = "Shenzhen Xinhongyusheng Electrical", @@ -1552,7 +1561,7 @@ [12][0x23 - 1] = "Tangem AG", [12][0x24 - 1] = "FuturePath Technology (Shenzhen) Co", [12][0x25 - 1] = "RC Module", -[12][0x26 - 1] = "Team Research Inc", +[12][0x26 - 1] = "Timetec International Inc", [12][0x27 - 1] = "ICMAX Technologies Co Limited", [12][0x28 - 1] = "Lynxi Technologies Ltd Co", [12][0x29 - 1] = "Guangzhou Taisupanke Computer Equipment", @@ -1570,7 +1579,7 @@ [12][0x35 - 1] = "Shenzhen Xinxinshun Technology Co", [12][0x36 - 1] = "Galois Inc", [12][0x37 - 1] = "Ubilite Inc", -[12][0x38 - 1] = "Shenzhen Quanzing Technology Co Ltd", +[12][0x38 - 1] = "Shenzhen Quanxing Technology Co Ltd", [12][0x39 - 1] = "Group RZX Technology LTDA", [12][0x3a - 1] = "Yottac Technology (XI'AN) Cooperation", [12][0x3b - 1] = "Shenzhen RuiRen Technology Co Ltd", @@ -1610,4 +1619,323 @@ [12][0x5d - 1] = "OLOy Technology", [12][0x5e - 1] = "Wuhan P&S Semiconductor Co Ltd", [12][0x5f - 1] = "Sitrus Technology", +[12][0x60 - 1] = "AnHui Conner Storage Co Ltd", +[12][0x61 - 1] = "Rochester Electronics", +[12][0x62 - 1] = "Wuxi Smart Memories Technologies Co", +[12][0x63 - 1] = "Star Memory", +[12][0x64 - 1] = "Agile Memory Technology Co Ltd", +[12][0x65 - 1] = "MEJEC", +[12][0x66 - 1] = "Rockchip Electronics Co Ltd", +[12][0x67 - 1] = "Dongguan Guanma e-commerce Co Ltd", +[12][0x68 - 1] = "Rayson Hi-Tech (SZ) Limited", +[12][0x69 - 1] = "MINRES Technologies GmbH", +[12][0x6a - 1] = "Himax Technologies Inc", +[12][0x6b - 1] = "Shenzhen Cwinner Technology Co Ltd", +[12][0x6c - 1] = "Tecmiyo", +[12][0x6d - 1] = "Shenzhen Suhuicun Technology Co Ltd", +[12][0x6e - 1] = "Vickter Electronics Co. Ltd.", +[12][0x6f - 1] = "lowRISC", +[12][0x70 - 1] = "EXEGate FZE", +[12][0x71 - 1] = "Shenzhen 9 Chapter Technologies Co", +[12][0x72 - 1] = "Addlink", +[12][0x73 - 1] = "Starsway", +[12][0x74 - 1] = "Pensando Systems Inc.", +[12][0x75 - 1] = "AirDisk", +[12][0x76 - 1] = "Shenzhen Speedmobile Technology Co", +[12][0x77 - 1] = "PEZY Computing", +[12][0x78 - 1] = "Extreme Engineering Solutions Inc", +[12][0x79 - 1] = "Shangxin Technology Co Ltd", +[12][0x7a - 1] = "Shanghai Zhaoxin Semiconductor Co", +[12][0x7b - 1] = "Xsight Labs Ltd", +[12][0x7c - 1] = "Hangzhou Hikstorage Technology Co", +[12][0x7d - 1] = "Dell Technologies", +[12][0x7e - 1] = "Guangdong StarFive Technology Co", +[13][0x01 - 1] = "TECOTON", +[13][0x02 - 1] = "Abko Co Ltd", +[13][0x03 - 1] = "Shenzhen Feisrike Technology Co Ltd", +[13][0x04 - 1] = "Shenzhen Sunhome Electronics Co Ltd", +[13][0x05 - 1] = "Global Mixed-mode Technology Inc", +[13][0x06 - 1] = "Shenzhen Weien Electronics Co. Ltd.", +[13][0x07 - 1] = "Shenzhen Cooyes Technology Co Ltd", +[13][0x08 - 1] = "Keymos Electronics Co., Limited", +[13][0x09 - 1] = "E-Rockic Technology Company Limited", +[13][0x0a - 1] = "Aerospace Science Memory Shenzhen", +[13][0x0b - 1] = "Shenzhen Quanji Technology Co Ltd", +[13][0x0c - 1] = "Dukosi", +[13][0x0d - 1] = "Maxell Corporation of America", +[13][0x0e - 1] = "Shenshen Xinxintao Electronics Co Ltd", +[13][0x0f - 1] = "Zhuhai Sanxia Semiconductor Co Ltd", +[13][0x10 - 1] = "Groq Inc", +[13][0x11 - 1] = "AstraTek", +[13][0x12 - 1] = "Shenzhen Xinyuze Technology Co Ltd", +[13][0x13 - 1] = "All Bit Semiconductor", +[13][0x14 - 1] = "ACFlow", +[13][0x15 - 1] = "Shenzhen Sipeed Technology Co Ltd", +[13][0x16 - 1] = "Linzhi Hong Kong Co Limited", +[13][0x17 - 1] = "Supreme Wise Limited", +[13][0x18 - 1] = "Blue Cheetah Analog Design Inc", +[13][0x19 - 1] = "Hefei Laiku Technology Co Ltd", +[13][0x1a - 1] = "Zord", +[13][0x1b - 1] = "SBO Hearing A/S", +[13][0x1c - 1] = "Regent Sharp International Limited", +[13][0x1d - 1] = "Permanent Potential Limited", +[13][0x1e - 1] = "Creative World International Limited", +[13][0x1f - 1] = "Base Creation International Limited", +[13][0x20 - 1] = "Shenzhen Zhixin Chuanglian Technology", +[13][0x21 - 1] = "Protected Logic Corporation", +[13][0x22 - 1] = "Sabrent", +[13][0x23 - 1] = "Union Memory", +[13][0x24 - 1] = "NEUCHIPS Corporation", +[13][0x25 - 1] = "Ingenic Semiconductor Co Ltd", +[13][0x26 - 1] = "SiPearl", +[13][0x27 - 1] = "Shenzhen Actseno Information Technology", +[13][0x28 - 1] = "RIVAI Technologies (Shenzhen) Co Ltd", +[13][0x29 - 1] = "Shenzhen Sunny Technology Co Ltd", +[13][0x2a - 1] = "Cott Electronics Ltd", +[13][0x2b - 1] = "Shanghai Synsense Technologies Co Ltd", +[13][0x2c - 1] = "Shenzhen Jintang Fuming Optoelectronics", +[13][0x2d - 1] = "CloudBEAR LLC", +[13][0x2e - 1] = "Emzior, LLC", +[13][0x2f - 1] = "Ehiway Microelectronic Science Tech Co", +[13][0x30 - 1] = "UNIM Innovation Technology (Wu XI)", +[13][0x31 - 1] = "GDRAMARS", +[13][0x32 - 1] = "Meminsights Technology", +[13][0x33 - 1] = "Zhuzhou Hongda Electronics Corp Ltd", +[13][0x34 - 1] = "Luminous Computing Inc", +[13][0x35 - 1] = "PROXMEM", +[13][0x36 - 1] = "Draper Labs", +[13][0x37 - 1] = "ORICO Technologies Co. Ltd.", +[13][0x38 - 1] = "Space Exploration Technologies Corp", +[13][0x39 - 1] = "AONDEVICES Inc", +[13][0x3a - 1] = "Shenzhen Netforward Micro Electronic", +[13][0x3b - 1] = "Syntacore Ltd", +[13][0x3c - 1] = "Shenzhen Secmem Microelectronics Co", +[13][0x3d - 1] = "ONiO As", +[13][0x3e - 1] = "Shenzhen Peladn Technology Co Ltd", +[13][0x3f - 1] = "O-Cubes Shanghai Microelectronics", +[13][0x40 - 1] = "ASTC", +[13][0x41 - 1] = "UMIS", +[13][0x42 - 1] = "Paradromics", +[13][0x43 - 1] = "Sinh Micro Co Ltd", +[13][0x44 - 1] = "Metorage Semiconductor Technology Co", +[13][0x45 - 1] = "Aeva Inc", +[13][0x46 - 1] = "HongKong Hyunion Electronics Co Ltd", +[13][0x47 - 1] = "China Flash Co Ltd", +[13][0x48 - 1] = "Sunplus Technology Co Ltd", +[13][0x49 - 1] = "Idaho Scientific", +[13][0x4a - 1] = "Suzhou SF Micro Electronics Co Ltd", +[13][0x4b - 1] = "IMEX Cap AG", +[13][0x4c - 1] = "Fitipower Integrated Technology Co Ltd", +[13][0x4d - 1] = "ShenzhenWooacme Technology Co Ltd", +[13][0x4e - 1] = "KeepData Original Chips", +[13][0x4f - 1] = "Rivos Inc", +[13][0x50 - 1] = "Big Innovation Company Limited", +[13][0x51 - 1] = "Wuhan YuXin Semiconductor Co Ltd", +[13][0x52 - 1] = "United Memory Technology (Jiangsu)", +[13][0x53 - 1] = "PQShield Ltd", +[13][0x54 - 1] = "ArchiTek Corporation", +[13][0x55 - 1] = "ShenZhen AZW Technology Co Ltd", +[13][0x56 - 1] = "Hengchi Zhixin (Dongguan) Technology", +[13][0x57 - 1] = "Eggtronic Engineering Spa", +[13][0x58 - 1] = "Fusontai Technology", +[13][0x59 - 1] = "PULP Platform", +[13][0x5a - 1] = "Koitek Electronic Technology (Shenzhen) Co", +[13][0x5b - 1] = "Shenzhen Jiteng Network Technology Co", +[13][0x5c - 1] = "Aviva Links Inc", +[13][0x5d - 1] = "Trilinear Technologies Inc", +[13][0x5e - 1] = "Shenzhen Developer Microelectronics Co", +[13][0x5f - 1] = "Guangdong OPPO Mobile Telecommunication", +[13][0x60 - 1] = "Akeana", +[13][0x61 - 1] = "Lyczar", +[13][0x62 - 1] = "Shenzhen Qiji Technology Co Ltd", +[13][0x63 - 1] = "Shenzhen Shangzhaoyuan Technology", +[13][0x64 - 1] = "Han Stor", +[13][0x65 - 1] = "China Micro Semicon Co., Ltd.", +[13][0x66 - 1] = "Shenzhen Zhuqin Technology Co Ltd", +[13][0x67 - 1] = "Shanghai Ningyuan Electronic Technology", +[13][0x68 - 1] = "Auradine", +[13][0x69 - 1] = "Suzhou Yishuo Electronics Co Ltd", +[13][0x6a - 1] = "Faurecia Clarion Electronics", +[13][0x6b - 1] = "SiMa Technologies", +[13][0x6c - 1] = "CFD Sales Inc", +[13][0x6d - 1] = "Suzhou Comay Information Co Ltd", +[13][0x6e - 1] = "Yentek", +[13][0x6f - 1] = "Qorvo Inc", +[13][0x70 - 1] = "Shenzhen Youzhi Computer Technology", +[13][0x71 - 1] = "Sychw Technology (Shenzhen) Co Ltd", +[13][0x72 - 1] = "MK Founder Technology Co Ltd", +[13][0x73 - 1] = "Siliconwaves Technologies Co Ltd", +[13][0x74 - 1] = "Hongkong Hyunion Electronics Co Ltd", +[13][0x75 - 1] = "Shenzhen Xinxinzhitao Electronics Business", +[13][0x76 - 1] = "Shenzhen HenQi Electronic Commerce Co", +[13][0x77 - 1] = "Shenzhen Jingyi Technology Co Ltd", +[13][0x78 - 1] = "Xiaohua Semiconductor Co. Ltd.", +[13][0x79 - 1] = "Shenzhen Dalu Semiconductor Technology", +[13][0x7a - 1] = "Shenzhen Ninespeed Electronics Co Ltd", +[13][0x7b - 1] = "ICYC Semiconductor Co Ltd", +[13][0x7c - 1] = "Shenzhen Jaguar Microsystems Co Ltd", +[13][0x7d - 1] = "Beijing EC-Founder Co Ltd", +[13][0x7e - 1] = "Shenzhen Taike Industrial Automation Co", +[14][0x01 - 1] = "Kalray SA", +[14][0x02 - 1] = "Shanghai Iluvatar CoreX Semiconductor Co", +[14][0x03 - 1] = "Fungible Inc", +[14][0x04 - 1] = "Song Industria E Comercio de Eletronicos", +[14][0x05 - 1] = "DreamBig Semiconductor Inc", +[14][0x06 - 1] = "ChampTek Electronics Corp", +[14][0x07 - 1] = "Fusontai Technology", +[14][0x08 - 1] = "Endress Hauser AG", +[14][0x09 - 1] = "altec ComputerSysteme GmbH", +[14][0x0a - 1] = "UltraRISC Technology (Shanghai) Co Ltd", +[14][0x0b - 1] = "Shenzhen Jing Da Kang Technology Co Ltd", +[14][0x0c - 1] = "Hangzhou Hongjun Microelectronics Co Ltd", +[14][0x0d - 1] = "Pliops Ltd", +[14][0x0e - 1] = "Cix Technology (Shanghai) Co Ltd", +[14][0x0f - 1] = "TeraDevices Inc", +[14][0x10 - 1] = "SpacemiT (Hangzhou)Technology Co Ltd", +[14][0x11 - 1] = "InnoPhase loT Inc", +[14][0x12 - 1] = "InnoPhase loT Inc", +[14][0x13 - 1] = "Yunhight Microelectronics", +[14][0x14 - 1] = "Samnix", +[14][0x15 - 1] = "HKC Storage Co Ltd", +[14][0x16 - 1] = "Chiplego Technology (Shanghai) Co Ltd", +[14][0x17 - 1] = "StoreSkill", +[14][0x18 - 1] = "Shenzhen Astou Technology Company", +[14][0x19 - 1] = "Guangdong LeafFive Technology Limited", +[14][0x1a - 1] = "Jin JuQuan", +[14][0x1b - 1] = "Huaxuan Technology (Shenzhen) Co Ltd", +[14][0x1c - 1] = "Gigastone Corporation", +[14][0x1d - 1] = "Kinsotin", +[14][0x1e - 1] = "PengYing", +[14][0x1f - 1] = "Shenzhen Xunhi Technology Co Ltd", +[14][0x20 - 1] = "FOXX Storage Inc", +[14][0x21 - 1] = "Shanghai Belling Corporation Ltd", +[14][0x22 - 1] = "Glenfy Tech Co Ltd", +[14][0x23 - 1] = "Sahasra Semiconductors Pvt Ltd", +[14][0x24 - 1] = "Chongqing SeekWave Technology Co Ltd", +[14][0x25 - 1] = "Shenzhen Zhixing Intelligent Manufacturing", +[14][0x26 - 1] = "Ethernovia", +[14][0x27 - 1] = "Shenzhen Xinrongda Technology Co Ltd", +[14][0x28 - 1] = "Hangzhou Clounix Technology Limited", +[14][0x29 - 1] = "JGINYUE", +[14][0x2a - 1] = "Shenzhen Xinwei Semiconductor Co Ltd", +[14][0x2b - 1] = "COLORFIRE Technology Co Ltd", +[14][0x2c - 1] = "B LKE", +[14][0x2d - 1] = "ZHUDIAN", +[14][0x2e - 1] = "REECHO", +[14][0x2f - 1] = "Enphase Energy Inc", +[14][0x30 - 1] = "Shenzhen Yingrui Storage Technology Co Ltd", +[14][0x31 - 1] = "Shenzhen Sinomos Semiconductor Technology", +[14][0x32 - 1] = "O2micro International Limited", +[14][0x33 - 1] = "Axelera AI BV", +[14][0x34 - 1] = "Silicon Legend Technology (Suzhou) Co Ltd", +[14][0x35 - 1] = "Suzhou Novosense Microelectronics Co Ltd", +[14][0x36 - 1] = "Pirateman", +[14][0x37 - 1] = "Yangtze MasonSemi", +[14][0x38 - 1] = "Shanghai Yunsilicon Technology Co Ltd", +[14][0x39 - 1] = "Rayson", +[14][0x3a - 1] = "Alphawave IP", +[14][0x3b - 1] = "Shenzhen Visions Chip Electronic Technology", +[14][0x3c - 1] = "KYO Group", +[14][0x3d - 1] = "Shenzhen Aboison Technology Co Ltd", +[14][0x3e - 1] = "Shenzhen JingSheng Semiconducto Co Ltd", +[14][0x3f - 1] = "Shenzhen Dingsheng Technology Co Ltd", +[14][0x40 - 1] = "EVAS Intelligence Co Ltd", +[14][0x41 - 1] = "Kaibright Electronic Technologies", +[14][0x42 - 1] = "Fraunhofer IMS", +[14][0x43 - 1] = "Shenzhen Xinrui Renhe Technology", +[14][0x44 - 1] = "Beijing Vcore Technology Co Ltd", +[14][0x45 - 1] = "Silicon Innovation Technologies Co Ltd", +[14][0x46 - 1] = "Shenzhen Zhengxinda Technology Co Ltd", +[14][0x47 - 1] = "Shenzhen Remai Electronics Co Lttd", +[14][0x48 - 1] = "Shenzhen Xinruiyan Electronics Co Ltd", +[14][0x49 - 1] = "CEC Huada Electronic Design Co Ltd", +[14][0x4a - 1] = "Westberry Technology Inc", +[14][0x4b - 1] = "Tongxin Microelectronics Co Ltd", +[14][0x4c - 1] = "UNIM Semiconductor (Shang Hai) Co Ltd", +[14][0x4d - 1] = "Shenzhen Qiaowenxingyu Industrial Co Ltd", +[14][0x4e - 1] = "ICC", +[14][0x4f - 1] = "Enfabrica Corporation", +[14][0x50 - 1] = "Niobium Microsystems Inc", +[14][0x51 - 1] = "Xiaoli AI Electronics (Shenzhen) Co Ltd", +[14][0x52 - 1] = "Silicon Mitus", +[14][0x53 - 1] = "Ajiatek Inc", +[14][0x54 - 1] = "HomeNet", +[14][0x55 - 1] = "Shenzhen Shubang Technology Co Ltd", +[14][0x56 - 1] = "Exacta Technologies Ltd", +[14][0x57 - 1] = "Synology", +[14][0x58 - 1] = "Trium Elektronik Bilgi Islem San Ve Dis", +[14][0x59 - 1] = "Wuxi HippStor Technology Co Ltd", +[14][0x5a - 1] = "SSCT", +[14][0x5b - 1] = "Sichuan Heentai Semiconductor Co Ltd", +[14][0x5c - 1] = "Zhejiang University", +[14][0x5d - 1] = "www.shingroup.cn", +[14][0x5e - 1] = "Suzhou Nano Mchip Technology Company", +[14][0x5f - 1] = "Feature Integration Technology Inc", +[14][0x60 - 1] = "d-Matrix", +[14][0x61 - 1] = "Golden Memory", +[14][0x62 - 1] = "Qingdao Thunderobot Technology Co Ltd", +[14][0x63 - 1] = "Shenzhen Tianxiang Chuangxin Technology", +[14][0x64 - 1] = "HYPHY USA", +[14][0x65 - 1] = "Valkyrie", +[14][0x66 - 1] = "Suzhou Hesetc Electronic Technology Co", +[14][0x67 - 1] = "Hainan Zhongyuncun Technology Co Ltd", +[14][0x68 - 1] = "Shenzhen Yousheng Bona Technology Co", +[14][0x69 - 1] = "Shenzhen Xinle Chuang Technology Co", +[14][0x6a - 1] = "DEEPX", +[14][0x6b - 1] = "iStarChip CA LLC", +[14][0x6c - 1] = "Shenzhen Vinreada Technology Co Ltd", +[14][0x6d - 1] = "Novatek Microelectronics Corp", +[14][0x6e - 1] = "Chemgdu EG Technology Co Ltd", +[14][0x6f - 1] = "AGI Technology", +[14][0x70 - 1] = "Syntiant", +[14][0x71 - 1] = "AOC", +[14][0x72 - 1] = "GamePP", +[14][0x73 - 1] = "Yibai Electronic Technologies", +[14][0x74 - 1] = "Hangzhou Rencheng Trading Co Ltd", +[14][0x75 - 1] = "HOGE Technology Co Ltd", +[14][0x76 - 1] = "United Micro Technology (Shenzhen) Co", +[14][0x77 - 1] = "Fabric of Truth Inc", +[14][0x78 - 1] = "Epitech", +[14][0x79 - 1] = "Elitestek", +[14][0x7a - 1] = "Cornelis Networks Inc", +[14][0x7b - 1] = "WingSemi Technologies Co Ltd", +[14][0x7c - 1] = "ForwardEdge ASIC", +[14][0x7d - 1] = "Beijing Future Imprint Technology Co Ltd", +[14][0x7e - 1] = "Fine Made Microelectronics Group Co Ltd", +[15][0x01 - 1] = "Changxin Memory Technology (Shanghai)", +[15][0x02 - 1] = "Synconv", +[15][0x03 - 1] = "MULTIUNIT", +[15][0x04 - 1] = "Zero ASIC Corporation", +[15][0x05 - 1] = "NTT Innovative Devices Corporation", +[15][0x06 - 1] = "Xbstor", +[15][0x07 - 1] = "Shenzhen South Electron Co Ltd", +[15][0x08 - 1] = "Iontra Inc", +[15][0x09 - 1] = "SIEFFI Inc", +[15][0x0a - 1] = "HK Winston Electronics Co Limited", +[15][0x0b - 1] = "Anhui SunChip Semiconductor Technology", +[15][0x0c - 1] = "HaiLa Technologies Inc", +[15][0x0d - 1] = "AUTOTALKS", +[15][0x0e - 1] = "Shenzhen Ranshuo Technology Co Limited", +[15][0x0f - 1] = "ScaleFlux", +[15][0x10 - 1] = "XC Memory", +[15][0x11 - 1] = "Guangzhou Beimu Technology Co., Ltd", +[15][0x12 - 1] = "Rays Semiconductor Nanjing Co Ltd", +[15][0x13 - 1] = "Milli-Centi Intelligence Technology Jiangsu", +[15][0x14 - 1] = "Zilia Technologioes", +[15][0x15 - 1] = "Incore Semiconductors", +[15][0x16 - 1] = "Kinetic Technologies", +[15][0x17 - 1] = "Nanjing Houmo Technology Co Ltd", +[15][0x18 - 1] = "Suzhou Yige Technology Co Ltd", +[15][0x19 - 1] = "Shenzhen Techwinsemi Technology Co Ltd", +[15][0x1a - 1] = "Pure Array Technology (Shanghai) Co. Ltd", +[15][0x1b - 1] = "Shenzhen Techwinsemi Technology Udstore", +[15][0x1c - 1] = "RISE MODE", +[15][0x1d - 1] = "NEWREESTAR", +[15][0x1e - 1] = "Hangzhou Hualan Microeletronique Co Ltd", +[15][0x1f - 1] = "Senscomm Semiconductor Co Ltd", +[15][0x20 - 1] = "Holt Integrated Circuits", +[15][0x21 - 1] = "Tenstorrent Inc", +[15][0x22 - 1] = "SkyeChip", +[15][0x23 - 1] = "Guangzhou Kaishile Trading Co Ltd", +[15][0x24 - 1] = "Jing Pai Digital Technology (Shenzhen) Co", /* EOF */ diff --git a/src/helper/jim-nvp.c b/src/helper/jim-nvp.c index 0409a83cdf..e1ab64ae5b 100644 --- a/src/helper/jim-nvp.c +++ b/src/helper/jim-nvp.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: BSD-2-Clause-Views + /* Jim - A small embeddable Tcl interpreter * * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org> @@ -11,34 +13,7 @@ * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl> * Copyright 2009 Zachary T Welch zw@superlucidity.net * Copyright 2009 David Brownell - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of the Jim Tcl Project. + * Copyright (c) 2005-2011 Jim Tcl Project. All rights reserved. */ #ifdef HAVE_CONFIG_H diff --git a/src/helper/jim-nvp.h b/src/helper/jim-nvp.h index 00e4af944b..11824cabf4 100644 --- a/src/helper/jim-nvp.h +++ b/src/helper/jim-nvp.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause-Views */ + /* Jim - A small embeddable Tcl interpreter * * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org> @@ -11,34 +13,7 @@ * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl> * Copyright 2009 Zachary T Welch zw@superlucidity.net * Copyright 2009 David Brownell - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of the Jim Tcl Project. + * Copyright (c) 2005-2011 Jim Tcl Project. All rights reserved. */ #ifndef OPENOCD_HELPER_JIM_NVP_H @@ -326,144 +301,4 @@ void jim_getopt_nvp_unknown(struct jim_getopt_info *goi, const struct jim_nvp *l */ int jim_getopt_enum(struct jim_getopt_info *goi, const char *const *lookup, int *puthere); -/* - * DEPRECATED API - * Do not use these API anymore, as they do not comply with OpenOCD coding style - * They are listed here to avoid breaking build after merge of patches already queued in gerrit - */ - -static inline __attribute__ ((deprecated)) -const char *Jim_Debug_ArgvString(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - return jim_debug_argv_string(interp, argc, argv); -} - -static inline __attribute__ ((deprecated)) -int Jim_GetNvp(Jim_Interp *interp, Jim_Obj *objptr, const struct jim_nvp *nvp_table, const struct jim_nvp **result) -{ - return jim_get_nvp(interp, objptr, nvp_table, result); -} - -static inline __attribute__ ((deprecated)) -void Jim_GetOpt_Debug(struct jim_getopt_info *goi) -{ - jim_getopt_debug(goi); -} - -static inline __attribute__ ((deprecated)) -int Jim_GetOpt_Double(struct jim_getopt_info *goi, double *puthere) -{ - return jim_getopt_double(goi, puthere); -} - -static inline __attribute__ ((deprecated)) -int Jim_GetOpt_Enum(struct jim_getopt_info *goi, const char *const *lookup, int *puthere) -{ - return jim_getopt_enum(goi, lookup, puthere); -} - -static inline __attribute__ ((deprecated)) -int Jim_GetOpt_Nvp(struct jim_getopt_info *goi, const struct jim_nvp *lookup, struct jim_nvp **puthere) -{ - return jim_getopt_nvp(goi, lookup, puthere); -} - -static inline __attribute__ ((deprecated)) -void Jim_GetOpt_NvpUnknown(struct jim_getopt_info *goi, const struct jim_nvp *lookup, int hadprefix) -{ - jim_getopt_nvp_unknown(goi, lookup, hadprefix); -} - -static inline __attribute__ ((deprecated)) -int Jim_GetOpt_Obj(struct jim_getopt_info *goi, Jim_Obj **puthere) -{ - return jim_getopt_obj(goi, puthere); -} - -static inline __attribute__ ((deprecated)) -int Jim_GetOpt_Setup(struct jim_getopt_info *goi, Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - return jim_getopt_setup(goi, interp, argc, argv); -} - -static inline __attribute__ ((deprecated)) -int Jim_GetOpt_String(struct jim_getopt_info *goi, const char **puthere, int *len) -{ - return jim_getopt_string(goi, puthere, len); -} - -static inline __attribute__ ((deprecated)) -int Jim_GetOpt_Wide(struct jim_getopt_info *goi, jim_wide *puthere) -{ - return jim_getopt_wide(goi, puthere); -} - -static inline __attribute__ ((deprecated)) -int Jim_Nvp_name2value(Jim_Interp *interp, const struct jim_nvp *nvp_table, const char *name, struct jim_nvp **result) -{ - return jim_nvp_name2value(interp, nvp_table, name, result); -} - -static inline __attribute__ ((deprecated)) -int Jim_Nvp_name2value_nocase(Jim_Interp *interp, const struct jim_nvp *nvp_table, const char *name, - struct jim_nvp **result) -{ - return jim_nvp_name2value_nocase(interp, nvp_table, name, result); -} - -static inline __attribute__ ((deprecated)) -struct jim_nvp *Jim_Nvp_name2value_nocase_simple(const struct jim_nvp *nvp_table, const char *name) -{ - return jim_nvp_name2value_nocase_simple(nvp_table, name); -} - -static inline __attribute__ ((deprecated)) -int Jim_Nvp_name2value_obj(Jim_Interp *interp, const struct jim_nvp *nvp_table, Jim_Obj *name_obj, - struct jim_nvp **result) -{ - return jim_nvp_name2value_obj(interp, nvp_table, name_obj, result); -} - -static inline __attribute__ ((deprecated)) -int Jim_Nvp_name2value_obj_nocase(Jim_Interp *interp, const struct jim_nvp *nvp_table, Jim_Obj *name_obj, - struct jim_nvp **result) -{ - return jim_nvp_name2value_obj_nocase(interp, nvp_table, name_obj, result); -} - -static inline __attribute__ ((deprecated)) -struct jim_nvp *Jim_Nvp_name2value_simple(const struct jim_nvp *nvp_table, const char *name) -{ - return jim_nvp_name2value_simple(nvp_table, name); -} - -static inline __attribute__ ((deprecated)) -int Jim_Nvp_value2name(Jim_Interp *interp, const struct jim_nvp *nvp_table, int value, struct jim_nvp **result) -{ - return jim_nvp_value2name(interp, nvp_table, value, result); -} - -static inline __attribute__ ((deprecated)) -int Jim_Nvp_value2name_obj(Jim_Interp *interp, const struct jim_nvp *nvp_table, Jim_Obj *value_obj, - struct jim_nvp **result) -{ - return jim_nvp_value2name_obj(interp, nvp_table, value_obj, result); -} - -static inline __attribute__ ((deprecated)) -struct jim_nvp *Jim_Nvp_value2name_simple(const struct jim_nvp *nvp_table, int v) -{ - return jim_nvp_value2name_simple(nvp_table, v); -} - -static inline __attribute__ ((deprecated)) -void Jim_SetResult_NvpUnknown(Jim_Interp *interp, Jim_Obj *param_name, Jim_Obj *param_value, - const struct jim_nvp *nvp_table) -{ - jim_set_result_nvp_unknown(interp, param_name, param_value, nvp_table); -} - -typedef struct jim_getopt_info Jim_GetOptInfo __attribute__ ((deprecated)); -typedef struct jim_nvp Jim_Nvp __attribute__ ((deprecated)); - #endif /* OPENOCD_HELPER_JIM_NVP_H */ diff --git a/src/helper/list.h b/src/helper/list.h index 552a3202a5..c9de0569bc 100644 --- a/src/helper/list.h +++ b/src/helper/list.h @@ -27,13 +27,6 @@ struct list_head { struct list_head *next, *prev; }; -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next, **pprev; -}; /* end local changes */ /* @@ -272,8 +265,7 @@ static inline void list_bulk_move_tail(struct list_head *head, * @param list the entry to test * @param head the head of the list */ -static inline int list_is_first(const struct list_head *list, - const struct list_head *head) +static inline int list_is_first(const struct list_head *list, const struct list_head *head) { return list->prev == head; } @@ -283,12 +275,21 @@ static inline int list_is_first(const struct list_head *list, * @param list the entry to test * @param head the head of the list */ -static inline int list_is_last(const struct list_head *list, - const struct list_head *head) +static inline int list_is_last(const struct list_head *list, const struct list_head *head) { return list->next == head; } +/** + * list_is_head - tests whether @a list is the list @a head + * @param list the entry to test + * @param head the head of the list + */ +static inline int list_is_head(const struct list_head *list, const struct list_head *head) +{ + return list == head; +} + /** * list_empty - tests whether a list is empty * @param head the list to test. @@ -407,10 +408,9 @@ static inline void list_cut_position(struct list_head *list, { if (list_empty(head)) return; - if (list_is_singular(head) && - (head->next != entry && head != entry)) + if (list_is_singular(head) && !list_is_head(entry, head) && (entry != head->next)) return; - if (entry == head) + if (list_is_head(entry, head)) INIT_LIST_HEAD(list); else __list_cut_position(list, head, entry); @@ -570,6 +570,19 @@ static inline void list_splice_tail_init(struct list_head *list, #define list_next_entry(pos, member) \ list_entry((pos)->member.next, typeof(*(pos)), member) +/** + * list_next_entry_circular - get the next element in list + * @param pos the type * to cursor. + * @param head the list head to take the element from. + * @param member the name of the list_head within the struct. + * + * Wraparound if pos is the last element (return the first element). + * Note, that list is expected to be not empty. + */ +#define list_next_entry_circular(pos, head, member) \ + (list_is_last(&(pos)->member, head) ? \ + list_first_entry(head, typeof(*(pos)), member) : list_next_entry(pos, member)) + /** * list_prev_entry - get the prev element in list * @param pos the type * to cursor @@ -578,13 +591,28 @@ static inline void list_splice_tail_init(struct list_head *list, #define list_prev_entry(pos, member) \ list_entry((pos)->member.prev, typeof(*(pos)), member) +/** + * list_prev_entry_circular - get the prev element in list + * @param pos the type * to cursor. + * @param head the list head to take the element from. + * @param member the name of the list_head within the struct. + * + * Wraparound if pos is the first element (return the last element). + * Note, that list is expected to be not empty. + */ +#define list_prev_entry_circular(pos, head, member) \ + (list_is_first(&(pos)->member, head) ? \ + list_last_entry(head, typeof(*(pos)), member) : list_prev_entry(pos, member)) + /** * list_for_each - iterate over a list * @param pos the &struct list_head to use as a loop cursor. * @param head the head for your list. */ #define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) + for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next) + +/* Ignore kernel list_for_each_rcu() */ /** * list_for_each_continue - continue iteration over a list @@ -625,6 +653,21 @@ static inline void list_splice_tail_init(struct list_head *list, pos != (head); \ pos = n, n = pos->prev) +/** + * list_count_nodes - count nodes in the list + * @param head the head for your list. + */ +static inline size_t list_count_nodes(struct list_head *head) +{ + struct list_head *pos; + size_t count = 0; + + list_for_each(pos, head) + count++; + + return count; +} + /** * list_entry_is_head - test if the entry points to the head of the list * @param pos the type * to cursor @@ -811,237 +854,7 @@ static inline void list_splice_tail_init(struct list_head *list, /* * Double linked lists with a single pointer list head. - * Mostly useful for hash tables where the two pointer list head is - * too wasteful. - * You lose the ability to access the tail in O(1). - */ - -#define HLIST_HEAD_INIT { .first = NULL } -#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } -#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) -static inline void INIT_HLIST_NODE(struct hlist_node *h) -{ - h->next = NULL; - h->pprev = NULL; -} - -/** - * hlist_unhashed - Has node been removed from list and reinitialized? - * @param h Node to be checked - * - * Not that not all removal functions will leave a node in unhashed - * state. For example, hlist_nulls_del_init_rcu() does leave the - * node in unhashed state, but hlist_nulls_del() does not. - */ -static inline int hlist_unhashed(const struct hlist_node *h) -{ - return !h->pprev; -} - -/* Ignore kernel hlist_unhashed_lockless() */ - -/** - * hlist_empty - Is the specified hlist_head structure an empty hlist? - * @param h Structure to check. - */ -static inline int hlist_empty(const struct hlist_head *h) -{ - return !h->first; -} - -static inline void __hlist_del(struct hlist_node *n) -{ - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - - *pprev = next; - if (next) - next->pprev = pprev; -} - -/** - * hlist_del - Delete the specified hlist_node from its list - * @param n Node to delete. - * - * Note that this function leaves the node in hashed state. Use - * hlist_del_init() or similar instead to unhash @a n. - */ -static inline void hlist_del(struct hlist_node *n) -{ - __hlist_del(n); - n->next = LIST_POISON1; - n->pprev = LIST_POISON2; -} - -/** - * hlist_del_init - Delete the specified hlist_node from its list and initialize - * @param n Node to delete. - * - * Note that this function leaves the node in unhashed state. - */ -static inline void hlist_del_init(struct hlist_node *n) -{ - if (!hlist_unhashed(n)) { - __hlist_del(n); - INIT_HLIST_NODE(n); - } -} - -/** - * hlist_add_head - add a new entry at the beginning of the hlist - * @param n new entry to be added - * @param h hlist head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - h->first = n; - n->pprev = &h->first; -} - -/** - * hlist_add_before - add a new entry before the one specified - * @param n new entry to be added - * @param next hlist node to add it before, which must be non-NULL - */ -static inline void hlist_add_before(struct hlist_node *n, - struct hlist_node *next) -{ - n->pprev = next->pprev; - n->next = next; - next->pprev = &n->next; - *(n->pprev) = n; -} - -/** - * hlist_add_behind - add a new entry after the one specified - * @param n new entry to be added - * @param prev hlist node to add it after, which must be non-NULL - */ -static inline void hlist_add_behind(struct hlist_node *n, - struct hlist_node *prev) -{ - n->next = prev->next; - prev->next = n; - n->pprev = &prev->next; - - if (n->next) - n->next->pprev = &n->next; -} - -/** - * hlist_add_fake - create a fake hlist consisting of a single headless node - * @param n Node to make a fake list out of - * - * This makes @a n appear to be its own predecessor on a headless hlist. - * The point of this is to allow things like hlist_del() to work correctly - * in cases where there is no list. - */ -static inline void hlist_add_fake(struct hlist_node *n) -{ - n->pprev = &n->next; -} - -/** - * hlist_fake: Is this node a fake hlist? - * @param h Node to check for being a self-referential fake hlist. - */ -static inline bool hlist_fake(struct hlist_node *h) -{ - return h->pprev == &h->next; -} - -/** - * hlist_is_singular_node - is node the only element of the specified hlist? - * @param n Node to check for singularity. - * @param h Header for potentially singular list. - * - * Check whether the node is the only node of the head without - * accessing head, thus avoiding unnecessary cache misses. - */ -static inline bool -hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h) -{ - return !n->next && n->pprev == &h->first; -} - -/** - * hlist_move_list - Move an hlist - * @param old hlist_head for old list. - * @param new hlist_head for new list. - * - * Move a list from one list head to another. Fixup the pprev - * reference of the first entry if it exists. - */ -static inline void hlist_move_list(struct hlist_head *old, - struct hlist_head *new) -{ - new->first = old->first; - if (new->first) - new->first->pprev = &new->first; - old->first = NULL; -} - -#define hlist_entry(ptr, type, member) container_of(ptr, type, member) - -#define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos ; pos = pos->next) - -#define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ - pos = n) - -#define hlist_entry_safe(ptr, type, member) \ - ({ typeof(ptr) ____ptr = (ptr); \ - ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ - }) - -/** - * hlist_for_each_entry - iterate over list of given type - * @param pos the type * to use as a loop cursor. - * @param head the head for your list. - * @param member the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry(pos, head, member) \ - for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ - pos; \ - pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) - -/** - * hlist_for_each_entry_continue - iterate over a hlist continuing after current point - * @param pos the type * to use as a loop cursor. - * @param member the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_continue(pos, member) \ - for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member);\ - pos; \ - pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) - -/** - * hlist_for_each_entry_from - iterate over a hlist continuing from current point - * @param pos the type * to use as a loop cursor. - * @param member the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_from(pos, member) \ - for (; pos; \ - pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) - -/** - * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @param pos the type * to use as a loop cursor. - * @param n a &struct hlist_node to use as temporary storage - * @param head the head for your list. - * @param member the name of the hlist_node within the struct. + * IGNORED */ -#define hlist_for_each_entry_safe(pos, n, head, member) \ - for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\ - pos && ({ n = pos->member.next; 1; }); \ - pos = hlist_entry_safe(n, typeof(*pos), member)) #endif /* OPENOCD_HELPER_LIST_H */ diff --git a/src/helper/log.c b/src/helper/log.c index 106d228675..471069adee 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -30,6 +19,7 @@ #include "command.h" #include "replacements.h" #include "time_support.h" +#include <server/gdb_server.h> #include <server/server.h> #include <stdarg.h> @@ -224,31 +214,28 @@ COMMAND_HANDLER(handle_debug_level_command) COMMAND_HANDLER(handle_log_output_command) { - if (CMD_ARGC == 0 || (CMD_ARGC == 1 && strcmp(CMD_ARGV[0], "default") == 0)) { - if (log_output != stderr && log_output) { - /* Close previous log file, if it was open and wasn't stderr. */ - fclose(log_output); - } - log_output = stderr; - LOG_DEBUG("set log_output to default"); - return ERROR_OK; - } - if (CMD_ARGC == 1) { - FILE *file = fopen(CMD_ARGV[0], "w"); + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + FILE *file; + if (CMD_ARGC == 1 && strcmp(CMD_ARGV[0], "default") != 0) { + file = fopen(CMD_ARGV[0], "w"); if (!file) { - LOG_ERROR("failed to open output log '%s'", CMD_ARGV[0]); + command_print(CMD, "failed to open output log \"%s\"", CMD_ARGV[0]); return ERROR_FAIL; } - if (log_output != stderr && log_output) { - /* Close previous log file, if it was open and wasn't stderr. */ - fclose(log_output); - } - log_output = file; - LOG_DEBUG("set log_output to \"%s\"", CMD_ARGV[0]); - return ERROR_OK; + command_print(CMD, "set log_output to \"%s\"", CMD_ARGV[0]); + } else { + file = stderr; + command_print(CMD, "set log_output to default"); } - return ERROR_COMMAND_SYNTAX_ERROR; + if (log_output != stderr && log_output) { + /* Close previous log file, if it was open and wasn't stderr. */ + fclose(log_output); + } + log_output = file; + return ERROR_OK; } static const struct command_registration log_command_handlers[] = { @@ -257,7 +244,7 @@ static const struct command_registration log_command_handlers[] = { .handler = handle_log_output_command, .mode = COMMAND_ANY, .help = "redirect logging to a file (default: stderr)", - .usage = "[file_name | \"default\"]", + .usage = "[file_name | 'default']", }, { .name = "debug_level", @@ -306,12 +293,6 @@ void log_exit(void) log_output = NULL; } -int set_log_output(struct command_context *cmd_ctx, FILE *output) -{ - log_output = output; - return ERROR_OK; -} - /* add/remove log callback handler */ int log_add_callback(log_callback_fn fn, void *priv) { @@ -416,9 +397,7 @@ char *alloc_printf(const char *format, ...) static void gdb_timeout_warning(int64_t delta_time) { - extern int gdb_actual_connections; - - if (gdb_actual_connections) + if (gdb_get_actual_connections()) LOG_WARNING("keep_alive() was not invoked in the " "%d ms timelimit. GDB alive packet not " "sent! (%" PRId64 " ms). Workaround: increase " diff --git a/src/helper/log.h b/src/helper/log.h index f0378ae794..ee71bf03f0 100644 --- a/src/helper/log.h +++ b/src/helper/log.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_HELPER_LOG_H @@ -73,7 +62,6 @@ __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 5, 6))); */ void log_init(void); void log_exit(void); -int set_log_output(struct command_context *cmd_ctx, FILE *output); int log_register_commands(struct command_context *cmd_ctx); diff --git a/src/helper/nvp.c b/src/helper/nvp.c new file mode 100644 index 0000000000..a938716ae9 --- /dev/null +++ b/src/helper/nvp.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: BSD-2-Clause-Views + +/* + * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org> + * Copyright 2005 Clemens Hintze <c.hintze@gmx.net> + * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net> + * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com + * Copyright 2008 Andrew Lunn <andrew@lunn.ch> + * Copyright 2008 Duane Ellis <openocd@duaneellis.com> + * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de> + * Copyright 2008 Steve Bennett <steveb@workware.net.au> + * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl> + * Copyright 2009 Zachary T Welch zw@superlucidity.net + * Copyright 2009 David Brownell + * Copyright (c) 2005-2011 Jim Tcl Project. All rights reserved. + * + * This file is extracted from jim-nvp.c, originally part of jim TCL code. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include <helper/command.h> +#include <helper/nvp.h> + +const struct nvp *nvp_name2value(const struct nvp *p, const char *name) +{ + while (p->name) { + if (strcmp(name, p->name) == 0) + break; + p++; + } + return p; +} + +const struct nvp *nvp_value2name(const struct nvp *p, int value) +{ + while (p->name) { + if (value == p->value) + break; + p++; + } + return p; +} + +void nvp_unknown_command_print(struct command_invocation *cmd, const struct nvp *nvp, + const char *param_name, const char *param_value) +{ + if (param_name) + command_print_sameline(cmd, "%s: Unknown: %s, try one of: ", param_name, param_value); + else + command_print_sameline(cmd, "Unknown param: %s, try one of: ", param_value); + + while (nvp->name) { + if ((nvp + 1)->name) + command_print_sameline(cmd, "%s, ", nvp->name); + else + command_print(cmd, "or %s", nvp->name); + + nvp++; + } + + /* We assume nvp to be not empty and loop has been taken; no need to add a '\n' */ +} diff --git a/src/helper/nvp.h b/src/helper/nvp.h new file mode 100644 index 0000000000..1f4e3d1b43 --- /dev/null +++ b/src/helper/nvp.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: BSD-2-Clause-Views */ + +/* + * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org> + * Copyright 2005 Clemens Hintze <c.hintze@gmx.net> + * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net> + * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com + * Copyright 2008 Andrew Lunn <andrew@lunn.ch> + * Copyright 2008 Duane Ellis <openocd@duaneellis.com> + * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de> + * Copyright 2008 Steve Bennett <steveb@workware.net.au> + * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl> + * Copyright 2009 Zachary T Welch zw@superlucidity.net + * Copyright 2009 David Brownell + * Copyright (c) 2005-2011 Jim Tcl Project. All rights reserved. + * + * This file is extracted from jim-nvp.h, originally part of jim TCL code. + */ + +#ifndef OPENOCD_HELPER_NVP_H +#define OPENOCD_HELPER_NVP_H + +#include <helper/compiler.h> + +/** Name Value Pairs, aka: NVP + * - Given a string - return the associated int. + * - Given a number - return the associated string. + * . + * + * Very useful when the number is not a simple index into an array of + * known string, or there may be multiple strings (aliases) that mean then same + * thing. + * + * An NVP Table is terminated with ".name = NULL". + * + * During the 'name2value' operation, if no matching string is found + * the pointer to the terminal element (with p->name == NULL) is returned. + * + * Example: + * \code + * const struct nvp yn[] = { + * { "yes", 1 }, + * { "no" , 0 }, + * { "yep", 1 }, + * { "nope", 0 }, + * { NULL, -1 }, + * }; + * + * struct nvp *result; + * result = nvp_name2value(yn, "yes"); + * returns &yn[0]; + * result = nvp_name2value(yn, "no"); + * returns &yn[1]; + * result = nvp_name2value(yn, "Blah"); + * returns &yn[4]; + * \endcode + * + * During the number2name operation, the first matching value is returned. + */ + +struct nvp { + const char *name; + int value; +}; + +struct command_invocation; + +/* Name Value Pairs Operations */ +const struct nvp *nvp_name2value(const struct nvp *nvp_table, const char *name) + __returns_nonnull __nonnull((1)); +const struct nvp *nvp_value2name(const struct nvp *nvp_table, int v) + __returns_nonnull __nonnull((1)); + +void nvp_unknown_command_print(struct command_invocation *cmd, const struct nvp *nvp, + const char *param_name, const char *param_value); + +#endif /* OPENOCD_HELPER_NVP_H */ diff --git a/src/helper/options.c b/src/helper/options.c index 199672789b..05cde6709f 100644 --- a/src/helper/options.c +++ b/src/helper/options.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -50,12 +39,12 @@ static int help_flag, version_flag; static const struct option long_options[] = { {"help", no_argument, &help_flag, 1}, {"version", no_argument, &version_flag, 1}, - {"debug", optional_argument, 0, 'd'}, - {"file", required_argument, 0, 'f'}, - {"search", required_argument, 0, 's'}, - {"log_output", required_argument, 0, 'l'}, - {"command", required_argument, 0, 'c'}, - {0, 0, 0, 0} + {"debug", optional_argument, NULL, 'd'}, + {"file", required_argument, NULL, 'f'}, + {"search", required_argument, NULL, 's'}, + {"log_output", required_argument, NULL, 'l'}, + {"command", required_argument, NULL, 'c'}, + {NULL, 0, NULL, 0} }; int configuration_output_handler(struct command_context *context, const char *line) diff --git a/src/helper/replacements.c b/src/helper/replacements.c index c34b17ec5a..782d975184 100644 --- a/src/helper/replacements.c +++ b/src/helper/replacements.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,24 +9,19 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ -/* DANGER!!!! These must be defined *BEFORE* replacements.h and the malloc() macro!!!! */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* define IN_REPLACEMENTS_C before include replacements.h */ +#define IN_REPLACEMENTS_C +#include "replacements.h" #include <stdlib.h> #include <string.h> + /* * clear_malloc * @@ -52,10 +49,6 @@ void *fill_malloc(size_t size) return t; } -#define IN_REPLACEMENTS_C -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif #ifdef HAVE_STRINGS_H #include <strings.h> #endif diff --git a/src/helper/replacements.h b/src/helper/replacements.h index 4d70d9cf30..6e30b628b0 100644 --- a/src/helper/replacements.h +++ b/src/helper/replacements.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_HELPER_REPLACEMENTS_H @@ -77,12 +66,10 @@ int gettimeofday(struct timeval *tv, struct timezone *tz); #endif -#ifndef IN_REPLACEMENTS_C -/**** clear_malloc & fill_malloc ****/ void *clear_malloc(size_t size); void *fill_malloc(size_t size); -#endif +#ifndef IN_REPLACEMENTS_C /* * Now you have 3 ways for the malloc function: * @@ -111,6 +98,7 @@ void *fill_malloc(size_t size); /* #define malloc(_a) clear_malloc(_a) * #define malloc(_a) fill_malloc(_a) */ +#endif /* IN_REPLACEMENTS_C */ /* GNU extensions to the C library that may be missing on some systems */ #ifndef HAVE_STRNDUP diff --git a/src/helper/startup.tcl b/src/helper/startup.tcl index 71f489dd5f..5a0d479f5e 100644 --- a/src/helper/startup.tcl +++ b/src/helper/startup.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Defines basic Tcl procs that must exist for OpenOCD scripts to work. # # Embedded into OpenOCD executable @@ -28,4 +30,26 @@ proc script {filename} { add_help_text script "filename of OpenOCD script (tcl) to run" add_usage_text script "<file>" +# Run a list of post-init commands +# Each command should be added with 'lappend post_init_commands command' +lappend _telnet_autocomplete_skip _run_post_init_commands +proc _run_post_init_commands {} { + if {[info exists ::post_init_commands]} { + foreach cmd $::post_init_commands { + eval $cmd + } + } +} + +# Run a list of pre-shutdown commands +# Each command should be added with 'lappend pre_shutdown_commands command' +lappend _telnet_autocomplete_skip _run_pre_shutdown_commands +proc _run_pre_shutdown_commands {} { + if {[info exists ::pre_shutdown_commands]} { + foreach cmd $::pre_shutdown_commands { + eval $cmd + } + } +} + ######### diff --git a/src/helper/system.h b/src/helper/system.h index 0d8be648cb..bd96d626ab 100644 --- a/src/helper/system.h +++ b/src/helper/system.h @@ -1,21 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007-2008 by Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_HELPER_SYSTEM_H diff --git a/src/helper/time_support.c b/src/helper/time_support.c index 861889ec69..dda3cb3e4e 100644 --- a/src/helper/time_support.c +++ b/src/helper/time_support.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/helper/time_support.h b/src/helper/time_support.h index b83c0ac772..c984296819 100644 --- a/src/helper/time_support.h +++ b/src/helper/time_support.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_HELPER_TIME_SUPPORT_H diff --git a/src/helper/time_support_common.c b/src/helper/time_support_common.c index b733c270ef..9d17a315bf 100644 --- a/src/helper/time_support_common.c +++ b/src/helper/time_support_common.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/helper/types.h b/src/helper/types.h index 010529ffc3..53249e5b79 100644 --- a/src/helper/types.h +++ b/src/helper/types.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_HELPER_TYPES_H @@ -162,7 +151,7 @@ static inline uint16_t be_to_h_u16(const uint8_t *buf) return (uint16_t)((uint16_t)buf[1] | (uint16_t)buf[0] << 8); } -static inline void h_u64_to_le(uint8_t *buf, int64_t val) +static inline void h_u64_to_le(uint8_t *buf, uint64_t val) { buf[7] = (uint8_t) (val >> 56); buf[6] = (uint8_t) (val >> 48); @@ -174,7 +163,7 @@ static inline void h_u64_to_le(uint8_t *buf, int64_t val) buf[0] = (uint8_t) (val >> 0); } -static inline void h_u64_to_be(uint8_t *buf, int64_t val) +static inline void h_u64_to_be(uint8_t *buf, uint64_t val) { buf[0] = (uint8_t) (val >> 56); buf[1] = (uint8_t) (val >> 48); @@ -186,46 +175,46 @@ static inline void h_u64_to_be(uint8_t *buf, int64_t val) buf[7] = (uint8_t) (val >> 0); } -static inline void h_u32_to_le(uint8_t *buf, int val) +static inline void h_u32_to_le(uint8_t *buf, uint32_t val) { - buf[3] = (uint8_t) (val >> 24); - buf[2] = (uint8_t) (val >> 16); - buf[1] = (uint8_t) (val >> 8); - buf[0] = (uint8_t) (val >> 0); + buf[3] = (val >> 24) & 0xff; + buf[2] = (val >> 16) & 0xff; + buf[1] = (val >> 8) & 0xff; + buf[0] = (val >> 0) & 0xff; } -static inline void h_u32_to_be(uint8_t *buf, int val) +static inline void h_u32_to_be(uint8_t *buf, uint32_t val) { - buf[0] = (uint8_t) (val >> 24); - buf[1] = (uint8_t) (val >> 16); - buf[2] = (uint8_t) (val >> 8); - buf[3] = (uint8_t) (val >> 0); + buf[0] = (val >> 24) & 0xff; + buf[1] = (val >> 16) & 0xff; + buf[2] = (val >> 8) & 0xff; + buf[3] = (val >> 0) & 0xff; } -static inline void h_u24_to_le(uint8_t *buf, int val) +static inline void h_u24_to_le(uint8_t *buf, unsigned int val) { - buf[2] = (uint8_t) (val >> 16); - buf[1] = (uint8_t) (val >> 8); - buf[0] = (uint8_t) (val >> 0); + buf[2] = (val >> 16) & 0xff; + buf[1] = (val >> 8) & 0xff; + buf[0] = (val >> 0) & 0xff; } -static inline void h_u24_to_be(uint8_t *buf, int val) +static inline void h_u24_to_be(uint8_t *buf, unsigned int val) { - buf[0] = (uint8_t) (val >> 16); - buf[1] = (uint8_t) (val >> 8); - buf[2] = (uint8_t) (val >> 0); + buf[0] = (val >> 16) & 0xff; + buf[1] = (val >> 8) & 0xff; + buf[2] = (val >> 0) & 0xff; } -static inline void h_u16_to_le(uint8_t *buf, int val) +static inline void h_u16_to_le(uint8_t *buf, uint16_t val) { - buf[1] = (uint8_t) (val >> 8); - buf[0] = (uint8_t) (val >> 0); + buf[1] = (val >> 8) & 0xff; + buf[0] = (val >> 0) & 0xff; } -static inline void h_u16_to_be(uint8_t *buf, int val) +static inline void h_u16_to_be(uint8_t *buf, uint16_t val) { - buf[0] = (uint8_t) (val >> 8); - buf[1] = (uint8_t) (val >> 0); + buf[0] = (val >> 8) & 0xff; + buf[1] = (val >> 0) & 0xff; } /** diff --git a/src/helper/update_jep106.pl b/src/helper/update_jep106.pl index 561e04b005..60472e3975 100755 --- a/src/helper/update_jep106.pl +++ b/src/helper/update_jep106.pl @@ -1,4 +1,6 @@ #!/usr/bin/perl +# SPDX-License-Identifier: GPL-2.0-or-later + use strict; use warnings; use File::Basename; diff --git a/src/helper/util.c b/src/helper/util.c index be163b26da..2e9f6155ee 100644 --- a/src/helper/util.c +++ b/src/helper/util.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2010 by Øyvind Harboe * - * * - * 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/>. * ***************************************************************************/ /* this file contains various functionality useful to standalone systems */ @@ -23,29 +12,23 @@ #include "log.h" #include "time_support.h" +#include "util.h" -static int jim_util_ms(Jim_Interp *interp, - int argc, - Jim_Obj * const *argv) +COMMAND_HANDLER(handler_util_ms) { - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?"); - return JIM_ERR; - } + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; - /* Cast from 64 to 32 bit int works for 2's-compliment - * when calculating differences*/ - Jim_SetResult(interp, Jim_NewIntObj(interp, (int)timeval_ms())); + command_print(CMD, "%" PRId64, timeval_ms()); - return JIM_OK; + return ERROR_OK; } static const struct command_registration util_command_handlers[] = { - /* jim handlers */ { .name = "ms", .mode = COMMAND_ANY, - .jim_handler = jim_util_ms, + .handler = handler_util_ms, .help = "Returns ever increasing milliseconds. Used to calculate differences in time.", .usage = "", diff --git a/src/helper/util.h b/src/helper/util.h index c9a11ddac5..3ccdc4fdfe 100644 --- a/src/helper/util.h +++ b/src/helper/util.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2010 by Øyvind Harboe * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_HELPER_UTIL_H diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am index 23424f5a2e..7ce4adc295 100644 --- a/src/jtag/Makefile.am +++ b/src/jtag/Makefile.am @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libjtag.la %C%_libjtag_la_LIBADD = @@ -7,11 +9,6 @@ include %D%/hla/Makefile.am %C%_libjtag_la_LIBADD += $(top_builddir)/%D%/hla/libocdhla.la endif -if AICE -include %D%/aice/Makefile.am -%C%_libjtag_la_LIBADD += $(top_builddir)/%D%/aice/libocdaice.la -endif - include %D%/drivers/Makefile.am %C%_libjtag_la_LIBADD += $(top_builddir)/%D%/drivers/libocdjtagdrivers.la diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index 1c34a26c3b..bbf1cb3d2e 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * Copyright (C) 2007-2010 Øyvind Harboe <oyvind.harboe@zylin.com> @@ -32,6 +32,8 @@ enum adapter_clk_mode { CLOCK_MODE_RCLK }; +#define DEFAULT_CLOCK_SPEED_KHZ 100U + /** * Adapter configuration */ @@ -42,13 +44,75 @@ static struct { enum adapter_clk_mode clock_mode; int speed_khz; int rclk_fallback_speed_khz; + struct adapter_gpio_config gpios[ADAPTER_GPIO_IDX_NUM]; + bool gpios_initialized; /* Initialization of GPIOs to their unset values performed at run time */ } adapter_config; +static const struct gpio_map { + const char *name; + enum adapter_gpio_direction direction; + bool permit_drive_option; + bool permit_init_state_option; +} gpio_map[ADAPTER_GPIO_IDX_NUM] = { + [ADAPTER_GPIO_IDX_TDO] = { "tdo", ADAPTER_GPIO_DIRECTION_INPUT, false, true, }, + [ADAPTER_GPIO_IDX_TDI] = { "tdi", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, + [ADAPTER_GPIO_IDX_TMS] = { "tms", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, + [ADAPTER_GPIO_IDX_TCK] = { "tck", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, + [ADAPTER_GPIO_IDX_SWDIO] = { "swdio", ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL, true, true, }, + [ADAPTER_GPIO_IDX_SWDIO_DIR] = { "swdio_dir", ADAPTER_GPIO_DIRECTION_OUTPUT, true, false, }, + [ADAPTER_GPIO_IDX_SWCLK] = { "swclk", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, + [ADAPTER_GPIO_IDX_TRST] = { "trst", ADAPTER_GPIO_DIRECTION_OUTPUT, false, true, }, + [ADAPTER_GPIO_IDX_SRST] = { "srst", ADAPTER_GPIO_DIRECTION_OUTPUT, false, true, }, + [ADAPTER_GPIO_IDX_LED] = { "led", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, +}; + bool is_adapter_initialized(void) { return adapter_config.adapter_initialized; } +/* For convenience of the bit-banging drivers keep the gpio_config drive + * settings for srst and trst in sync with values set by the "adapter + * reset_config" command. + */ +static void sync_adapter_reset_with_gpios(void) +{ + enum reset_types cfg = jtag_get_reset_config(); + if (cfg & RESET_SRST_PUSH_PULL) + adapter_config.gpios[ADAPTER_GPIO_IDX_SRST].drive = ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL; + else + adapter_config.gpios[ADAPTER_GPIO_IDX_SRST].drive = ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN; + if (cfg & RESET_TRST_OPEN_DRAIN) + adapter_config.gpios[ADAPTER_GPIO_IDX_TRST].drive = ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN; + else + adapter_config.gpios[ADAPTER_GPIO_IDX_TRST].drive = ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL; +} + +static void adapter_driver_gpios_init(void) +{ + if (adapter_config.gpios_initialized) + return; + + for (int i = 0; i < ADAPTER_GPIO_IDX_NUM; ++i) { + /* Use ADAPTER_GPIO_NOT_SET as the sentinel 'unset' value. */ + adapter_config.gpios[i].gpio_num = ADAPTER_GPIO_NOT_SET; + adapter_config.gpios[i].chip_num = ADAPTER_GPIO_NOT_SET; + if (gpio_map[i].direction == ADAPTER_GPIO_DIRECTION_INPUT) + adapter_config.gpios[i].init_state = ADAPTER_GPIO_INIT_STATE_INPUT; + } + + /* Drivers assume active low, and this is the normal behaviour for reset + * lines so should be the default. */ + adapter_config.gpios[ADAPTER_GPIO_IDX_SRST].active_low = true; + adapter_config.gpios[ADAPTER_GPIO_IDX_TRST].active_low = true; + sync_adapter_reset_with_gpios(); + + /* JTAG GPIOs should be inactive except for tms */ + adapter_config.gpios[ADAPTER_GPIO_IDX_TMS].init_state = ADAPTER_GPIO_INIT_STATE_ACTIVE; + + adapter_config.gpios_initialized = true; +} + /** * Do low-level setup like initializing registers, output signals, * and clocking. @@ -65,23 +129,33 @@ int adapter_init(struct command_context *cmd_ctx) return ERROR_JTAG_INVALID_INTERFACE; } + adapter_driver_gpios_init(); + int retval; + + /* If the adapter supports configurable speed but the speed is not configured, + * provide a hint to the user. */ + if (adapter_driver->speed && adapter_config.clock_mode == CLOCK_MODE_UNSELECTED) { + LOG_WARNING("An adapter speed is not selected in the init scripts." + " OpenOCD will try to run the adapter at very low speed (%d kHz).", + DEFAULT_CLOCK_SPEED_KHZ); + LOG_WARNING("To remove this warnings and achieve reasonable communication speed with the target," + " set \"adapter speed\" or \"jtag_rclk\" in the init scripts."); + retval = adapter_config_khz(DEFAULT_CLOCK_SPEED_KHZ); + if (retval != ERROR_OK) + return ERROR_JTAG_INIT_FAILED; + } + retval = adapter_driver->init(); if (retval != ERROR_OK) return retval; adapter_config.adapter_initialized = true; if (!adapter_driver->speed) { - LOG_INFO("This adapter doesn't support configurable speed"); + LOG_INFO("Note: The adapter \"%s\" doesn't support configurable speed", adapter_driver->name); return ERROR_OK; } - if (adapter_config.clock_mode == CLOCK_MODE_UNSELECTED) { - LOG_ERROR("An adapter speed is not selected in the init script." - " Insert a call to \"adapter speed\" or \"jtag_rclk\" to proceed."); - return ERROR_JTAG_INIT_FAILED; - } - int requested_khz = adapter_get_speed_khz(); int actual_khz = requested_khz; int speed_var = 0; @@ -301,21 +375,18 @@ bool adapter_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, size_t path return equal; } -static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(handle_adapter_name) { - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc-1, argv + 1); - /* return the name of the interface */ /* TCL code might need to know the exact type... */ /* FUTURE: we allow this as a means to "set" the interface. */ - if (goi.argc != 0) { - Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)"); - return JIM_ERR; - } - const char *name = adapter_driver ? adapter_driver->name : NULL; - Jim_SetResultString(goi.interp, name ? name : "undefined", -1); - return JIM_OK; + + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + command_print(CMD, "%s", adapter_driver ? adapter_driver->name : "undefined"); + + return ERROR_OK; } COMMAND_HANDLER(adapter_transports_command) @@ -528,6 +599,8 @@ COMMAND_HANDLER(handle_reset_config_command) old_cfg &= ~mask; new_cfg |= old_cfg; jtag_set_reset_config(new_cfg); + sync_adapter_reset_with_gpios(); + } else new_cfg = jtag_get_reset_config(); @@ -758,6 +831,219 @@ COMMAND_HANDLER(handle_adapter_reset_de_assert) (srst == VALUE_DEASSERT) ? SRST_DEASSERT : SRST_ASSERT); } +static int get_gpio_index(const char *signal_name) +{ + for (int i = 0; i < ADAPTER_GPIO_IDX_NUM; ++i) { + if (strcmp(gpio_map[i].name, signal_name) == 0) + return i; + } + return -1; +} + +static COMMAND_HELPER(helper_adapter_gpio_print_config, enum adapter_gpio_config_index gpio_idx) +{ + struct adapter_gpio_config *gpio_config = &adapter_config.gpios[gpio_idx]; + const char *active_state = gpio_config->active_low ? "low" : "high"; + const char *dir = ""; + const char *drive = ""; + const char *pull = ""; + const char *init_state = ""; + + if (gpio_config->gpio_num == ADAPTER_GPIO_NOT_SET) { + command_print(CMD, "adapter gpio %s: not configured", gpio_map[gpio_idx].name); + return ERROR_OK; + } + + switch (gpio_map[gpio_idx].direction) { + case ADAPTER_GPIO_DIRECTION_INPUT: + dir = "input"; + break; + case ADAPTER_GPIO_DIRECTION_OUTPUT: + dir = "output"; + break; + case ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL: + dir = "bidirectional"; + break; + } + + if (gpio_map[gpio_idx].permit_drive_option) { + switch (gpio_config->drive) { + case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL: + drive = ", push-pull"; + break; + case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN: + drive = ", open-drain"; + break; + case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE: + drive = ", open-source"; + break; + } + } + + switch (gpio_config->pull) { + case ADAPTER_GPIO_PULL_NONE: + pull = ", pull-none"; + break; + case ADAPTER_GPIO_PULL_UP: + pull = ", pull-up"; + break; + case ADAPTER_GPIO_PULL_DOWN: + pull = ", pull-down"; + break; + } + + if (gpio_map[gpio_idx].permit_init_state_option) { + switch (gpio_config->init_state) { + case ADAPTER_GPIO_INIT_STATE_INACTIVE: + init_state = ", init-state inactive"; + break; + case ADAPTER_GPIO_INIT_STATE_ACTIVE: + init_state = ", init-state active"; + break; + case ADAPTER_GPIO_INIT_STATE_INPUT: + init_state = ", init-state input"; + break; + } + } + + command_print(CMD, "adapter gpio %s (%s): num %u, chip %d, active-%s%s%s%s", + gpio_map[gpio_idx].name, dir, gpio_config->gpio_num, (int)gpio_config->chip_num, active_state, + drive, pull, init_state); + + return ERROR_OK; +} + +COMMAND_HANDLER(helper_adapter_gpio_print_all_configs) +{ + for (int i = 0; i < ADAPTER_GPIO_IDX_NUM; ++i) + CALL_COMMAND_HANDLER(helper_adapter_gpio_print_config, i); + return ERROR_OK; +} + +COMMAND_HANDLER(adapter_gpio_config_handler) +{ + unsigned int i = 1; + struct adapter_gpio_config *gpio_config; + + adapter_driver_gpios_init(); + + if (CMD_ARGC == 0) { + CALL_COMMAND_HANDLER(helper_adapter_gpio_print_all_configs); + return ERROR_OK; + } + + int gpio_idx = get_gpio_index(CMD_ARGV[0]); + if (gpio_idx == -1) { + LOG_ERROR("adapter has no gpio named %s", CMD_ARGV[0]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (CMD_ARGC == 1) { + CALL_COMMAND_HANDLER(helper_adapter_gpio_print_config, gpio_idx); + return ERROR_OK; + } + + gpio_config = &adapter_config.gpios[gpio_idx]; + while (i < CMD_ARGC) { + LOG_DEBUG("Processing %s", CMD_ARGV[i]); + + if (isdigit(*CMD_ARGV[i])) { + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[i], gpio_config->gpio_num); + ++i; + continue; + } + + if (strcmp(CMD_ARGV[i], "-chip") == 0) { + if (CMD_ARGC - i < 2) { + LOG_ERROR("-chip option requires a parameter"); + return ERROR_FAIL; + } + LOG_DEBUG("-chip arg is %s", CMD_ARGV[i + 1]); + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[i + 1], gpio_config->chip_num); + i += 2; + continue; + } + + if (strcmp(CMD_ARGV[i], "-active-high") == 0) { + ++i; + gpio_config->active_low = false; + continue; + } + if (strcmp(CMD_ARGV[i], "-active-low") == 0) { + ++i; + gpio_config->active_low = true; + continue; + } + + if (gpio_map[gpio_idx].permit_drive_option) { + if (strcmp(CMD_ARGV[i], "-push-pull") == 0) { + ++i; + gpio_config->drive = ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL; + continue; + } + if (strcmp(CMD_ARGV[i], "-open-drain") == 0) { + ++i; + gpio_config->drive = ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN; + continue; + } + if (strcmp(CMD_ARGV[i], "-open-source") == 0) { + ++i; + gpio_config->drive = ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE; + continue; + } + } + + if (strcmp(CMD_ARGV[i], "-pull-none") == 0) { + ++i; + gpio_config->pull = ADAPTER_GPIO_PULL_NONE; + continue; + } + if (strcmp(CMD_ARGV[i], "-pull-up") == 0) { + ++i; + gpio_config->pull = ADAPTER_GPIO_PULL_UP; + continue; + } + if (strcmp(CMD_ARGV[i], "-pull-down") == 0) { + ++i; + gpio_config->pull = ADAPTER_GPIO_PULL_DOWN; + continue; + } + + if (gpio_map[gpio_idx].permit_init_state_option) { + if (strcmp(CMD_ARGV[i], "-init-inactive") == 0) { + ++i; + gpio_config->init_state = ADAPTER_GPIO_INIT_STATE_INACTIVE; + continue; + } + if (strcmp(CMD_ARGV[i], "-init-active") == 0) { + ++i; + gpio_config->init_state = ADAPTER_GPIO_INIT_STATE_ACTIVE; + continue; + } + + if (gpio_map[gpio_idx].direction == ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL && + strcmp(CMD_ARGV[i], "-init-input") == 0) { + ++i; + gpio_config->init_state = ADAPTER_GPIO_INIT_STATE_INPUT; + continue; + } + } + + LOG_ERROR("illegal option for adapter %s %s: %s", + CMD_NAME, gpio_map[gpio_idx].name, CMD_ARGV[i]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + /* Force swdio_dir init state to be compatible with swdio init state */ + if (gpio_idx == ADAPTER_GPIO_IDX_SWDIO) + adapter_config.gpios[ADAPTER_GPIO_IDX_SWDIO_DIR].init_state = + (gpio_config->init_state == ADAPTER_GPIO_INIT_STATE_INPUT) ? + ADAPTER_GPIO_INIT_STATE_INACTIVE : + ADAPTER_GPIO_INIT_STATE_ACTIVE; + + return ERROR_OK; +} + #ifdef HAVE_LIBUSB_GET_PORT_NUMBERS COMMAND_HANDLER(handle_usb_location_command) { @@ -836,9 +1122,10 @@ static const struct command_registration adapter_command_handlers[] = { { .name = "name", .mode = COMMAND_ANY, - .jim_handler = jim_adapter_name, + .handler = handle_adapter_name, .help = "Returns the name of the currently " "selected adapter (driver)", + .usage = "", }, { .name = "srst", @@ -875,6 +1162,19 @@ static const struct command_registration adapter_command_handlers[] = { .help = "Controls SRST and TRST lines.", .usage = "|assert [srst|trst [deassert|assert srst|trst]]", }, + { + .name = "gpio", + .handler = adapter_gpio_config_handler, + .mode = COMMAND_CONFIG, + .help = "gpio adapter command group", + .usage = "[ tdo|tdi|tms|tck|trst|swdio|swdio_dir|swclk|srst|led" + "[gpio_number] " + "[-chip chip_number] " + "[-active-high|-active-low] " + "[-push-pull|-open-drain|-open-source] " + "[-pull-none|-pull-up|-pull-down]" + "[-init-inactive|-init-active|-init-input] ]", + }, COMMAND_REGISTRATION_DONE }; @@ -911,3 +1211,14 @@ int adapter_register_commands(struct command_context *ctx) { return register_commands(ctx, NULL, interface_command_handlers); } + +const char *adapter_gpio_get_name(enum adapter_gpio_config_index idx) +{ + return gpio_map[idx].name; +} + +/* Allow drivers access to the GPIO configuration */ +const struct adapter_gpio_config *adapter_gpio_get_config(void) +{ + return adapter_config.gpios; +} diff --git a/src/jtag/adapter.h b/src/jtag/adapter.h index 300769c229..23ffe2cc51 100644 --- a/src/jtag/adapter.h +++ b/src/jtag/adapter.h @@ -10,6 +10,60 @@ #include <stdbool.h> #include <stddef.h> #include <stdint.h> +#include <limits.h> + +/** Supported output drive modes for adaptor GPIO */ +enum adapter_gpio_drive_mode { + ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL, + ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN, + ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE, +}; + +/** Supported GPIO directions */ +enum adapter_gpio_direction { + ADAPTER_GPIO_DIRECTION_INPUT, + ADAPTER_GPIO_DIRECTION_OUTPUT, + ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL, +}; + +/** Supported initial states for GPIO */ +enum adapter_gpio_init_state { + ADAPTER_GPIO_INIT_STATE_INACTIVE, /* Should be zero so it is the default state */ + ADAPTER_GPIO_INIT_STATE_ACTIVE, + ADAPTER_GPIO_INIT_STATE_INPUT, +}; + +/** Supported pull directions for GPIO */ +enum adapter_gpio_pull { + ADAPTER_GPIO_PULL_NONE, + ADAPTER_GPIO_PULL_UP, + ADAPTER_GPIO_PULL_DOWN, +}; + +/** Adapter GPIO */ +enum adapter_gpio_config_index { + ADAPTER_GPIO_IDX_TDO, + ADAPTER_GPIO_IDX_TDI, + ADAPTER_GPIO_IDX_TMS, + ADAPTER_GPIO_IDX_TCK, + ADAPTER_GPIO_IDX_TRST, + ADAPTER_GPIO_IDX_SWDIO, + ADAPTER_GPIO_IDX_SWDIO_DIR, + ADAPTER_GPIO_IDX_SWCLK, + ADAPTER_GPIO_IDX_SRST, + ADAPTER_GPIO_IDX_LED, + ADAPTER_GPIO_IDX_NUM, /* must be the last item */ +}; + +/** Configuration options for a single GPIO */ +struct adapter_gpio_config { + unsigned int gpio_num; + unsigned int chip_num; + enum adapter_gpio_drive_mode drive; /* For outputs only */ + enum adapter_gpio_init_state init_state; + bool active_low; + enum adapter_gpio_pull pull; +}; struct command_context; @@ -58,4 +112,16 @@ unsigned int adapter_get_speed_khz(void); /** Retrieves the serial number set with command 'adapter serial' */ const char *adapter_get_required_serial(void); +/** + * Retrieves gpio name + */ +const char *adapter_gpio_get_name(enum adapter_gpio_config_index idx); + +/** + * Retrieves gpio configuration set with command "adapter gpio <signal_name>" + */ +const struct adapter_gpio_config *adapter_gpio_get_config(void); + +#define ADAPTER_GPIO_NOT_SET UINT_MAX + #endif /* OPENOCD_JTAG_ADAPTER_H */ diff --git a/src/jtag/aice/Makefile.am b/src/jtag/aice/Makefile.am deleted file mode 100644 index b6a7ba9221..0000000000 --- a/src/jtag/aice/Makefile.am +++ /dev/null @@ -1,14 +0,0 @@ -noinst_LTLIBRARIES += %D%/libocdaice.la - -%C%_libocdaice_la_CPPFLAGS = -I$(top_srcdir)/src/jtag/drivers $(AM_CPPFLAGS) $(LIBUSB1_CFLAGS) -%C%_libocdaice_la_SOURCES = \ - %D%/aice_transport.c \ - %D%/aice_interface.c \ - %D%/aice_port.c \ - %D%/aice_usb.c \ - %D%/aice_pipe.c \ - %D%/aice_transport.h \ - %D%/aice_interface.h \ - %D%/aice_port.h \ - %D%/aice_usb.h \ - %D%/aice_pipe.h diff --git a/src/jtag/aice/aice_interface.c b/src/jtag/aice/aice_interface.c deleted file mode 100644 index cb126c6b17..0000000000 --- a/src/jtag/aice/aice_interface.c +++ /dev/null @@ -1,518 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 by Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <jtag/adapter.h> -#include <jtag/interface.h> -#include <jtag/commands.h> -#include <transport/transport.h> -#include <target/target.h> -#include <jtag/aice/aice_transport.h> -#include "aice_usb.h" - -#define AICE_KHZ_TO_SPEED_MAP_SIZE 16 -static const int aice_khz_to_speed_map[AICE_KHZ_TO_SPEED_MAP_SIZE] = { - 30000, - 15000, - 7500, - 3750, - 1875, - 937, - 468, - 234, - 48000, - 24000, - 12000, - 6000, - 3000, - 1500, - 750, - 375, -}; - -static const struct aice_port *aice_port; -static struct aice_port_param_s param; -static uint32_t retry_times; -static uint32_t count_to_check_dbger; - -/***************************************************************************/ -/* External interface implementation */ -static uint32_t aice_target_id_codes[AICE_MAX_NUM_CORE]; -static uint8_t aice_num_of_target_id_codes; - -/***************************************************************************/ -/* AICE operations */ -int aice_init_targets(void) -{ - int res; - struct target *target; - struct aice_port_s *aice; - - LOG_DEBUG("aice_init_targets"); - - if (aice_num_of_target_id_codes == 0) { - res = aice_port->api->idcode(aice_target_id_codes, &aice_num_of_target_id_codes); - if (res != ERROR_OK) { - LOG_ERROR("<-- TARGET ERROR! Failed to identify AndesCore " - "JTAG Manufacture ID in the JTAG scan chain. " - "Failed to access EDM registers. -->"); - return res; - } - } - - for (target = all_targets; target; target = target->next) { - target->tap->idcode = aice_target_id_codes[target->tap->abs_chain_position]; - - unsigned ii, limit = target->tap->expected_ids_cnt; - int found = 0; - - for (ii = 0; ii < limit; ii++) { - uint32_t expected = target->tap->expected_ids[ii]; - - /* treat "-expected-id 0" as a "don't-warn" wildcard */ - if (!expected || (target->tap->idcode == expected)) { - found = 1; - break; - } - } - - if (found == 0) { - LOG_ERROR - ("aice_init_targets: target not found: idcode: %" PRIx32, - target->tap->idcode); - return ERROR_FAIL; - } - - aice = calloc(1, sizeof(struct aice_port_s)); - aice->port = aice_port; - aice->coreid = target->tap->abs_chain_position; - - target->tap->priv = aice; - target->tap->hasidcode = 1; - } - - return ERROR_OK; -} - -/***************************************************************************/ -/* End of External interface implementation */ - -/* initial aice - * 1. open usb - * 2. get/show version number - * 3. reset - */ -static int aice_init(void) -{ - if (aice_port->api->open(¶m) != ERROR_OK) { - LOG_ERROR("Cannot find AICE Interface! Please check " - "connection and permissions."); - return ERROR_JTAG_INIT_FAILED; - } - - aice_port->api->set_retry_times(retry_times); - aice_port->api->set_count_to_check_dbger(count_to_check_dbger); - - LOG_INFO("AICE JTAG Interface ready"); - - return ERROR_OK; -} - -/* cleanup aice resource - * close usb - */ -static int aice_quit(void) -{ - aice_port->api->close(); - return ERROR_OK; -} - -static int aice_execute_reset(struct jtag_command *cmd) -{ - static int last_trst; - int retval = ERROR_OK; - - LOG_DEBUG_IO("reset trst: %d", cmd->cmd.reset->trst); - - if (cmd->cmd.reset->trst != last_trst) { - if (cmd->cmd.reset->trst) - retval = aice_port->api->reset(); - - last_trst = cmd->cmd.reset->trst; - } - - return retval; -} - -static int aice_execute_command(struct jtag_command *cmd) -{ - int retval; - - switch (cmd->type) { - case JTAG_RESET: - retval = aice_execute_reset(cmd); - break; - default: - retval = ERROR_OK; - break; - } - return retval; -} - -/* aice has no need to implement jtag execution model -*/ -static int aice_execute_queue(void) -{ - struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ - int retval; - - retval = ERROR_OK; - - while (cmd) { - if (aice_execute_command(cmd) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - - cmd = cmd->next; - } - - return retval; -} - -/* set jtag frequency(base frequency/frequency divider) to your jtag adapter */ -static int aice_speed(int speed) -{ - return aice_port->api->set_jtag_clock(speed); -} - -/* convert jtag adapter frequency(base frequency/frequency divider) to - * human readable KHz value */ -static int aice_speed_div(int speed, int *khz) -{ - *khz = aice_khz_to_speed_map[speed]; - - return ERROR_OK; -} - -/* convert human readable KHz value to jtag adapter frequency - * (base frequency/frequency divider) */ -static int aice_khz(int khz, int *jtag_speed) -{ - int i; - for (i = 0 ; i < AICE_KHZ_TO_SPEED_MAP_SIZE ; i++) { - if (khz == aice_khz_to_speed_map[i]) { - if (i >= 8) - *jtag_speed = i | AICE_TCK_CONTROL_TCK3048; - else - *jtag_speed = i; - break; - } - } - - if (i == AICE_KHZ_TO_SPEED_MAP_SIZE) { - LOG_INFO("No support the jtag clock: %d", khz); - LOG_INFO("Supported jtag clocks are:"); - - for (i = 0 ; i < AICE_KHZ_TO_SPEED_MAP_SIZE ; i++) - LOG_INFO("* %d", aice_khz_to_speed_map[i]); - - return ERROR_FAIL; - } - - return ERROR_OK; -} - -int aice_scan_jtag_chain(void) -{ - LOG_DEBUG("=== %s ===", __func__); - uint8_t num_of_idcode = 0; - struct target *target; - - int res = aice_port->api->idcode(aice_target_id_codes, &num_of_idcode); - if (res != ERROR_OK) { - LOG_ERROR("<-- TARGET ERROR! Failed to identify AndesCore " - "JTAG Manufacture ID in the JTAG scan chain. " - "Failed to access EDM registers. -->"); - return res; - } - - for (unsigned int i = 0; i < num_of_idcode; i++) - LOG_DEBUG("id_codes[%u] = 0x%" PRIx32, i, aice_target_id_codes[i]); - - /* Update tap idcode */ - for (target = all_targets; target; target = target->next) - target->tap->idcode = aice_target_id_codes[target->tap->abs_chain_position]; - - return ERROR_OK; -} - -/***************************************************************************/ -/* Command handlers */ -COMMAND_HANDLER(aice_handle_aice_info_command) -{ - LOG_DEBUG("aice_handle_aice_info_command"); - - command_print(CMD, "Description: %s", param.device_desc); - command_print(CMD, "Serial number: %s", adapter_get_required_serial()); - if (strncmp(aice_port->name, "aice_pipe", 9) == 0) - command_print(CMD, "Adapter: %s", param.adapter_name); - - return ERROR_OK; -} - -COMMAND_HANDLER(aice_handle_aice_port_command) -{ - LOG_DEBUG("aice_handle_aice_port_command"); - - if (CMD_ARGC != 1) { - LOG_ERROR("Need exactly one argument to 'aice port'"); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - for (const struct aice_port *l = aice_port_get_list(); l->name; l++) { - if (strcmp(l->name, CMD_ARGV[0]) == 0) { - aice_port = l; - return ERROR_OK; - } - } - - LOG_ERROR("No AICE port '%s' found", CMD_ARGV[0]); - return ERROR_FAIL; -} - -COMMAND_HANDLER(aice_handle_aice_desc_command) -{ - LOG_DEBUG("aice_handle_aice_desc_command"); - - if (CMD_ARGC == 1) - param.device_desc = strdup(CMD_ARGV[0]); - else - LOG_ERROR("expected exactly one argument to aice desc <description>"); - - return ERROR_OK; -} - -COMMAND_HANDLER(aice_handle_aice_vid_pid_command) -{ - LOG_DEBUG("aice_handle_aice_vid_pid_command"); - - if (CMD_ARGC != 2) { - LOG_WARNING("ignoring extra IDs in aice vid_pid (maximum is 1 pair)"); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], param.vid); - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], param.pid); - - return ERROR_OK; -} - -COMMAND_HANDLER(aice_handle_aice_adapter_command) -{ - LOG_DEBUG("aice_handle_aice_adapter_command"); - - if (CMD_ARGC == 1) - param.adapter_name = strdup(CMD_ARGV[0]); - else - LOG_ERROR("expected exactly one argument to aice adapter <adapter-name>"); - - return ERROR_OK; -} - -COMMAND_HANDLER(aice_handle_aice_retry_times_command) -{ - LOG_DEBUG("aice_handle_aice_retry_times_command"); - - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], retry_times); - else - LOG_ERROR("expected exactly one argument to aice retry_times <num_of_retry>"); - - return ERROR_OK; -} - -COMMAND_HANDLER(aice_handle_aice_count_to_check_dbger_command) -{ - LOG_DEBUG("aice_handle_aice_count_to_check_dbger_command"); - - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], count_to_check_dbger); - else - LOG_ERROR("expected exactly one argument to aice count_to_check_dbger " - "<count_of_checking>"); - - return ERROR_OK; -} - -COMMAND_HANDLER(aice_handle_aice_custom_srst_script_command) -{ - LOG_DEBUG("aice_handle_aice_custom_srst_script_command"); - - if (CMD_ARGC > 0) { - aice_port->api->set_custom_srst_script(CMD_ARGV[0]); - return ERROR_OK; - } - - return ERROR_FAIL; -} - -COMMAND_HANDLER(aice_handle_aice_custom_trst_script_command) -{ - LOG_DEBUG("aice_handle_aice_custom_trst_script_command"); - - if (CMD_ARGC > 0) { - aice_port->api->set_custom_trst_script(CMD_ARGV[0]); - return ERROR_OK; - } - - return ERROR_FAIL; -} - -COMMAND_HANDLER(aice_handle_aice_custom_restart_script_command) -{ - LOG_DEBUG("aice_handle_aice_custom_restart_script_command"); - - if (CMD_ARGC > 0) { - aice_port->api->set_custom_restart_script(CMD_ARGV[0]); - return ERROR_OK; - } - - return ERROR_FAIL; -} - -COMMAND_HANDLER(aice_handle_aice_reset_command) -{ - LOG_DEBUG("aice_handle_aice_reset_command"); - - return aice_port->api->reset(); -} - - -static const struct command_registration aice_subcommand_handlers[] = { - { - .name = "info", - .handler = &aice_handle_aice_info_command, - .mode = COMMAND_EXEC, - .help = "show aice info", - .usage = "", - }, - { - .name = "port", - .handler = &aice_handle_aice_port_command, - .mode = COMMAND_CONFIG, - .help = "set the port of the AICE", - .usage = "['aice_pipe'|'aice_usb']", - }, - { - .name = "desc", - .handler = &aice_handle_aice_desc_command, - .mode = COMMAND_CONFIG, - .help = "set the aice device description", - .usage = "[description string]", - }, - { - .name = "vid_pid", - .handler = &aice_handle_aice_vid_pid_command, - .mode = COMMAND_CONFIG, - .help = "the vendor and product ID of the AICE device", - .usage = "(vid pid)*", - }, - { - .name = "adapter", - .handler = &aice_handle_aice_adapter_command, - .mode = COMMAND_CONFIG, - .help = "set the file name of adapter", - .usage = "[adapter name]", - }, - { - .name = "retry_times", - .handler = &aice_handle_aice_retry_times_command, - .mode = COMMAND_CONFIG, - .help = "set retry times as AICE timeout", - .usage = "num_of_retry", - }, - { - .name = "count_to_check_dbger", - .handler = &aice_handle_aice_count_to_check_dbger_command, - .mode = COMMAND_CONFIG, - .help = "set retry times as checking $DBGER status", - .usage = "count_of_checking", - }, - { - .name = "custom_srst_script", - .handler = &aice_handle_aice_custom_srst_script_command, - .mode = COMMAND_CONFIG, - .usage = "script_file_name", - .help = "set custom srst script", - }, - { - .name = "custom_trst_script", - .handler = &aice_handle_aice_custom_trst_script_command, - .mode = COMMAND_CONFIG, - .usage = "script_file_name", - .help = "set custom trst script", - }, - { - .name = "custom_restart_script", - .handler = &aice_handle_aice_custom_restart_script_command, - .mode = COMMAND_CONFIG, - .usage = "script_file_name", - .help = "set custom restart script", - }, - { - .name = "reset", - .handler = &aice_handle_aice_reset_command, - .mode = COMMAND_EXEC, - .usage = "", - .help = "reset AICE", - }, - COMMAND_REGISTRATION_DONE -}; - -static const struct command_registration aice_command_handlers[] = { - { - .name = "aice", - .mode = COMMAND_ANY, - .help = "perform aice management", - .usage = "[subcommand]", - .chain = aice_subcommand_handlers, - }, - COMMAND_REGISTRATION_DONE -}; -/***************************************************************************/ -/* End of Command handlers */ - -static struct jtag_interface aice_interface = { - .execute_queue = aice_execute_queue, -}; - -struct adapter_driver aice_adapter_driver = { - .name = "aice", - .transports = aice_transports, - .commands = aice_command_handlers, - - .init = aice_init, - .quit = aice_quit, - .speed = aice_speed, /* set interface speed */ - .khz = aice_khz, /* convert khz to interface speed value */ - .speed_div = aice_speed_div, /* return readable value */ - - .jtag_ops = &aice_interface, -}; diff --git a/src/jtag/aice/aice_interface.h b/src/jtag/aice/aice_interface.h deleted file mode 100644 index 3bddfa342a..0000000000 --- a/src/jtag/aice/aice_interface.h +++ /dev/null @@ -1,25 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 by Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_JTAG_AICE_AICE_INTERFACE_H -#define OPENOCD_JTAG_AICE_AICE_INTERFACE_H - -int aice_init_targets(void); -int aice_scan_jtag_chain(void); - -#endif /* OPENOCD_JTAG_AICE_AICE_INTERFACE_H */ diff --git a/src/jtag/aice/aice_pipe.c b/src/jtag/aice/aice_pipe.c deleted file mode 100644 index e464b8654b..0000000000 --- a/src/jtag/aice/aice_pipe.c +++ /dev/null @@ -1,896 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 by Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <helper/system.h> - -#ifdef _WIN32 -#include <windows.h> -#else -#include <signal.h> -#endif - -#include <helper/log.h> -#include <helper/time_support.h> -#include <helper/system.h> -#include "aice_port.h" -#include "aice_pipe.h" - -#define AICE_PIPE_MAXLINE 8192 - -#ifdef _WIN32 -PROCESS_INFORMATION proc_info; - -static HANDLE aice_pipe_output[2]; -static HANDLE aice_pipe_input[2]; - -static int aice_pipe_write(const void *buffer, int count) -{ - BOOL success; - DWORD written; - - success = WriteFile(aice_pipe_output[1], buffer, count, &written, NULL); - if (!success) { - LOG_ERROR("(WIN32) write to pipe failed, error code: 0x%08l" PRIx32, GetLastError()); - return -1; - } - - return written; -} - -static int aice_pipe_read(void *buffer, int count) -{ - BOOL success; - DWORD has_read; - - success = ReadFile(aice_pipe_input[0], buffer, count, &has_read, NULL); - if (!success || (has_read == 0)) { - LOG_ERROR("(WIN32) read from pipe failed, error code: 0x%08l" PRIx32, GetLastError()); - return -1; - } - - return has_read; -} - -static int aice_pipe_child_init(struct aice_port_param_s *param) -{ - STARTUPINFO start_info; - BOOL success; - - ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION)); - ZeroMemory(&start_info, sizeof(STARTUPINFO)); - start_info.cb = sizeof(STARTUPINFO); - start_info.hStdError = aice_pipe_input[1]; - start_info.hStdOutput = aice_pipe_input[1]; - start_info.hStdInput = aice_pipe_output[0]; - start_info.dwFlags |= STARTF_USESTDHANDLES; - - success = CreateProcess(NULL, - param->adapter_name, - NULL, - NULL, - TRUE, - 0, - NULL, - NULL, - &start_info, - &proc_info); - - if (!success) { - LOG_ERROR("Create new process failed"); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int aice_pipe_parent_init(struct aice_port_param_s *param) -{ - /* send open to adapter */ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_OPEN; - set_u16(command + 1, param->vid); - set_u16(command + 3, param->pid); - - if (aice_pipe_write(command, 5) != 5) { - LOG_ERROR("write failed\n"); - return ERROR_FAIL; - } - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) { - LOG_ERROR("read failed\n"); - return ERROR_FAIL; - } - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; -} - -static int aice_pipe_open(struct aice_port_param_s *param) -{ - SECURITY_ATTRIBUTES attribute; - - attribute.nLength = sizeof(SECURITY_ATTRIBUTES); - attribute.bInheritHandle = TRUE; - attribute.lpSecurityDescriptor = NULL; - - if (!CreatePipe(&aice_pipe_output[0], &aice_pipe_output[1], - &attribute, AICE_PIPE_MAXLINE)) { - LOG_ERROR("Create pipes failed"); - return ERROR_FAIL; - } - if (!CreatePipe(&aice_pipe_input[0], &aice_pipe_input[1], - &attribute, AICE_PIPE_MAXLINE)) { - LOG_ERROR("Create pipes failed"); - return ERROR_FAIL; - } - - /* do not inherit aice_pipe_output[1] & aice_pipe_input[0] to child process */ - if (!SetHandleInformation(aice_pipe_output[1], HANDLE_FLAG_INHERIT, 0)) - return ERROR_FAIL; - if (!SetHandleInformation(aice_pipe_input[0], HANDLE_FLAG_INHERIT, 0)) - return ERROR_FAIL; - - aice_pipe_child_init(param); - - aice_pipe_parent_init(param); - - return ERROR_OK; -} - -#else - -static int aice_pipe_output[2]; -static int aice_pipe_input[2]; - -static int aice_pipe_write(const void *buffer, int count) -{ - if (write(aice_pipe_output[1], buffer, count) != count) { - LOG_ERROR("write to pipe failed"); - return -1; - } - - return count; -} - -static int aice_pipe_read(void *buffer, int count) -{ - int n; - int64_t then, cur; - - then = timeval_ms(); - - while (1) { - n = read(aice_pipe_input[0], buffer, count); - - if ((n == -1) && (errno == EAGAIN)) { - cur = timeval_ms(); - if (cur - then > 500) - keep_alive(); - continue; - } else if (n > 0) - break; - else { - LOG_ERROR("read from pipe failed"); - break; - } - } - - return n; -} - -static int aice_pipe_child_init(struct aice_port_param_s *param) -{ - close(aice_pipe_output[1]); - close(aice_pipe_input[0]); - - if (aice_pipe_output[0] != STDIN_FILENO) { - if (dup2(aice_pipe_output[0], STDIN_FILENO) != STDIN_FILENO) { - LOG_ERROR("Map aice_pipe to STDIN failed"); - return ERROR_FAIL; - } - close(aice_pipe_output[0]); - } - - if (aice_pipe_input[1] != STDOUT_FILENO) { - if (dup2(aice_pipe_input[1], STDOUT_FILENO) != STDOUT_FILENO) { - LOG_ERROR("Map aice_pipe to STDOUT failed"); - return ERROR_FAIL; - } - close(aice_pipe_input[1]); - } - - if (execl(param->adapter_name, param->adapter_name, (char *)0) < 0) { - LOG_ERROR("Execute aice_pipe failed"); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int aice_pipe_parent_init(struct aice_port_param_s *param) -{ - close(aice_pipe_output[0]); - close(aice_pipe_input[1]); - - /* set read end of pipe as non-blocking */ - if (fcntl(aice_pipe_input[0], F_SETFL, O_NONBLOCK)) - return ERROR_FAIL; - - /* send open to adapter */ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_OPEN; - set_u16(command + 1, param->vid); - set_u16(command + 3, param->pid); - - if (aice_pipe_write(command, 5) != 5) { - LOG_ERROR("write failed\n"); - return ERROR_FAIL; - } - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) { - LOG_ERROR("read failed\n"); - return ERROR_FAIL; - } - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; -} - -static void sig_pipe(int signo) -{ - exit(1); -} - -static int aice_pipe_open(struct aice_port_param_s *param) -{ - pid_t pid; - - if (signal(SIGPIPE, sig_pipe) == SIG_ERR) { - LOG_ERROR("Register SIGPIPE handler failed"); - return ERROR_FAIL; - } - - if (pipe(aice_pipe_output) < 0 || pipe(aice_pipe_input) < 0) { - LOG_ERROR("Create pipes failed"); - return ERROR_FAIL; - } - - pid = fork(); - if (pid < 0) { - LOG_ERROR("Fork new process failed"); - return ERROR_FAIL; - } else if (pid == 0) { - if (aice_pipe_child_init(param) != ERROR_OK) { - LOG_ERROR("AICE_PIPE child process initial error"); - return ERROR_FAIL; - } else { - if (aice_pipe_parent_init(param) != ERROR_OK) { - LOG_ERROR("AICE_PIPE parent process initial error"); - return ERROR_FAIL; - } - } - } - - return ERROR_OK; -} -#endif - -static int aice_pipe_close(void) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_CLOSE; - - if (aice_pipe_write(command, 1) != 1) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_OK) { -#ifdef _WIN32 - WaitForSingleObject(proc_info.hProcess, INFINITE); - CloseHandle(proc_info.hProcess); - CloseHandle(proc_info.hThread); -#endif - return ERROR_OK; - } else - return ERROR_FAIL; -} - -static int aice_pipe_idcode(uint32_t *idcode, uint8_t *num_of_idcode) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_IDCODE; - - if (aice_pipe_write(command, 1) != 1) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - *num_of_idcode = line[0]; - - if ((*num_of_idcode == 0) || (*num_of_idcode >= 16)) - return ERROR_FAIL; - - for (int i = 0 ; i < *num_of_idcode ; i++) - idcode[i] = get_u32(line + i * 4 + 1); - - return ERROR_OK; -} - -static int aice_pipe_state(uint32_t coreid, enum aice_target_state_s *state) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_STATE; - - if (aice_pipe_write(command, 1) != 1) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - *state = (enum aice_target_state_s)line[0]; - - return ERROR_OK; -} - -static int aice_pipe_reset(void) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_RESET; - - if (aice_pipe_write(command, 1) != 1) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; -} - -static int aice_pipe_assert_srst(uint32_t coreid, enum aice_srst_type_s srst) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_ASSERT_SRST; - command[1] = srst; - - if (aice_pipe_write(command, 2) != 2) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; -} - -static int aice_pipe_run(uint32_t coreid) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_RUN; - - if (aice_pipe_write(command, 1) != 1) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; -} - -static int aice_pipe_halt(uint32_t coreid) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_HALT; - - if (aice_pipe_write(command, 1) != 1) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; -} - -static int aice_pipe_read_reg(uint32_t coreid, uint32_t num, uint32_t *val) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_READ_REG; - set_u32(command + 1, num); - - if (aice_pipe_write(command, 5) != 5) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - *val = get_u32(line); - - return ERROR_OK; -} - -static int aice_pipe_write_reg(uint32_t coreid, uint32_t num, uint32_t val) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_WRITE_REG; - set_u32(command + 1, num); - set_u32(command + 5, val); - - if (aice_pipe_write(command, 9) != 9) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; -} - -static int aice_pipe_read_reg_64(uint32_t coreid, uint32_t num, uint64_t *val) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_READ_REG_64; - set_u32(command + 1, num); - - if (aice_pipe_write(command, 5) != 5) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - *val = (((uint64_t)get_u32(line + 4)) << 32) | get_u32(line); - - return ERROR_OK; -} - -static int aice_pipe_write_reg_64(uint32_t coreid, uint32_t num, uint64_t val) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_WRITE_REG_64; - set_u32(command + 1, num); - set_u32(command + 5, val & 0xFFFFFFFF); - set_u32(command + 9, (val >> 32) & 0xFFFFFFFF); - - if (aice_pipe_write(command, 13) != 9) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; -} - -static int aice_pipe_step(uint32_t coreid) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_STEP; - - if (aice_pipe_write(command, 1) != 1) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; -} - -static int aice_pipe_read_mem_unit(uint32_t coreid, uint32_t addr, uint32_t size, - uint32_t count, uint8_t *buffer) -{ - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_READ_MEM_UNIT; - set_u32(command + 1, addr); - set_u32(command + 5, size); - set_u32(command + 9, count); - - if (aice_pipe_write(command, 13) != 13) - return ERROR_FAIL; - - if (aice_pipe_read(buffer, size * count) < 0) - return ERROR_FAIL; - - return ERROR_OK; -} - -static int aice_pipe_write_mem_unit(uint32_t coreid, uint32_t addr, uint32_t size, - uint32_t count, const uint8_t *buffer) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_WRITE_MEM_UNIT; - set_u32(command + 1, addr); - set_u32(command + 5, size); - set_u32(command + 9, count); - - /* WRITE_MEM_UNIT|addr|size|count|data */ - memcpy(command + 13, buffer, size * count); - - if (aice_pipe_write(command, 13 + size * count) < 0) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; - - return ERROR_OK; -} - -static int aice_pipe_read_mem_bulk(uint32_t coreid, uint32_t addr, - uint32_t length, uint8_t *buffer) -{ - char line[AICE_PIPE_MAXLINE + 1]; - char command[AICE_PIPE_MAXLINE]; - uint32_t remain_len = length; - uint32_t prepare_len; - char *received_line; - uint32_t received_len; - int read_len; - - command[0] = AICE_READ_MEM_BULK; - set_u32(command + 1, addr); - set_u32(command + 5, length); - - if (aice_pipe_write(command, 9) < 0) - return ERROR_FAIL; - - while (remain_len > 0) { - if (remain_len > AICE_PIPE_MAXLINE) - prepare_len = AICE_PIPE_MAXLINE; - else - prepare_len = remain_len; - - prepare_len++; - received_len = 0; - received_line = line; - do { - read_len = aice_pipe_read(received_line, prepare_len - received_len); - if (read_len < 0) - return ERROR_FAIL; - received_line += read_len; - received_len += read_len; - } while (received_len < prepare_len); - - if (line[0] != AICE_OK) - return ERROR_FAIL; - - prepare_len--; - memcpy(buffer, line + 1, prepare_len); - remain_len -= prepare_len; - buffer += prepare_len; - } - - return ERROR_OK; -} - -static int aice_pipe_write_mem_bulk(uint32_t coreid, uint32_t addr, - uint32_t length, const uint8_t *buffer) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE + 4]; - uint32_t remain_len = length; - uint32_t written_len = 0; - uint32_t write_len; - - command[0] = AICE_WRITE_MEM_BULK; - set_u32(command + 1, addr); - set_u32(command + 5, length); - - /* Send command first */ - if (aice_pipe_write(command, 9) < 0) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_ERROR) - return ERROR_FAIL; - - while (remain_len > 0) { - if (remain_len > AICE_PIPE_MAXLINE) - write_len = AICE_PIPE_MAXLINE; - else - write_len = remain_len; - - set_u32(command, write_len); - memcpy(command + 4, buffer + written_len, write_len); /* data only */ - - if (aice_pipe_write(command, write_len + 4) < 0) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_ERROR) - return ERROR_FAIL; - - remain_len -= write_len; - written_len += write_len; - } - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; -} - -static int aice_pipe_read_debug_reg(uint32_t coreid, uint32_t addr, uint32_t *val) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_READ_DEBUG_REG; - set_u32(command + 1, addr); - - if (aice_pipe_write(command, 5) != 5) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - *val = get_u32(line); - - return ERROR_OK; -} - -static int aice_pipe_write_debug_reg(uint32_t coreid, uint32_t addr, const uint32_t val) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_WRITE_DEBUG_REG; - set_u32(command + 1, addr); - set_u32(command + 5, val); - - if (aice_pipe_write(command, 9) != 9) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; -} - -static int aice_pipe_set_jtag_clock(uint32_t a_clock) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_SET_JTAG_CLOCK; - set_u32(command + 1, a_clock); - - if (aice_pipe_write(command, 5) != 5) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; -} - -static int aice_pipe_memory_access(uint32_t coreid, enum nds_memory_access access_channel) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_MEMORY_ACCESS; - set_u32(command + 1, access_channel); - - if (aice_pipe_write(command, 5) != 5) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; -} - -static int aice_pipe_memory_mode(uint32_t coreid, enum nds_memory_select mem_select) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_MEMORY_MODE; - set_u32(command + 1, mem_select); - - if (aice_pipe_write(command, 5) != 5) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; -} - -static int aice_pipe_read_tlb(uint32_t coreid, target_addr_t virtual_address, - target_addr_t *physical_address) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_READ_TLB; - set_u32(command + 1, virtual_address); - - if (aice_pipe_write(command, 5) != 5) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_OK) { - *physical_address = get_u32(line + 1); - return ERROR_OK; - } else - return ERROR_FAIL; -} - -static int aice_pipe_cache_ctl(uint32_t coreid, uint32_t subtype, uint32_t address) -{ - char line[AICE_PIPE_MAXLINE]; - char command[AICE_PIPE_MAXLINE]; - - command[0] = AICE_CACHE_CTL; - set_u32(command + 1, subtype); - set_u32(command + 5, address); - - if (aice_pipe_write(command, 9) != 9) - return ERROR_FAIL; - - if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) - return ERROR_FAIL; - - if (line[0] == AICE_OK) - return ERROR_OK; - else - return ERROR_FAIL; -} - -static int aice_pipe_set_retry_times(uint32_t a_retry_times) -{ - return ERROR_OK; -} - -/** */ -struct aice_port_api_s aice_pipe = { - /** */ - .open = aice_pipe_open, - /** */ - .close = aice_pipe_close, - /** */ - .idcode = aice_pipe_idcode, - /** */ - .set_jtag_clock = aice_pipe_set_jtag_clock, - /** */ - .state = aice_pipe_state, - /** */ - .reset = aice_pipe_reset, - /** */ - .assert_srst = aice_pipe_assert_srst, - /** */ - .run = aice_pipe_run, - /** */ - .halt = aice_pipe_halt, - /** */ - .step = aice_pipe_step, - /** */ - .read_reg = aice_pipe_read_reg, - /** */ - .write_reg = aice_pipe_write_reg, - /** */ - .read_reg_64 = aice_pipe_read_reg_64, - /** */ - .write_reg_64 = aice_pipe_write_reg_64, - /** */ - .read_mem_unit = aice_pipe_read_mem_unit, - /** */ - .write_mem_unit = aice_pipe_write_mem_unit, - /** */ - .read_mem_bulk = aice_pipe_read_mem_bulk, - /** */ - .write_mem_bulk = aice_pipe_write_mem_bulk, - /** */ - .read_debug_reg = aice_pipe_read_debug_reg, - /** */ - .write_debug_reg = aice_pipe_write_debug_reg, - - /** */ - .memory_access = aice_pipe_memory_access, - /** */ - .memory_mode = aice_pipe_memory_mode, - - /** */ - .read_tlb = aice_pipe_read_tlb, - - /** */ - .cache_ctl = aice_pipe_cache_ctl, - - /** */ - .set_retry_times = aice_pipe_set_retry_times, -}; diff --git a/src/jtag/aice/aice_pipe.h b/src/jtag/aice/aice_pipe.h deleted file mode 100644 index 467ad0ad5a..0000000000 --- a/src/jtag/aice/aice_pipe.h +++ /dev/null @@ -1,31 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 by Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_JTAG_AICE_AICE_PIPE_H -#define OPENOCD_JTAG_AICE_AICE_PIPE_H - -#include <helper/types.h> - -#define set_u32(buffer, value) h_u32_to_le((uint8_t *)buffer, value) -#define set_u16(buffer, value) h_u16_to_le((uint8_t *)buffer, value) -#define get_u32(buffer) le_to_h_u32((const uint8_t *)buffer) -#define get_u16(buffer) le_to_h_u16((const uint8_t *)buffer) - -extern struct aice_port_api_s aice_pipe; - -#endif /* OPENOCD_JTAG_AICE_AICE_PIPE_H */ diff --git a/src/jtag/aice/aice_port.c b/src/jtag/aice/aice_port.c deleted file mode 100644 index 2fa346ca0f..0000000000 --- a/src/jtag/aice/aice_port.c +++ /dev/null @@ -1,45 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 by Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <helper/log.h> -#include "aice_usb.h" -#include "aice_pipe.h" -#include "aice_port.h" - -static const struct aice_port aice_ports[] = { - { - .name = "aice_usb", - .type = AICE_PORT_AICE_USB, - .api = &aice_usb_api, - }, - { - .name = "aice_pipe", - .type = AICE_PORT_AICE_PIPE, - .api = &aice_pipe, - }, - {.name = NULL, /* END OF TABLE */ }, -}; - -/** */ -const struct aice_port *aice_port_get_list(void) -{ - return aice_ports; -} diff --git a/src/jtag/aice/aice_port.h b/src/jtag/aice/aice_port.h deleted file mode 100644 index 159368888e..0000000000 --- a/src/jtag/aice/aice_port.h +++ /dev/null @@ -1,235 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 by Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_JTAG_AICE_AICE_PORT_H -#define OPENOCD_JTAG_AICE_AICE_PORT_H - -#include <target/nds32_edm.h> - -#define AICE_MAX_NUM_CORE (0x10) - -#define ERROR_AICE_DISCONNECT (-200) -#define ERROR_AICE_TIMEOUT (-201) - -enum aice_target_state_s { - AICE_DISCONNECT = 0, - AICE_TARGET_DETACH, - AICE_TARGET_UNKNOWN, - AICE_TARGET_RUNNING, - AICE_TARGET_HALTED, - AICE_TARGET_RESET, - AICE_TARGET_DEBUG_RUNNING, -}; - -enum aice_srst_type_s { - AICE_SRST = 0x1, - AICE_RESET_HOLD = 0x8, -}; - -enum aice_target_endian { - AICE_LITTLE_ENDIAN = 0, - AICE_BIG_ENDIAN, -}; - -enum aice_api_s { - AICE_OPEN = 0x0, - AICE_CLOSE, - AICE_RESET, - AICE_IDCODE, - AICE_SET_JTAG_CLOCK, - AICE_ASSERT_SRST, - AICE_RUN, - AICE_HALT, - AICE_STEP, - AICE_READ_REG, - AICE_WRITE_REG, - AICE_READ_REG_64, - AICE_WRITE_REG_64, - AICE_READ_MEM_UNIT, - AICE_WRITE_MEM_UNIT, - AICE_READ_MEM_BULK, - AICE_WRITE_MEM_BULK, - AICE_READ_DEBUG_REG, - AICE_WRITE_DEBUG_REG, - AICE_STATE, - AICE_MEMORY_ACCESS, - AICE_MEMORY_MODE, - AICE_READ_TLB, - AICE_CACHE_CTL, - AICE_SET_RETRY_TIMES, - AICE_PROGRAM_EDM, - AICE_SET_COMMAND_MODE, - AICE_EXECUTE, - AICE_SET_CUSTOM_SRST_SCRIPT, - AICE_SET_CUSTOM_TRST_SCRIPT, - AICE_SET_CUSTOM_RESTART_SCRIPT, - AICE_SET_COUNT_TO_CHECK_DBGER, - AICE_SET_DATA_ENDIAN, -}; - -enum aice_error_s { - AICE_OK, - AICE_ACK, - AICE_ERROR, -}; - -enum aice_cache_ctl_type { - AICE_CACHE_CTL_L1D_INVALALL = 0, - AICE_CACHE_CTL_L1D_VA_INVAL, - AICE_CACHE_CTL_L1D_WBALL, - AICE_CACHE_CTL_L1D_VA_WB, - AICE_CACHE_CTL_L1I_INVALALL, - AICE_CACHE_CTL_L1I_VA_INVAL, -}; - -enum aice_command_mode { - AICE_COMMAND_MODE_NORMAL, - AICE_COMMAND_MODE_PACK, - AICE_COMMAND_MODE_BATCH, -}; - -struct aice_port_param_s { - /** */ - const char *device_desc; - /** */ - uint16_t vid; - /** */ - uint16_t pid; - /** */ - char *adapter_name; -}; - -struct aice_port_s { - /** */ - uint32_t coreid; - /** */ - const struct aice_port *port; -}; - -/** */ -extern struct aice_port_api_s aice_usb_layout_api; - -/** */ -struct aice_port_api_s { - /** */ - int (*open)(struct aice_port_param_s *param); - /** */ - int (*close)(void); - /** */ - int (*reset)(void); - /** */ - int (*idcode)(uint32_t *idcode, uint8_t *num_of_idcode); - /** */ - int (*set_jtag_clock)(uint32_t a_clock); - /** */ - int (*assert_srst)(uint32_t coreid, enum aice_srst_type_s srst); - /** */ - int (*run)(uint32_t coreid); - /** */ - int (*halt)(uint32_t coreid); - /** */ - int (*step)(uint32_t coreid); - /** */ - int (*read_reg)(uint32_t coreid, uint32_t num, uint32_t *val); - /** */ - int (*write_reg)(uint32_t coreid, uint32_t num, uint32_t val); - /** */ - int (*read_reg_64)(uint32_t coreid, uint32_t num, uint64_t *val); - /** */ - int (*write_reg_64)(uint32_t coreid, uint32_t num, uint64_t val); - /** */ - int (*read_mem_unit)(uint32_t coreid, uint32_t addr, uint32_t size, - uint32_t count, uint8_t *buffer); - /** */ - int (*write_mem_unit)(uint32_t coreid, uint32_t addr, uint32_t size, - uint32_t count, const uint8_t *buffer); - /** */ - int (*read_mem_bulk)(uint32_t coreid, uint32_t addr, uint32_t length, - uint8_t *buffer); - /** */ - int (*write_mem_bulk)(uint32_t coreid, uint32_t addr, uint32_t length, - const uint8_t *buffer); - /** */ - int (*read_debug_reg)(uint32_t coreid, uint32_t addr, uint32_t *val); - /** */ - int (*write_debug_reg)(uint32_t coreid, uint32_t addr, const uint32_t val); - - /** */ - int (*state)(uint32_t coreid, enum aice_target_state_s *state); - - /** */ - int (*memory_access)(uint32_t coreid, enum nds_memory_access a_access); - /** */ - int (*memory_mode)(uint32_t coreid, enum nds_memory_select mem_select); - - /** */ - int (*read_tlb)(uint32_t coreid, target_addr_t virtual_address, target_addr_t *physical_address); - - /** */ - int (*cache_ctl)(uint32_t coreid, uint32_t subtype, uint32_t address); - - /** */ - int (*set_retry_times)(uint32_t a_retry_times); - - /** */ - int (*program_edm)(uint32_t coreid, char *command_sequence); - - /** */ - int (*set_command_mode)(enum aice_command_mode command_mode); - - /** */ - int (*execute)(uint32_t coreid, uint32_t *instructions, uint32_t instruction_num); - - /** */ - int (*set_custom_srst_script)(const char *script); - - /** */ - int (*set_custom_trst_script)(const char *script); - - /** */ - int (*set_custom_restart_script)(const char *script); - - /** */ - int (*set_count_to_check_dbger)(uint32_t count_to_check); - - /** */ - int (*set_data_endian)(uint32_t coreid, enum aice_target_endian target_data_endian); - - /** */ - int (*profiling)(uint32_t coreid, uint32_t interval, uint32_t iteration, - uint32_t reg_no, uint32_t *samples, uint32_t *num_samples); -}; - -#define AICE_PORT_UNKNOWN 0 -#define AICE_PORT_AICE_USB 1 -#define AICE_PORT_AICE_PIPE 2 - -/** */ -struct aice_port { - /** */ - const char *name; - /** */ - int type; - /** */ - struct aice_port_api_s *const api; -}; - -/** */ -const struct aice_port *aice_port_get_list(void); - -#endif /* OPENOCD_JTAG_AICE_AICE_PORT_H */ diff --git a/src/jtag/aice/aice_transport.c b/src/jtag/aice/aice_transport.c deleted file mode 100644 index 2f2542e532..0000000000 --- a/src/jtag/aice/aice_transport.c +++ /dev/null @@ -1,443 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 by Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* project specific includes */ -#include <jtag/interface.h> -#include <jtag/tcl.h> -#include <transport/transport.h> -#include <target/target.h> -#include <jtag/aice/aice_interface.h> -#include <jtag/aice/aice_transport.h> -#include <string.h> - -/* */ -static int jim_newtap_expected_id(struct jim_nvp *n, struct jim_getopt_info *goi, - struct jtag_tap *tap) -{ - jim_wide w; - int e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi->interp, "option: %s bad parameter", - n->name); - return e; - } - - unsigned expected_len = sizeof(uint32_t) * tap->expected_ids_cnt; - uint32_t *new_expected_ids = malloc(expected_len + sizeof(uint32_t)); - if (!new_expected_ids) { - Jim_SetResultFormatted(goi->interp, "no memory"); - return JIM_ERR; - } - - assert(tap->expected_ids); - memcpy(new_expected_ids, tap->expected_ids, expected_len); - - new_expected_ids[tap->expected_ids_cnt] = w; - - free(tap->expected_ids); - tap->expected_ids = new_expected_ids; - tap->expected_ids_cnt++; - - return JIM_OK; -} - -#define NTAP_OPT_EXPECTED_ID 0 - -/* */ -static int jim_aice_newtap_cmd(struct jim_getopt_info *goi) -{ - struct jtag_tap *tap; - int x; - int e; - struct jim_nvp *n; - char *cp; - const struct jim_nvp opts[] = { - {.name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID}, - {.name = NULL, .value = -1}, - }; - - tap = calloc(1, sizeof(struct jtag_tap)); - if (!tap) { - Jim_SetResultFormatted(goi->interp, "no memory"); - return JIM_ERR; - } - - /* - * we expect CHIP + TAP + OPTIONS - * */ - if (goi->argc < 3) { - Jim_SetResultFormatted(goi->interp, - "Missing CHIP TAP OPTIONS ...."); - free(tap); - return JIM_ERR; - } - - const char *tmp; - jim_getopt_string(goi, &tmp, NULL); - tap->chip = strdup(tmp); - - jim_getopt_string(goi, &tmp, NULL); - tap->tapname = strdup(tmp); - - /* name + dot + name + null */ - x = strlen(tap->chip) + 1 + strlen(tap->tapname) + 1; - cp = malloc(x); - sprintf(cp, "%s.%s", tap->chip, tap->tapname); - tap->dotted_name = cp; - - LOG_DEBUG("Creating New Tap, Chip: %s, Tap: %s, Dotted: %s, %d params", - tap->chip, tap->tapname, tap->dotted_name, goi->argc); - - while (goi->argc) { - e = jim_getopt_nvp(goi, opts, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(goi, opts, 0); - free(cp); - free(tap); - return e; - } - LOG_DEBUG("Processing option: %s", n->name); - switch (n->value) { - case NTAP_OPT_EXPECTED_ID: - e = jim_newtap_expected_id(n, goi, tap); - if (e != JIM_OK) { - free(cp); - free(tap); - return e; - } - break; - } /* switch (n->value) */ - } /* while (goi->argc) */ - - /* default is enabled-after-reset */ - tap->enabled = !tap->disabled_after_reset; - - jtag_tap_init(tap); - return JIM_OK; -} - -/* */ -static int jim_aice_newtap(Jim_Interp *interp, int argc, Jim_Obj * const *argv) -{ - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - return jim_aice_newtap_cmd(&goi); -} - -/* */ -COMMAND_HANDLER(handle_aice_init_command) -{ - if (CMD_ARGC != 0) - return ERROR_COMMAND_SYNTAX_ERROR; - - static bool jtag_initialized; - if (jtag_initialized) { - LOG_INFO("'jtag init' has already been called"); - return ERROR_OK; - } - jtag_initialized = true; - - LOG_DEBUG("Initializing jtag devices..."); - return jtag_init(CMD_CTX); -} - -COMMAND_HANDLER(handle_scan_chain_command) -{ - struct jtag_tap *tap; - char expected_id[12]; - - aice_scan_jtag_chain(); - tap = jtag_all_taps(); - command_print(CMD, - " TapName Enabled IdCode Expected IrLen IrCap IrMask"); - command_print(CMD, - "-- ------------------- -------- ---------- ---------- ----- ----- ------"); - - while (tap) { - uint32_t expected, expected_mask, ii; - - snprintf(expected_id, sizeof(expected_id), "0x%08x", - (unsigned)((tap->expected_ids_cnt > 0) - ? tap->expected_ids[0] - : 0)); - if (tap->ignore_version) - expected_id[2] = '*'; - - expected = buf_get_u32(tap->expected, 0, tap->ir_length); - expected_mask = buf_get_u32(tap->expected_mask, 0, tap->ir_length); - - command_print(CMD, - "%2d %-18s %c 0x%08x %s %5d 0x%02x 0x%02x", - tap->abs_chain_position, - tap->dotted_name, - tap->enabled ? 'Y' : 'n', - (unsigned int)(tap->idcode), - expected_id, - (unsigned int)(tap->ir_length), - (unsigned int)(expected), - (unsigned int)(expected_mask)); - - for (ii = 1; ii < tap->expected_ids_cnt; ii++) { - snprintf(expected_id, sizeof(expected_id), "0x%08x", - (unsigned) tap->expected_ids[ii]); - if (tap->ignore_version) - expected_id[2] = '*'; - - command_print(CMD, - " %s", - expected_id); - } - - tap = tap->next_tap; - } - - return ERROR_OK; -} - -static int jim_aice_arp_init(Jim_Interp *interp, int argc, Jim_Obj * const *argv) -{ - LOG_DEBUG("No implement: jim_aice_arp_init"); - - return JIM_OK; -} - -/* */ -static int aice_init_reset(struct command_context *cmd_ctx) -{ - LOG_DEBUG("Initializing with hard TRST+SRST reset"); - - int retval; - enum reset_types jtag_reset_config = jtag_get_reset_config(); - - jtag_add_reset(1, 0); /* TAP_RESET */ - if (jtag_reset_config & RESET_HAS_SRST) { - jtag_add_reset(1, 1); - if ((jtag_reset_config & RESET_SRST_PULLS_TRST) == 0) - jtag_add_reset(0, 1); - } - jtag_add_reset(0, 0); - retval = jtag_execute_queue(); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; -} - -/* */ -static int jim_aice_arp_init_reset(Jim_Interp *interp, int argc, Jim_Obj * const *argv) -{ - int e = ERROR_OK; - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - if (goi.argc != 0) { - Jim_WrongNumArgs(goi.interp, 1, goi.argv - 1, "(no params)"); - return JIM_ERR; - } - struct command_context *context = current_command_context(interp); - e = aice_init_reset(context); - - if (e != ERROR_OK) { - Jim_Obj *obj = Jim_NewIntObj(goi.interp, e); - Jim_SetResultFormatted(goi.interp, "error: %#s", obj); - return JIM_ERR; - } - return JIM_OK; -} - -static int jim_aice_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - if (goi.argc != 0) { - Jim_WrongNumArgs(goi.interp, 1, goi.argv, "Too many parameters"); - return JIM_ERR; - } - Jim_SetResult(goi.interp, Jim_NewListObj(goi.interp, NULL, 0)); - struct jtag_tap *tap; - - for (tap = jtag_all_taps(); tap; tap = tap->next_tap) - Jim_ListAppendElement(goi.interp, - Jim_GetResult(goi.interp), - Jim_NewStringObj(goi.interp, - tap->dotted_name, -1)); - - return JIM_OK; -} - -/* */ -static const struct command_registration aice_transport_jtag_subcommand_handlers[] = { - { - .name = "init", - .mode = COMMAND_ANY, - .handler = handle_aice_init_command, - .help = "initialize jtag scan chain", - .usage = "" - }, - { - .name = "arp_init", - .mode = COMMAND_ANY, - .jim_handler = jim_aice_arp_init, - .help = "Validates JTAG scan chain against the list of " - "declared TAPs.", - }, - { - .name = "arp_init-reset", - .mode = COMMAND_ANY, - .jim_handler = jim_aice_arp_init_reset, - .help = "Uses TRST and SRST to try resetting everything on " - "the JTAG scan chain, then performs 'jtag arp_init'." - }, - { - .name = "newtap", - .mode = COMMAND_CONFIG, - .jim_handler = jim_aice_newtap, - .help = "Create a new TAP instance named basename.tap_type, " - "and appends it to the scan chain.", - .usage = "basename tap_type ['-expected_id' number]" - }, - { - .name = "tapisenabled", - .mode = COMMAND_EXEC, - .jim_handler = jim_jtag_tap_enabler, - .help = "Returns a Tcl boolean (0/1) indicating whether " - "the TAP is enabled (1) or not (0).", - .usage = "tap_name", - }, - { - .name = "tapenable", - .mode = COMMAND_EXEC, - .jim_handler = jim_jtag_tap_enabler, - .help = "Try to enable the specified TAP using the " - "'tap-enable' TAP event.", - .usage = "tap_name", - }, - { - .name = "tapdisable", - .mode = COMMAND_EXEC, - .jim_handler = jim_jtag_tap_enabler, - .help = "Try to disable the specified TAP using the " - "'tap-disable' TAP event.", - .usage = "tap_name", - }, - { - .name = "configure", - .mode = COMMAND_ANY, - .jim_handler = jim_jtag_configure, - .help = "Provide a Tcl handler for the specified " - "TAP event.", - .usage = "tap_name '-event' event_name handler", - }, - { - .name = "cget", - .mode = COMMAND_EXEC, - .jim_handler = jim_jtag_configure, - .help = "Return any Tcl handler for the specified " - "TAP event.", - .usage = "tap_name '-event' event_name", - }, - { - .name = "names", - .mode = COMMAND_ANY, - .jim_handler = jim_aice_names, - .help = "Returns list of all JTAG tap names.", - }, - { - .name = "scan_chain", - .handler = handle_scan_chain_command, - .mode = COMMAND_ANY, - .help = "print current scan chain configuration", - .usage = "" - }, - - COMMAND_REGISTRATION_DONE -}; - -/* */ -static const struct command_registration aice_transport_command_handlers[] = { - { - .name = "jtag", - .mode = COMMAND_ANY, - .usage = "", - .chain = aice_transport_jtag_subcommand_handlers, - }, - COMMAND_REGISTRATION_DONE - -}; - -/* */ -static int aice_transport_register_commands(struct command_context *cmd_ctx) -{ - return register_commands(cmd_ctx, NULL, aice_transport_command_handlers); -} - -/* */ -static int aice_transport_init(struct command_context *cmd_ctx) -{ - LOG_DEBUG("aice_transport_init"); - struct target *t = get_current_target(cmd_ctx); - struct transport *transport; - - if (!t) { - LOG_ERROR("no current target"); - return ERROR_FAIL; - } - - transport = get_current_transport(); - - if (!transport) { - LOG_ERROR("no transport selected"); - return ERROR_FAIL; - } - - LOG_DEBUG("current transport %s", transport->name); - - return aice_init_targets(); -} - -/* */ -static int aice_transport_select(struct command_context *ctx) -{ - LOG_DEBUG("aice_transport_select"); - - int retval; - - retval = aice_transport_register_commands(ctx); - - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; -} - -static struct transport aice_jtag_transport = { - .name = "aice_jtag", - .select = aice_transport_select, - .init = aice_transport_init, -}; - -const char *aice_transports[] = { "aice_jtag", NULL }; - -static void aice_constructor(void) __attribute__((constructor)); -static void aice_constructor(void) -{ - transport_register(&aice_jtag_transport); -} diff --git a/src/jtag/aice/aice_transport.h b/src/jtag/aice/aice_transport.h deleted file mode 100644 index 3af8bc2ee8..0000000000 --- a/src/jtag/aice/aice_transport.h +++ /dev/null @@ -1,24 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 by Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_JTAG_AICE_AICE_TRANSPORT_H -#define OPENOCD_JTAG_AICE_AICE_TRANSPORT_H - -extern const char *aice_transports[]; - -#endif /* OPENOCD_JTAG_AICE_AICE_TRANSPORT_H */ diff --git a/src/jtag/aice/aice_usb.c b/src/jtag/aice/aice_usb.c deleted file mode 100644 index fc46e3722c..0000000000 --- a/src/jtag/aice/aice_usb.c +++ /dev/null @@ -1,4111 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 by Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <helper/system.h> -#include <jtag/drivers/libusb_helper.h> -#include <helper/log.h> -#include <helper/time_support.h> -#include <helper/system.h> -#include <target/target.h> -#include <jtag/jtag.h> -#include <target/nds32_insn.h> -#include <target/nds32_reg.h> -#include "aice_usb.h" - - -/* Global USB buffers */ -static uint8_t usb_in_buffer[AICE_IN_BUFFER_SIZE]; -static uint8_t usb_out_buffer[AICE_OUT_BUFFER_SIZE]; -static uint32_t jtag_clock; -static struct aice_usb_handler_s aice_handler; -/* AICE max retry times. If AICE command timeout, retry it. */ -static int aice_max_retry_times = 50; -/* Default endian is little endian. */ -static enum aice_target_endian data_endian; - -/* Constants for AICE command format length */ -#define AICE_FORMAT_HTDA (3) -#define AICE_FORMAT_HTDC (7) -#define AICE_FORMAT_HTDMA (4) -#define AICE_FORMAT_HTDMB (8) -#define AICE_FORMAT_HTDMC (8) -#define AICE_FORMAT_HTDMD (12) -#define AICE_FORMAT_DTHA (6) -#define AICE_FORMAT_DTHB (2) -#define AICE_FORMAT_DTHMA (8) -#define AICE_FORMAT_DTHMB (4) - -/* Constants for AICE command */ -#define AICE_CMD_SCAN_CHAIN 0x00 -#define AICE_CMD_T_READ_MISC 0x20 -#define AICE_CMD_T_READ_EDMSR 0x21 -#define AICE_CMD_T_READ_DTR 0x22 -#define AICE_CMD_T_READ_MEM_B 0x24 -#define AICE_CMD_T_READ_MEM_H 0x25 -#define AICE_CMD_T_READ_MEM 0x26 -#define AICE_CMD_T_FASTREAD_MEM 0x27 -#define AICE_CMD_T_WRITE_MISC 0x28 -#define AICE_CMD_T_WRITE_EDMSR 0x29 -#define AICE_CMD_T_WRITE_DTR 0x2A -#define AICE_CMD_T_WRITE_DIM 0x2B -#define AICE_CMD_T_WRITE_MEM_B 0x2C -#define AICE_CMD_T_WRITE_MEM_H 0x2D -#define AICE_CMD_T_WRITE_MEM 0x2E -#define AICE_CMD_T_FASTWRITE_MEM 0x2F -#define AICE_CMD_T_EXECUTE 0x3E -#define AICE_CMD_READ_CTRL 0x50 -#define AICE_CMD_WRITE_CTRL 0x51 -#define AICE_CMD_BATCH_BUFFER_READ 0x60 -#define AICE_CMD_READ_DTR_TO_BUFFER 0x61 -#define AICE_CMD_BATCH_BUFFER_WRITE 0x68 -#define AICE_CMD_WRITE_DTR_FROM_BUFFER 0x69 - -/***************************************************************************/ -/* AICE commands' pack/unpack functions */ -static void aice_pack_htda(uint8_t cmd_code, uint8_t extra_word_length, - uint32_t address) -{ - usb_out_buffer[0] = cmd_code; - usb_out_buffer[1] = extra_word_length; - usb_out_buffer[2] = (uint8_t)(address & 0xFF); -} - -static void aice_pack_htdc(uint8_t cmd_code, uint8_t extra_word_length, - uint32_t address, uint32_t word, enum aice_target_endian access_endian) -{ - usb_out_buffer[0] = cmd_code; - usb_out_buffer[1] = extra_word_length; - usb_out_buffer[2] = (uint8_t)(address & 0xFF); - if (access_endian == AICE_BIG_ENDIAN) { - usb_out_buffer[6] = (uint8_t)((word >> 24) & 0xFF); - usb_out_buffer[5] = (uint8_t)((word >> 16) & 0xFF); - usb_out_buffer[4] = (uint8_t)((word >> 8) & 0xFF); - usb_out_buffer[3] = (uint8_t)(word & 0xFF); - } else { - usb_out_buffer[3] = (uint8_t)((word >> 24) & 0xFF); - usb_out_buffer[4] = (uint8_t)((word >> 16) & 0xFF); - usb_out_buffer[5] = (uint8_t)((word >> 8) & 0xFF); - usb_out_buffer[6] = (uint8_t)(word & 0xFF); - } -} - -static void aice_pack_htdma(uint8_t cmd_code, uint8_t target_id, - uint8_t extra_word_length, uint32_t address) -{ - usb_out_buffer[0] = cmd_code; - usb_out_buffer[1] = target_id; - usb_out_buffer[2] = extra_word_length; - usb_out_buffer[3] = (uint8_t)(address & 0xFF); -} - -static void aice_pack_htdmb(uint8_t cmd_code, uint8_t target_id, - uint8_t extra_word_length, uint32_t address) -{ - usb_out_buffer[0] = cmd_code; - usb_out_buffer[1] = target_id; - usb_out_buffer[2] = extra_word_length; - usb_out_buffer[3] = 0; - usb_out_buffer[4] = (uint8_t)((address >> 24) & 0xFF); - usb_out_buffer[5] = (uint8_t)((address >> 16) & 0xFF); - usb_out_buffer[6] = (uint8_t)((address >> 8) & 0xFF); - usb_out_buffer[7] = (uint8_t)(address & 0xFF); -} - -static void aice_pack_htdmc(uint8_t cmd_code, uint8_t target_id, - uint8_t extra_word_length, uint32_t address, uint32_t word, - enum aice_target_endian access_endian) -{ - usb_out_buffer[0] = cmd_code; - usb_out_buffer[1] = target_id; - usb_out_buffer[2] = extra_word_length; - usb_out_buffer[3] = (uint8_t)(address & 0xFF); - if (access_endian == AICE_BIG_ENDIAN) { - usb_out_buffer[7] = (uint8_t)((word >> 24) & 0xFF); - usb_out_buffer[6] = (uint8_t)((word >> 16) & 0xFF); - usb_out_buffer[5] = (uint8_t)((word >> 8) & 0xFF); - usb_out_buffer[4] = (uint8_t)(word & 0xFF); - } else { - usb_out_buffer[4] = (uint8_t)((word >> 24) & 0xFF); - usb_out_buffer[5] = (uint8_t)((word >> 16) & 0xFF); - usb_out_buffer[6] = (uint8_t)((word >> 8) & 0xFF); - usb_out_buffer[7] = (uint8_t)(word & 0xFF); - } -} - -static void aice_pack_htdmc_multiple_data(uint8_t cmd_code, uint8_t target_id, - uint8_t extra_word_length, uint32_t address, uint32_t *word, - uint8_t num_of_words, enum aice_target_endian access_endian) -{ - usb_out_buffer[0] = cmd_code; - usb_out_buffer[1] = target_id; - usb_out_buffer[2] = extra_word_length; - usb_out_buffer[3] = (uint8_t)(address & 0xFF); - - uint8_t i; - for (i = 0 ; i < num_of_words ; i++, word++) { - if (access_endian == AICE_BIG_ENDIAN) { - usb_out_buffer[7 + i * 4] = (uint8_t)((*word >> 24) & 0xFF); - usb_out_buffer[6 + i * 4] = (uint8_t)((*word >> 16) & 0xFF); - usb_out_buffer[5 + i * 4] = (uint8_t)((*word >> 8) & 0xFF); - usb_out_buffer[4 + i * 4] = (uint8_t)(*word & 0xFF); - } else { - usb_out_buffer[4 + i * 4] = (uint8_t)((*word >> 24) & 0xFF); - usb_out_buffer[5 + i * 4] = (uint8_t)((*word >> 16) & 0xFF); - usb_out_buffer[6 + i * 4] = (uint8_t)((*word >> 8) & 0xFF); - usb_out_buffer[7 + i * 4] = (uint8_t)(*word & 0xFF); - } - } -} - -static void aice_pack_htdmd(uint8_t cmd_code, uint8_t target_id, - uint8_t extra_word_length, uint32_t address, uint32_t word, - enum aice_target_endian access_endian) -{ - usb_out_buffer[0] = cmd_code; - usb_out_buffer[1] = target_id; - usb_out_buffer[2] = extra_word_length; - usb_out_buffer[3] = 0; - usb_out_buffer[4] = (uint8_t)((address >> 24) & 0xFF); - usb_out_buffer[5] = (uint8_t)((address >> 16) & 0xFF); - usb_out_buffer[6] = (uint8_t)((address >> 8) & 0xFF); - usb_out_buffer[7] = (uint8_t)(address & 0xFF); - if (access_endian == AICE_BIG_ENDIAN) { - usb_out_buffer[11] = (uint8_t)((word >> 24) & 0xFF); - usb_out_buffer[10] = (uint8_t)((word >> 16) & 0xFF); - usb_out_buffer[9] = (uint8_t)((word >> 8) & 0xFF); - usb_out_buffer[8] = (uint8_t)(word & 0xFF); - } else { - usb_out_buffer[8] = (uint8_t)((word >> 24) & 0xFF); - usb_out_buffer[9] = (uint8_t)((word >> 16) & 0xFF); - usb_out_buffer[10] = (uint8_t)((word >> 8) & 0xFF); - usb_out_buffer[11] = (uint8_t)(word & 0xFF); - } -} - -static void aice_pack_htdmd_multiple_data(uint8_t cmd_code, uint8_t target_id, - uint8_t extra_word_length, uint32_t address, const uint8_t *word, - enum aice_target_endian access_endian) -{ - usb_out_buffer[0] = cmd_code; - usb_out_buffer[1] = target_id; - usb_out_buffer[2] = extra_word_length; - usb_out_buffer[3] = 0; - usb_out_buffer[4] = (uint8_t)((address >> 24) & 0xFF); - usb_out_buffer[5] = (uint8_t)((address >> 16) & 0xFF); - usb_out_buffer[6] = (uint8_t)((address >> 8) & 0xFF); - usb_out_buffer[7] = (uint8_t)(address & 0xFF); - - uint32_t i; - /* num_of_words may be over 0xFF, so use uint32_t */ - uint32_t num_of_words = extra_word_length + 1; - - for (i = 0 ; i < num_of_words ; i++, word += 4) { - if (access_endian == AICE_BIG_ENDIAN) { - usb_out_buffer[11 + i * 4] = word[3]; - usb_out_buffer[10 + i * 4] = word[2]; - usb_out_buffer[9 + i * 4] = word[1]; - usb_out_buffer[8 + i * 4] = word[0]; - } else { - usb_out_buffer[8 + i * 4] = word[3]; - usb_out_buffer[9 + i * 4] = word[2]; - usb_out_buffer[10 + i * 4] = word[1]; - usb_out_buffer[11 + i * 4] = word[0]; - } - } -} - -static void aice_unpack_dtha(uint8_t *cmd_ack_code, uint8_t *extra_word_length, - uint32_t *word, enum aice_target_endian access_endian) -{ - *cmd_ack_code = usb_in_buffer[0]; - *extra_word_length = usb_in_buffer[1]; - - if (access_endian == AICE_BIG_ENDIAN) { - *word = (usb_in_buffer[5] << 24) | - (usb_in_buffer[4] << 16) | - (usb_in_buffer[3] << 8) | - (usb_in_buffer[2]); - } else { - *word = (usb_in_buffer[2] << 24) | - (usb_in_buffer[3] << 16) | - (usb_in_buffer[4] << 8) | - (usb_in_buffer[5]); - } -} - -static void aice_unpack_dtha_multiple_data(uint8_t *cmd_ack_code, - uint8_t *extra_word_length, uint32_t *word, uint8_t num_of_words, - enum aice_target_endian access_endian) -{ - *cmd_ack_code = usb_in_buffer[0]; - *extra_word_length = usb_in_buffer[1]; - - uint8_t i; - for (i = 0 ; i < num_of_words ; i++, word++) { - if (access_endian == AICE_BIG_ENDIAN) { - *word = (usb_in_buffer[5 + i * 4] << 24) | - (usb_in_buffer[4 + i * 4] << 16) | - (usb_in_buffer[3 + i * 4] << 8) | - (usb_in_buffer[2 + i * 4]); - } else { - *word = (usb_in_buffer[2 + i * 4] << 24) | - (usb_in_buffer[3 + i * 4] << 16) | - (usb_in_buffer[4 + i * 4] << 8) | - (usb_in_buffer[5 + i * 4]); - } - } -} - -static void aice_unpack_dthb(uint8_t *cmd_ack_code, uint8_t *extra_word_length) -{ - *cmd_ack_code = usb_in_buffer[0]; - *extra_word_length = usb_in_buffer[1]; -} - -static void aice_unpack_dthma(uint8_t *cmd_ack_code, uint8_t *target_id, - uint8_t *extra_word_length, uint32_t *word, - enum aice_target_endian access_endian) -{ - *cmd_ack_code = usb_in_buffer[0]; - *target_id = usb_in_buffer[1]; - *extra_word_length = usb_in_buffer[2]; - if (access_endian == AICE_BIG_ENDIAN) { - *word = (usb_in_buffer[7] << 24) | - (usb_in_buffer[6] << 16) | - (usb_in_buffer[5] << 8) | - (usb_in_buffer[4]); - } else { - *word = (usb_in_buffer[4] << 24) | - (usb_in_buffer[5] << 16) | - (usb_in_buffer[6] << 8) | - (usb_in_buffer[7]); - } -} - -static void aice_unpack_dthma_multiple_data(uint8_t *cmd_ack_code, - uint8_t *target_id, uint8_t *extra_word_length, uint8_t *word, - enum aice_target_endian access_endian) -{ - *cmd_ack_code = usb_in_buffer[0]; - *target_id = usb_in_buffer[1]; - *extra_word_length = usb_in_buffer[2]; - if (access_endian == AICE_BIG_ENDIAN) { - word[0] = usb_in_buffer[4]; - word[1] = usb_in_buffer[5]; - word[2] = usb_in_buffer[6]; - word[3] = usb_in_buffer[7]; - } else { - word[0] = usb_in_buffer[7]; - word[1] = usb_in_buffer[6]; - word[2] = usb_in_buffer[5]; - word[3] = usb_in_buffer[4]; - } - word += 4; - - uint8_t i; - for (i = 0; i < *extra_word_length; i++) { - if (access_endian == AICE_BIG_ENDIAN) { - word[0] = usb_in_buffer[8 + i * 4]; - word[1] = usb_in_buffer[9 + i * 4]; - word[2] = usb_in_buffer[10 + i * 4]; - word[3] = usb_in_buffer[11 + i * 4]; - } else { - word[0] = usb_in_buffer[11 + i * 4]; - word[1] = usb_in_buffer[10 + i * 4]; - word[2] = usb_in_buffer[9 + i * 4]; - word[3] = usb_in_buffer[8 + i * 4]; - } - word += 4; - } -} - -static void aice_unpack_dthmb(uint8_t *cmd_ack_code, uint8_t *target_id, - uint8_t *extra_word_length) -{ - *cmd_ack_code = usb_in_buffer[0]; - *target_id = usb_in_buffer[1]; - *extra_word_length = usb_in_buffer[2]; -} - -/***************************************************************************/ -/* End of AICE commands' pack/unpack functions */ - -/* calls the given usb_bulk_* function, allowing for the data to - * trickle in with some timeouts */ -static int usb_bulk_with_retries( - int (*f)(struct libusb_device_handle *, int, char *, int, int, int *), - struct libusb_device_handle *dev, int ep, - char *bytes, int size, int timeout, int *transferred) -{ - int tries = 3, count = 0; - - while (tries && (count < size)) { - int result, ret; - - ret = f(dev, ep, bytes + count, size - count, timeout, &result); - if (ret == ERROR_OK) - count += result; - else if ((ret != ERROR_TIMEOUT_REACHED) || !--tries) - return ret; - } - - *transferred = count; - return ERROR_OK; -} - -static int wrap_usb_bulk_write(struct libusb_device_handle *dev, int ep, - char *buff, int size, int timeout, int *transferred) -{ - - /* usb_bulk_write() takes const char *buff */ - jtag_libusb_bulk_write(dev, ep, buff, size, timeout, transferred); - - return 0; -} - -static inline int usb_bulk_write_ex(struct libusb_device_handle *dev, int ep, - char *bytes, int size, int timeout) -{ - int tr = 0; - - usb_bulk_with_retries(&wrap_usb_bulk_write, - dev, ep, bytes, size, timeout, &tr); - return tr; -} - -static inline int usb_bulk_read_ex(struct libusb_device_handle *dev, int ep, - char *bytes, int size, int timeout) -{ - int tr = 0; - usb_bulk_with_retries(&jtag_libusb_bulk_read, - dev, ep, bytes, size, timeout, &tr); - return tr; -} - -/* Write data from out_buffer to USB. */ -static int aice_usb_write(uint8_t *out_buffer, int out_length) -{ - int result; - - if (out_length > AICE_OUT_BUFFER_SIZE) { - LOG_ERROR("aice_write illegal out_length=%i (max=%i)", - out_length, AICE_OUT_BUFFER_SIZE); - return -1; - } - - result = usb_bulk_write_ex(aice_handler.usb_handle, aice_handler.usb_write_ep, - (char *)out_buffer, out_length, AICE_USB_TIMEOUT); - - LOG_DEBUG_IO("aice_usb_write, out_length = %i, result = %i", - out_length, result); - - return result; -} - -/* Read data from USB into in_buffer. */ -static int aice_usb_read(uint8_t *in_buffer, int expected_size) -{ - int result = usb_bulk_read_ex(aice_handler.usb_handle, aice_handler.usb_read_ep, - (char *)in_buffer, expected_size, AICE_USB_TIMEOUT); - - LOG_DEBUG_IO("aice_usb_read, result = %d", result); - - return result; -} - -static uint8_t usb_out_packets_buffer[AICE_OUT_PACKETS_BUFFER_SIZE]; -static uint8_t usb_in_packets_buffer[AICE_IN_PACKETS_BUFFER_SIZE]; -static uint32_t usb_out_packets_buffer_length; -static uint32_t usb_in_packets_buffer_length; -static enum aice_command_mode aice_command_mode; - -static int aice_batch_buffer_write(uint8_t buf_index, const uint8_t *word, - uint32_t num_of_words); - -static int aice_usb_packet_flush(void) -{ - if (usb_out_packets_buffer_length == 0) - return 0; - - if (aice_command_mode == AICE_COMMAND_MODE_PACK) { - LOG_DEBUG("Flush usb packets (AICE_COMMAND_MODE_PACK)"); - - if (aice_usb_write(usb_out_packets_buffer, - usb_out_packets_buffer_length) < 0) - return ERROR_FAIL; - - if (aice_usb_read(usb_in_packets_buffer, - usb_in_packets_buffer_length) < 0) - return ERROR_FAIL; - - usb_out_packets_buffer_length = 0; - usb_in_packets_buffer_length = 0; - - } else if (aice_command_mode == AICE_COMMAND_MODE_BATCH) { - LOG_DEBUG("Flush usb packets (AICE_COMMAND_MODE_BATCH)"); - - /* use BATCH_BUFFER_WRITE to fill command-batch-buffer */ - if (aice_batch_buffer_write(AICE_BATCH_COMMAND_BUFFER_0, - usb_out_packets_buffer, - (usb_out_packets_buffer_length + 3) / 4) != ERROR_OK) - return ERROR_FAIL; - - usb_out_packets_buffer_length = 0; - usb_in_packets_buffer_length = 0; - - /* enable BATCH command */ - aice_command_mode = AICE_COMMAND_MODE_NORMAL; - if (aice_write_ctrl(AICE_WRITE_CTRL_BATCH_CTRL, 0x80000000) != ERROR_OK) - return ERROR_FAIL; - aice_command_mode = AICE_COMMAND_MODE_BATCH; - - /* wait 1 second (AICE bug, workaround) */ - alive_sleep(1000); - - /* check status */ - uint32_t i; - uint32_t batch_status; - - i = 0; - while (1) { - int retval = aice_read_ctrl(AICE_READ_CTRL_BATCH_STATUS, &batch_status); - if (retval != ERROR_OK) - return retval; - - if (batch_status & 0x1) - return ERROR_OK; - else if (batch_status & 0xE) - return ERROR_FAIL; - - if ((i % 30) == 0) - keep_alive(); - - i++; - } - } - - return ERROR_OK; -} - -static int aice_usb_packet_append(uint8_t *out_buffer, int out_length, int in_length) -{ - uint32_t max_packet_size = AICE_OUT_PACKETS_BUFFER_SIZE; - - if (aice_command_mode == AICE_COMMAND_MODE_PACK) { - max_packet_size = AICE_OUT_PACK_COMMAND_SIZE; - } else if (aice_command_mode == AICE_COMMAND_MODE_BATCH) { - max_packet_size = AICE_OUT_BATCH_COMMAND_SIZE; - } else { - /* AICE_COMMAND_MODE_NORMAL */ - if (aice_usb_packet_flush() != ERROR_OK) - return ERROR_FAIL; - } - - if (usb_out_packets_buffer_length + out_length > max_packet_size) - if (aice_usb_packet_flush() != ERROR_OK) { - LOG_DEBUG("Flush usb packets failed"); - return ERROR_FAIL; - } - - LOG_DEBUG("Append usb packets 0x%02x", out_buffer[0]); - - memcpy(usb_out_packets_buffer + usb_out_packets_buffer_length, out_buffer, out_length); - usb_out_packets_buffer_length += out_length; - usb_in_packets_buffer_length += in_length; - - return ERROR_OK; -} - -/***************************************************************************/ -/* AICE commands */ -static int aice_reset_box(void) -{ - if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK) - return ERROR_FAIL; - - /* turn off FASTMODE */ - uint32_t pin_status; - if (aice_read_ctrl(AICE_READ_CTRL_GET_JTAG_PIN_STATUS, &pin_status) - != ERROR_OK) - return ERROR_FAIL; - - if (aice_write_ctrl(AICE_WRITE_CTRL_JTAG_PIN_STATUS, pin_status & (~0x2)) - != ERROR_OK) - return ERROR_FAIL; - - return ERROR_OK; -} - -static int aice_scan_chain(uint32_t *id_codes, uint8_t *num_of_ids) -{ - int retry_times = 0; - - if ((aice_command_mode == AICE_COMMAND_MODE_PACK) || - (aice_command_mode == AICE_COMMAND_MODE_BATCH)) - aice_usb_packet_flush(); - - do { - aice_pack_htda(AICE_CMD_SCAN_CHAIN, 0x0F, 0x0); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDA); - - LOG_DEBUG("SCAN_CHAIN, length: 0x0F"); - - /** TODO: modify receive length */ - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHA); - if (result != AICE_FORMAT_DTHA) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHA, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - aice_unpack_dtha_multiple_data(&cmd_ack_code, num_of_ids, id_codes, - 0x10, AICE_LITTLE_ENDIAN); - - if (cmd_ack_code != AICE_CMD_SCAN_CHAIN) { - - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_SCAN_CHAIN, cmd_ack_code); - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - continue; - } - - LOG_DEBUG("SCAN_CHAIN response, # of IDs: %" PRIu8, *num_of_ids); - - if (*num_of_ids == 0xFF) { - LOG_ERROR("No target connected"); - return ERROR_FAIL; - } else if (*num_of_ids == AICE_MAX_NUM_CORE) { - LOG_INFO("The ice chain over 16 targets"); - } else { - (*num_of_ids)++; - } - break; - } while (1); - - return ERROR_OK; -} - -int aice_read_ctrl(uint32_t address, uint32_t *data) -{ - if ((aice_command_mode == AICE_COMMAND_MODE_PACK) || - (aice_command_mode == AICE_COMMAND_MODE_BATCH)) - aice_usb_packet_flush(); - - aice_pack_htda(AICE_CMD_READ_CTRL, 0, address); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDA); - - LOG_DEBUG("READ_CTRL, address: 0x%" PRIx32, address); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHA); - if (result != AICE_FORMAT_DTHA) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHA, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - aice_unpack_dtha(&cmd_ack_code, &extra_length, data, AICE_LITTLE_ENDIAN); - - LOG_DEBUG("READ_CTRL response, data: 0x%" PRIx32, *data); - - if (cmd_ack_code != AICE_CMD_READ_CTRL) { - LOG_ERROR("aice command error (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_READ_CTRL, cmd_ack_code); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -int aice_write_ctrl(uint32_t address, uint32_t data) -{ - if (aice_command_mode == AICE_COMMAND_MODE_PACK) { - aice_usb_packet_flush(); - } else if (aice_command_mode == AICE_COMMAND_MODE_BATCH) { - aice_pack_htdc(AICE_CMD_WRITE_CTRL, 0, address, data, AICE_LITTLE_ENDIAN); - return aice_usb_packet_append(usb_out_buffer, AICE_FORMAT_HTDC, - AICE_FORMAT_DTHB); - } - - aice_pack_htdc(AICE_CMD_WRITE_CTRL, 0, address, data, AICE_LITTLE_ENDIAN); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDC); - - LOG_DEBUG("WRITE_CTRL, address: 0x%" PRIx32 ", data: 0x%" PRIx32, address, data); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHB); - if (result != AICE_FORMAT_DTHB) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHB, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - aice_unpack_dthb(&cmd_ack_code, &extra_length); - - LOG_DEBUG("WRITE_CTRL response"); - - if (cmd_ack_code != AICE_CMD_WRITE_CTRL) { - LOG_ERROR("aice command error (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_WRITE_CTRL, cmd_ack_code); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int aice_read_dtr(uint8_t target_id, uint32_t *data) -{ - int retry_times = 0; - - if ((aice_command_mode == AICE_COMMAND_MODE_PACK) || - (aice_command_mode == AICE_COMMAND_MODE_BATCH)) - aice_usb_packet_flush(); - - do { - aice_pack_htdma(AICE_CMD_T_READ_DTR, target_id, 0, 0); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMA); - - LOG_DEBUG("READ_DTR, COREID: %" PRIu8, target_id); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMA); - if (result != AICE_FORMAT_DTHMA) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHMA, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthma(&cmd_ack_code, &res_target_id, &extra_length, - data, AICE_LITTLE_ENDIAN); - - if (cmd_ack_code == AICE_CMD_T_READ_DTR) { - LOG_DEBUG("READ_DTR response, data: 0x%" PRIx32, *data); - break; - } else { - - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_READ_DTR, cmd_ack_code); - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -static int aice_read_dtr_to_buffer(uint8_t target_id, uint32_t buffer_idx) -{ - int retry_times = 0; - - if (aice_command_mode == AICE_COMMAND_MODE_PACK) { - aice_usb_packet_flush(); - } else if (aice_command_mode == AICE_COMMAND_MODE_BATCH) { - aice_pack_htdma(AICE_CMD_READ_DTR_TO_BUFFER, target_id, 0, buffer_idx); - return aice_usb_packet_append(usb_out_buffer, AICE_FORMAT_HTDMA, - AICE_FORMAT_DTHMB); - } - - do { - aice_pack_htdma(AICE_CMD_READ_DTR_TO_BUFFER, target_id, 0, buffer_idx); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMA); - - LOG_DEBUG("READ_DTR_TO_BUFFER, COREID: %" PRIu8, target_id); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB); - if (result != AICE_FORMAT_DTHMB) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", AICE_FORMAT_DTHMB, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length); - - if (cmd_ack_code == AICE_CMD_READ_DTR_TO_BUFFER) { - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_READ_DTR_TO_BUFFER, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -static int aice_write_dtr(uint8_t target_id, uint32_t data) -{ - int retry_times = 0; - - if (aice_command_mode == AICE_COMMAND_MODE_PACK) { - aice_usb_packet_flush(); - } else if (aice_command_mode == AICE_COMMAND_MODE_BATCH) { - aice_pack_htdmc(AICE_CMD_T_WRITE_DTR, target_id, 0, 0, data, AICE_LITTLE_ENDIAN); - return aice_usb_packet_append(usb_out_buffer, AICE_FORMAT_HTDMC, - AICE_FORMAT_DTHMB); - } - - do { - aice_pack_htdmc(AICE_CMD_T_WRITE_DTR, target_id, 0, 0, data, AICE_LITTLE_ENDIAN); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMC); - - LOG_DEBUG("WRITE_DTR, COREID: %" PRIu8 ", data: 0x%" PRIx32, target_id, data); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB); - if (result != AICE_FORMAT_DTHMB) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", AICE_FORMAT_DTHMB, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length); - - if (cmd_ack_code == AICE_CMD_T_WRITE_DTR) { - LOG_DEBUG("WRITE_DTR response"); - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_WRITE_DTR, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -static int aice_write_dtr_from_buffer(uint8_t target_id, uint32_t buffer_idx) -{ - int retry_times = 0; - - if (aice_command_mode == AICE_COMMAND_MODE_PACK) { - aice_usb_packet_flush(); - } else if (aice_command_mode == AICE_COMMAND_MODE_BATCH) { - aice_pack_htdma(AICE_CMD_WRITE_DTR_FROM_BUFFER, target_id, 0, buffer_idx); - return aice_usb_packet_append(usb_out_buffer, AICE_FORMAT_HTDMA, - AICE_FORMAT_DTHMB); - } - - do { - aice_pack_htdma(AICE_CMD_WRITE_DTR_FROM_BUFFER, target_id, 0, buffer_idx); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMA); - - LOG_DEBUG("WRITE_DTR_FROM_BUFFER, COREID: %" PRIu8 "", target_id); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB); - if (result != AICE_FORMAT_DTHMB) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", AICE_FORMAT_DTHMB, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length); - - if (cmd_ack_code == AICE_CMD_WRITE_DTR_FROM_BUFFER) { - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_WRITE_DTR_FROM_BUFFER, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -static int aice_read_misc(uint8_t target_id, uint32_t address, uint32_t *data) -{ - int retry_times = 0; - - if ((aice_command_mode == AICE_COMMAND_MODE_PACK) || - (aice_command_mode == AICE_COMMAND_MODE_BATCH)) - aice_usb_packet_flush(); - - do { - aice_pack_htdma(AICE_CMD_T_READ_MISC, target_id, 0, address); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMA); - - LOG_DEBUG("READ_MISC, COREID: %" PRIu8 ", address: 0x%" PRIx32, target_id, address); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMA); - if (result != AICE_FORMAT_DTHMA) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHMA, result); - return ERROR_AICE_DISCONNECT; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthma(&cmd_ack_code, &res_target_id, &extra_length, - data, AICE_LITTLE_ENDIAN); - - if (cmd_ack_code == AICE_CMD_T_READ_MISC) { - LOG_DEBUG("READ_MISC response, data: 0x%" PRIx32, *data); - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_READ_MISC, cmd_ack_code); - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -static int aice_write_misc(uint8_t target_id, uint32_t address, uint32_t data) -{ - int retry_times = 0; - - if (aice_command_mode == AICE_COMMAND_MODE_PACK) { - aice_usb_packet_flush(); - } else if (aice_command_mode == AICE_COMMAND_MODE_BATCH) { - aice_pack_htdmc(AICE_CMD_T_WRITE_MISC, target_id, 0, address, data, - AICE_LITTLE_ENDIAN); - return aice_usb_packet_append(usb_out_buffer, AICE_FORMAT_HTDMC, - AICE_FORMAT_DTHMB); - } - - do { - aice_pack_htdmc(AICE_CMD_T_WRITE_MISC, target_id, 0, address, - data, AICE_LITTLE_ENDIAN); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMC); - - LOG_DEBUG("WRITE_MISC, COREID: %" PRIu8 ", address: 0x%" PRIx32 ", data: 0x%" PRIx32, - target_id, address, data); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB); - if (result != AICE_FORMAT_DTHMB) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHMB, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length); - - if (cmd_ack_code == AICE_CMD_T_WRITE_MISC) { - LOG_DEBUG("WRITE_MISC response"); - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_WRITE_MISC, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -static int aice_read_edmsr(uint8_t target_id, uint32_t address, uint32_t *data) -{ - int retry_times = 0; - - if ((aice_command_mode == AICE_COMMAND_MODE_PACK) || - (aice_command_mode == AICE_COMMAND_MODE_BATCH)) - aice_usb_packet_flush(); - - do { - aice_pack_htdma(AICE_CMD_T_READ_EDMSR, target_id, 0, address); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMA); - - LOG_DEBUG("READ_EDMSR, COREID: %" PRIu8 ", address: 0x%" PRIx32, target_id, address); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMA); - if (result != AICE_FORMAT_DTHMA) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHMA, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthma(&cmd_ack_code, &res_target_id, &extra_length, - data, AICE_LITTLE_ENDIAN); - - if (cmd_ack_code == AICE_CMD_T_READ_EDMSR) { - LOG_DEBUG("READ_EDMSR response, data: 0x%" PRIx32, *data); - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_READ_EDMSR, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -static int aice_write_edmsr(uint8_t target_id, uint32_t address, uint32_t data) -{ - int retry_times = 0; - - if (aice_command_mode == AICE_COMMAND_MODE_PACK) { - aice_usb_packet_flush(); - } else if (aice_command_mode == AICE_COMMAND_MODE_BATCH) { - aice_pack_htdmc(AICE_CMD_T_WRITE_EDMSR, target_id, 0, address, data, - AICE_LITTLE_ENDIAN); - return aice_usb_packet_append(usb_out_buffer, AICE_FORMAT_HTDMC, - AICE_FORMAT_DTHMB); - } - - do { - aice_pack_htdmc(AICE_CMD_T_WRITE_EDMSR, target_id, 0, address, - data, AICE_LITTLE_ENDIAN); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMC); - - LOG_DEBUG("WRITE_EDMSR, COREID: %" PRIu8 ", address: 0x%" PRIx32 ", data: 0x%" PRIx32, - target_id, address, data); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB); - if (result != AICE_FORMAT_DTHMB) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHMB, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length); - - if (cmd_ack_code == AICE_CMD_T_WRITE_EDMSR) { - LOG_DEBUG("WRITE_EDMSR response"); - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_WRITE_EDMSR, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -static int aice_switch_to_big_endian(uint32_t *word, uint8_t num_of_words) -{ - uint32_t tmp; - - for (uint8_t i = 0 ; i < num_of_words ; i++) { - tmp = ((word[i] >> 24) & 0x000000FF) | - ((word[i] >> 8) & 0x0000FF00) | - ((word[i] << 8) & 0x00FF0000) | - ((word[i] << 24) & 0xFF000000); - word[i] = tmp; - } - - return ERROR_OK; -} - -static int aice_write_dim(uint8_t target_id, uint32_t *word, uint8_t num_of_words) -{ - uint32_t big_endian_word[4]; - int retry_times = 0; - - /** instruction is big-endian */ - memcpy(big_endian_word, word, sizeof(big_endian_word)); - aice_switch_to_big_endian(big_endian_word, num_of_words); - - if (aice_command_mode == AICE_COMMAND_MODE_PACK) { - aice_usb_packet_flush(); - } else if (aice_command_mode == AICE_COMMAND_MODE_BATCH) { - aice_pack_htdmc_multiple_data(AICE_CMD_T_WRITE_DIM, target_id, - num_of_words - 1, 0, big_endian_word, num_of_words, - AICE_LITTLE_ENDIAN); - return aice_usb_packet_append(usb_out_buffer, - AICE_FORMAT_HTDMC + (num_of_words - 1) * 4, - AICE_FORMAT_DTHMB); - } - - do { - aice_pack_htdmc_multiple_data(AICE_CMD_T_WRITE_DIM, target_id, num_of_words - 1, 0, - big_endian_word, num_of_words, AICE_LITTLE_ENDIAN); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMC + (num_of_words - 1) * 4); - - LOG_DEBUG("WRITE_DIM, COREID: %" PRIu8 - ", data: 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32, - target_id, - big_endian_word[0], - big_endian_word[1], - big_endian_word[2], - big_endian_word[3]); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB); - if (result != AICE_FORMAT_DTHMB) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", AICE_FORMAT_DTHMB, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length); - - - if (cmd_ack_code == AICE_CMD_T_WRITE_DIM) { - LOG_DEBUG("WRITE_DIM response"); - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_WRITE_DIM, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -static int aice_do_execute(uint8_t target_id) -{ - int retry_times = 0; - - if (aice_command_mode == AICE_COMMAND_MODE_PACK) { - aice_usb_packet_flush(); - } else if (aice_command_mode == AICE_COMMAND_MODE_BATCH) { - aice_pack_htdmc(AICE_CMD_T_EXECUTE, target_id, 0, 0, 0, AICE_LITTLE_ENDIAN); - return aice_usb_packet_append(usb_out_buffer, - AICE_FORMAT_HTDMC, - AICE_FORMAT_DTHMB); - } - - do { - aice_pack_htdmc(AICE_CMD_T_EXECUTE, target_id, 0, 0, 0, AICE_LITTLE_ENDIAN); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMC); - - LOG_DEBUG("EXECUTE, COREID: %" PRIu8 "", target_id); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB); - if (result != AICE_FORMAT_DTHMB) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHMB, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length); - - if (cmd_ack_code == AICE_CMD_T_EXECUTE) { - LOG_DEBUG("EXECUTE response"); - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_EXECUTE, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -static int aice_write_mem_b(uint8_t target_id, uint32_t address, uint32_t data) -{ - int retry_times = 0; - - LOG_DEBUG("WRITE_MEM_B, COREID: %" PRIu8 ", ADDRESS %08" PRIx32 " VALUE %08" PRIx32, - target_id, - address, - data); - - if ((aice_command_mode == AICE_COMMAND_MODE_PACK) || - (aice_command_mode == AICE_COMMAND_MODE_BATCH)) { - aice_pack_htdmd(AICE_CMD_T_WRITE_MEM_B, target_id, 0, address, - data & 0x000000FF, data_endian); - return aice_usb_packet_append(usb_out_buffer, AICE_FORMAT_HTDMD, - AICE_FORMAT_DTHMB); - } else { - do { - aice_pack_htdmd(AICE_CMD_T_WRITE_MEM_B, target_id, 0, - address, data & 0x000000FF, data_endian); - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMD); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB); - if (result != AICE_FORMAT_DTHMB) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", AICE_FORMAT_DTHMB, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length); - - if (cmd_ack_code == AICE_CMD_T_WRITE_MEM_B) { - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_WRITE_MEM_B, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - } - - return ERROR_OK; -} - -static int aice_write_mem_h(uint8_t target_id, uint32_t address, uint32_t data) -{ - int retry_times = 0; - - LOG_DEBUG("WRITE_MEM_H, COREID: %" PRIu8 ", ADDRESS %08" PRIx32 " VALUE %08" PRIx32, - target_id, - address, - data); - - if ((aice_command_mode == AICE_COMMAND_MODE_PACK) || - (aice_command_mode == AICE_COMMAND_MODE_BATCH)) { - aice_pack_htdmd(AICE_CMD_T_WRITE_MEM_H, target_id, 0, - (address >> 1) & 0x7FFFFFFF, data & 0x0000FFFF, data_endian); - return aice_usb_packet_append(usb_out_buffer, AICE_FORMAT_HTDMD, - AICE_FORMAT_DTHMB); - } else { - do { - aice_pack_htdmd(AICE_CMD_T_WRITE_MEM_H, target_id, 0, - (address >> 1) & 0x7FFFFFFF, data & 0x0000FFFF, data_endian); - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMD); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB); - if (result != AICE_FORMAT_DTHMB) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHMB, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length); - - if (cmd_ack_code == AICE_CMD_T_WRITE_MEM_H) { - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_WRITE_MEM_H, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - } - - return ERROR_OK; -} - -static int aice_write_mem(uint8_t target_id, uint32_t address, uint32_t data) -{ - int retry_times = 0; - - LOG_DEBUG("WRITE_MEM, COREID: %" PRIu8 ", ADDRESS %08" PRIx32 " VALUE %08" PRIx32, - target_id, - address, - data); - - if ((aice_command_mode == AICE_COMMAND_MODE_PACK) || - (aice_command_mode == AICE_COMMAND_MODE_BATCH)) { - aice_pack_htdmd(AICE_CMD_T_WRITE_MEM, target_id, 0, - (address >> 2) & 0x3FFFFFFF, data, data_endian); - return aice_usb_packet_append(usb_out_buffer, AICE_FORMAT_HTDMD, - AICE_FORMAT_DTHMB); - } else { - do { - aice_pack_htdmd(AICE_CMD_T_WRITE_MEM, target_id, 0, - (address >> 2) & 0x3FFFFFFF, data, data_endian); - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMD); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB); - if (result != AICE_FORMAT_DTHMB) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHMB, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length); - - if (cmd_ack_code == AICE_CMD_T_WRITE_MEM) { - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_WRITE_MEM, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - } - - return ERROR_OK; -} - -static int aice_fastread_mem(uint8_t target_id, uint8_t *word, uint32_t num_of_words) -{ - int retry_times = 0; - - if ((aice_command_mode == AICE_COMMAND_MODE_PACK) || - (aice_command_mode == AICE_COMMAND_MODE_BATCH)) - aice_usb_packet_flush(); - - do { - aice_pack_htdmb(AICE_CMD_T_FASTREAD_MEM, target_id, num_of_words - 1, 0); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMB); - - LOG_DEBUG("FASTREAD_MEM, COREID: %" PRIu8 ", # of DATA %08" PRIx32, - target_id, num_of_words); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMA + (num_of_words - 1) * 4); - if (result < 0) { - LOG_ERROR("aice_usb_read failed (requested=%" PRIu32 ", result=%d)", - AICE_FORMAT_DTHMA + (num_of_words - 1) * 4, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthma_multiple_data(&cmd_ack_code, &res_target_id, - &extra_length, word, data_endian); - - if (cmd_ack_code == AICE_CMD_T_FASTREAD_MEM) { - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_FASTREAD_MEM, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -static int aice_fastwrite_mem(uint8_t target_id, const uint8_t *word, uint32_t num_of_words) -{ - int retry_times = 0; - - if (aice_command_mode == AICE_COMMAND_MODE_PACK) { - aice_usb_packet_flush(); - } else if (aice_command_mode == AICE_COMMAND_MODE_BATCH) { - aice_pack_htdmd_multiple_data(AICE_CMD_T_FASTWRITE_MEM, target_id, - num_of_words - 1, 0, word, data_endian); - return aice_usb_packet_append(usb_out_buffer, - AICE_FORMAT_HTDMD + (num_of_words - 1) * 4, - AICE_FORMAT_DTHMB); - } - - do { - aice_pack_htdmd_multiple_data(AICE_CMD_T_FASTWRITE_MEM, target_id, - num_of_words - 1, 0, word, data_endian); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMD + (num_of_words - 1) * 4); - - LOG_DEBUG("FASTWRITE_MEM, COREID: %" PRIu8 ", # of DATA %08" PRIx32, - target_id, num_of_words); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB); - if (result != AICE_FORMAT_DTHMB) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHMB, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length); - - if (cmd_ack_code == AICE_CMD_T_FASTWRITE_MEM) { - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_FASTWRITE_MEM, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -static int aice_read_mem_b(uint8_t target_id, uint32_t address, uint32_t *data) -{ - int retry_times = 0; - - if ((aice_command_mode == AICE_COMMAND_MODE_PACK) || - (aice_command_mode == AICE_COMMAND_MODE_BATCH)) - aice_usb_packet_flush(); - - do { - aice_pack_htdmb(AICE_CMD_T_READ_MEM_B, target_id, 0, address); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMB); - - LOG_DEBUG("READ_MEM_B, COREID: %" PRIu8 "", target_id); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMA); - if (result != AICE_FORMAT_DTHMA) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHMA, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthma(&cmd_ack_code, &res_target_id, &extra_length, - data, data_endian); - - if (cmd_ack_code == AICE_CMD_T_READ_MEM_B) { - LOG_DEBUG("READ_MEM_B response, data: 0x%02" PRIx32, *data); - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_READ_MEM_B, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -static int aice_read_mem_h(uint8_t target_id, uint32_t address, uint32_t *data) -{ - int retry_times = 0; - - if ((aice_command_mode == AICE_COMMAND_MODE_PACK) || - (aice_command_mode == AICE_COMMAND_MODE_BATCH)) - aice_usb_packet_flush(); - - do { - aice_pack_htdmb(AICE_CMD_T_READ_MEM_H, target_id, 0, (address >> 1) & 0x7FFFFFFF); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMB); - - LOG_DEBUG("READ_MEM_H, CORE_ID: %" PRIu8 "", target_id); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMA); - if (result != AICE_FORMAT_DTHMA) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHMA, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthma(&cmd_ack_code, &res_target_id, &extra_length, - data, data_endian); - - if (cmd_ack_code == AICE_CMD_T_READ_MEM_H) { - LOG_DEBUG("READ_MEM_H response, data: 0x%" PRIx32, *data); - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_READ_MEM_H, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -static int aice_read_mem(uint8_t target_id, uint32_t address, uint32_t *data) -{ - int retry_times = 0; - - if ((aice_command_mode == AICE_COMMAND_MODE_PACK) || - (aice_command_mode == AICE_COMMAND_MODE_BATCH)) - aice_usb_packet_flush(); - - do { - aice_pack_htdmb(AICE_CMD_T_READ_MEM, target_id, 0, - (address >> 2) & 0x3FFFFFFF); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMB); - - LOG_DEBUG("READ_MEM, COREID: %" PRIu8 "", target_id); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMA); - if (result != AICE_FORMAT_DTHMA) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHMA, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthma(&cmd_ack_code, &res_target_id, &extra_length, - data, data_endian); - - if (cmd_ack_code == AICE_CMD_T_READ_MEM) { - LOG_DEBUG("READ_MEM response, data: 0x%" PRIx32, *data); - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_T_READ_MEM, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -static int aice_batch_buffer_read(uint8_t buf_index, uint32_t *word, uint32_t num_of_words) -{ - int retry_times = 0; - - do { - aice_pack_htdma(AICE_CMD_BATCH_BUFFER_READ, 0, num_of_words - 1, buf_index); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMA); - - LOG_DEBUG("BATCH_BUFFER_READ, # of DATA %08" PRIx32, num_of_words); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMA + (num_of_words - 1) * 4); - if (result < 0) { - LOG_ERROR("aice_usb_read failed (requested=%" PRIu32 ", result=%d)", - AICE_FORMAT_DTHMA + (num_of_words - 1) * 4, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthma_multiple_data(&cmd_ack_code, &res_target_id, - &extra_length, (uint8_t *)word, data_endian); - - if (cmd_ack_code == AICE_CMD_BATCH_BUFFER_READ) { - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_BATCH_BUFFER_READ, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -int aice_batch_buffer_write(uint8_t buf_index, const uint8_t *word, uint32_t num_of_words) -{ - int retry_times = 0; - - if (num_of_words == 0) - return ERROR_OK; - - do { - /* only pack AICE_CMD_BATCH_BUFFER_WRITE command header */ - aice_pack_htdmc(AICE_CMD_BATCH_BUFFER_WRITE, 0, num_of_words - 1, buf_index, - 0, data_endian); - - /* use append instead of pack */ - memcpy(usb_out_buffer + 4, word, num_of_words * 4); - - aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMC + (num_of_words - 1) * 4); - - LOG_DEBUG("BATCH_BUFFER_WRITE, # of DATA %08" PRIx32, num_of_words); - - int result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB); - if (result != AICE_FORMAT_DTHMB) { - LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)", - AICE_FORMAT_DTHMB, result); - return ERROR_FAIL; - } - - uint8_t cmd_ack_code; - uint8_t extra_length; - uint8_t res_target_id; - aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length); - - if (cmd_ack_code == AICE_CMD_BATCH_BUFFER_WRITE) { - break; - } else { - if (retry_times > aice_max_retry_times) { - LOG_ERROR("aice command timeout (command=0x%x, response=0x%" PRIx8 ")", - AICE_CMD_BATCH_BUFFER_WRITE, cmd_ack_code); - - return ERROR_FAIL; - } - - /* clear timeout and retry */ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - retry_times++; - } - } while (1); - - return ERROR_OK; -} - -/***************************************************************************/ -/* End of AICE commands */ - -typedef int (*read_mem_func_t)(uint32_t coreid, uint32_t address, uint32_t *data); -typedef int (*write_mem_func_t)(uint32_t coreid, uint32_t address, uint32_t data); - -static struct aice_nds32_info core_info[AICE_MAX_NUM_CORE]; -static uint8_t total_num_of_core; - -static char *custom_srst_script; -static char *custom_trst_script; -static char *custom_restart_script; -static uint32_t aice_count_to_check_dbger = 30; - -static int aice_read_reg(uint32_t coreid, uint32_t num, uint32_t *val); -static int aice_write_reg(uint32_t coreid, uint32_t num, uint32_t val); - -static int check_suppressed_exception(uint32_t coreid, uint32_t dbger_value) -{ - uint32_t ir4_value = 0; - uint32_t ir6_value = 0; - /* the default value of handling_suppressed_exception is false */ - static bool handling_suppressed_exception; - - if (handling_suppressed_exception) - return ERROR_OK; - - if ((dbger_value & NDS_DBGER_ALL_SUPRS_EX) == NDS_DBGER_ALL_SUPRS_EX) { - LOG_ERROR("<-- TARGET WARNING! Exception is detected and suppressed. -->"); - handling_suppressed_exception = true; - - aice_read_reg(coreid, IR4, &ir4_value); - /* Clear IR6.SUPRS_EXC, IR6.IMP_EXC */ - aice_read_reg(coreid, IR6, &ir6_value); - /* - * For MCU version(MSC_CFG.MCU == 1) like V3m - * | SWID[30:16] | Reserved[15:10] | SUPRS_EXC[9] | IMP_EXC[8] - * |VECTOR[7:5] | INST[4] | Exc Type[3:0] | - * - * For non-MCU version(MSC_CFG.MCU == 0) like V3 - * | SWID[30:16] | Reserved[15:14] | SUPRS_EXC[13] | IMP_EXC[12] - * | VECTOR[11:5] | INST[4] | Exc Type[3:0] | - */ - LOG_INFO("EVA: 0x%08" PRIx32, ir4_value); - LOG_INFO("ITYPE: 0x%08" PRIx32, ir6_value); - - ir6_value = ir6_value & (~0x300); /* for MCU */ - ir6_value = ir6_value & (~0x3000); /* for non-MCU */ - aice_write_reg(coreid, IR6, ir6_value); - - handling_suppressed_exception = false; - } - - return ERROR_OK; -} - -static int check_privilege(uint32_t coreid, uint32_t dbger_value) -{ - if ((dbger_value & NDS_DBGER_ILL_SEC_ACC) == NDS_DBGER_ILL_SEC_ACC) { - LOG_ERROR("<-- TARGET ERROR! Insufficient security privilege " - "to execute the debug operations. -->"); - - /* Clear DBGER.ILL_SEC_ACC */ - if (aice_write_misc(coreid, NDS_EDM_MISC_DBGER, - NDS_DBGER_ILL_SEC_ACC) != ERROR_OK) - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int aice_check_dbger(uint32_t coreid, uint32_t expect_status) -{ - uint32_t i = 0; - uint32_t value_dbger = 0; - - while (1) { - aice_read_misc(coreid, NDS_EDM_MISC_DBGER, &value_dbger); - - if ((value_dbger & expect_status) == expect_status) { - if (check_suppressed_exception(coreid, value_dbger) != ERROR_OK) - return ERROR_FAIL; - if (check_privilege(coreid, value_dbger) != ERROR_OK) - return ERROR_FAIL; - return ERROR_OK; - } - - if ((i % 30) == 0) - keep_alive(); - - int64_t then = 0; - if (i == aice_count_to_check_dbger) - then = timeval_ms(); - if (i >= aice_count_to_check_dbger) { - if ((timeval_ms() - then) > 1000) { - LOG_ERROR("Timeout (1000ms) waiting for $DBGER status " - "being 0x%08" PRIx32, expect_status); - return ERROR_FAIL; - } - } - i++; - } - - return ERROR_FAIL; -} - -static int aice_execute_dim(uint32_t coreid, uint32_t *insts, uint8_t n_inst) -{ - /** fill DIM */ - if (aice_write_dim(coreid, insts, n_inst) != ERROR_OK) - return ERROR_FAIL; - - /** clear DBGER.DPED */ - if (aice_write_misc(coreid, NDS_EDM_MISC_DBGER, NDS_DBGER_DPED) != ERROR_OK) - return ERROR_FAIL; - - /** execute DIM */ - if (aice_do_execute(coreid) != ERROR_OK) - return ERROR_FAIL; - - /** read DBGER.DPED */ - if (aice_check_dbger(coreid, NDS_DBGER_DPED) != ERROR_OK) { - LOG_ERROR("<-- TARGET ERROR! Debug operations do not finish properly: " - "0x%08" PRIx32 "0x%08" PRIx32 "0x%08" PRIx32 "0x%08" PRIx32 ". -->", - insts[0], - insts[1], - insts[2], - insts[3]); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int aice_read_reg(uint32_t coreid, uint32_t num, uint32_t *val) -{ - LOG_DEBUG("aice_read_reg, reg_no: 0x%08" PRIx32, num); - - uint32_t instructions[4]; /** execute instructions in DIM */ - - if (nds32_reg_type(num) == NDS32_REG_TYPE_GPR) { /* general registers */ - instructions[0] = MTSR_DTR(num); - instructions[1] = DSB; - instructions[2] = NOP; - instructions[3] = BEQ_MINUS_12; - } else if (nds32_reg_type(num) == NDS32_REG_TYPE_SPR) { /* user special registers */ - instructions[0] = MFUSR_G0(0, nds32_reg_sr_index(num)); - instructions[1] = MTSR_DTR(0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } else if (nds32_reg_type(num) == NDS32_REG_TYPE_AUMR) { /* audio registers */ - if ((num >= CB_CTL) && (num <= CBE3)) { - instructions[0] = AMFAR2(0, nds32_reg_sr_index(num)); - instructions[1] = MTSR_DTR(0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } else { - instructions[0] = AMFAR(0, nds32_reg_sr_index(num)); - instructions[1] = MTSR_DTR(0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } - } else if (nds32_reg_type(num) == NDS32_REG_TYPE_FPU) { /* fpu registers */ - if (num == FPCSR) { - instructions[0] = FMFCSR; - instructions[1] = MTSR_DTR(0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } else if (num == FPCFG) { - instructions[0] = FMFCFG; - instructions[1] = MTSR_DTR(0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } else { - if (num >= FS0 && num <= FS31) { /* single precision */ - instructions[0] = FMFSR(0, nds32_reg_sr_index(num)); - instructions[1] = MTSR_DTR(0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } else if (num >= FD0 && num <= FD31) { /* double precision */ - instructions[0] = FMFDR(0, nds32_reg_sr_index(num)); - instructions[1] = MTSR_DTR(0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } - } - } else { /* system registers */ - instructions[0] = MFSR(0, nds32_reg_sr_index(num)); - instructions[1] = MTSR_DTR(0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } - - aice_execute_dim(coreid, instructions, 4); - - uint32_t value_edmsw = 0; - aice_read_edmsr(coreid, NDS_EDM_SR_EDMSW, &value_edmsw); - if (value_edmsw & NDS_EDMSW_WDV) - aice_read_dtr(coreid, val); - else { - LOG_ERROR("<-- TARGET ERROR! The debug target failed to update " - "the DTR register. -->"); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int aice_usb_read_reg(uint32_t coreid, uint32_t num, uint32_t *val) -{ - LOG_DEBUG("aice_usb_read_reg"); - - if (num == R0) { - *val = core_info[coreid].r0_backup; - } else if (num == R1) { - *val = core_info[coreid].r1_backup; - } else if (num == DR41) { - /* As target is halted, OpenOCD will backup DR41/DR42/DR43. - * As user wants to read these registers, OpenOCD should return - * the backup values, instead of reading the real values. - * As user wants to write these registers, OpenOCD should write - * to the backup values, instead of writing to real registers. */ - *val = core_info[coreid].edmsw_backup; - } else if (num == DR42) { - *val = core_info[coreid].edm_ctl_backup; - } else if ((core_info[coreid].target_dtr_valid == true) && (num == DR43)) { - *val = core_info[coreid].target_dtr_backup; - } else { - if (aice_read_reg(coreid, num, val) != ERROR_OK) - *val = 0xBBADBEEF; - } - - return ERROR_OK; -} - -static int aice_write_reg(uint32_t coreid, uint32_t num, uint32_t val) -{ - LOG_DEBUG("aice_write_reg, reg_no: 0x%08" PRIx32 ", value: 0x%08" PRIx32, num, val); - - uint32_t instructions[4]; /** execute instructions in DIM */ - uint32_t value_edmsw = 0; - - aice_write_dtr(coreid, val); - aice_read_edmsr(coreid, NDS_EDM_SR_EDMSW, &value_edmsw); - if (0 == (value_edmsw & NDS_EDMSW_RDV)) { - LOG_ERROR("<-- TARGET ERROR! AICE failed to write to the DTR register. -->"); - return ERROR_FAIL; - } - - if (nds32_reg_type(num) == NDS32_REG_TYPE_GPR) { /* general registers */ - instructions[0] = MFSR_DTR(num); - instructions[1] = DSB; - instructions[2] = NOP; - instructions[3] = BEQ_MINUS_12; - } else if (nds32_reg_type(num) == NDS32_REG_TYPE_SPR) { /* user special registers */ - instructions[0] = MFSR_DTR(0); - instructions[1] = MTUSR_G0(0, nds32_reg_sr_index(num)); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } else if (nds32_reg_type(num) == NDS32_REG_TYPE_AUMR) { /* audio registers */ - if ((num >= CB_CTL) && (num <= CBE3)) { - instructions[0] = MFSR_DTR(0); - instructions[1] = AMTAR2(0, nds32_reg_sr_index(num)); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } else { - instructions[0] = MFSR_DTR(0); - instructions[1] = AMTAR(0, nds32_reg_sr_index(num)); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } - } else if (nds32_reg_type(num) == NDS32_REG_TYPE_FPU) { /* fpu registers */ - if (num == FPCSR) { - instructions[0] = MFSR_DTR(0); - instructions[1] = FMTCSR; - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } else if (num == FPCFG) { - /* FPCFG is readonly */ - } else { - if (num >= FS0 && num <= FS31) { /* single precision */ - instructions[0] = MFSR_DTR(0); - instructions[1] = FMTSR(0, nds32_reg_sr_index(num)); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } else if (num >= FD0 && num <= FD31) { /* double precision */ - instructions[0] = MFSR_DTR(0); - instructions[1] = FMTDR(0, nds32_reg_sr_index(num)); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } - } - } else { - instructions[0] = MFSR_DTR(0); - instructions[1] = MTSR(0, nds32_reg_sr_index(num)); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - } - - return aice_execute_dim(coreid, instructions, 4); -} - -static int aice_usb_write_reg(uint32_t coreid, uint32_t num, uint32_t val) -{ - LOG_DEBUG("aice_usb_write_reg"); - - if (num == R0) - core_info[coreid].r0_backup = val; - else if (num == R1) - core_info[coreid].r1_backup = val; - else if (num == DR42) - /* As target is halted, OpenOCD will backup DR41/DR42/DR43. - * As user wants to read these registers, OpenOCD should return - * the backup values, instead of reading the real values. - * As user wants to write these registers, OpenOCD should write - * to the backup values, instead of writing to real registers. */ - core_info[coreid].edm_ctl_backup = val; - else if ((core_info[coreid].target_dtr_valid == true) && (num == DR43)) - core_info[coreid].target_dtr_backup = val; - else - return aice_write_reg(coreid, num, val); - - return ERROR_OK; -} - -static int aice_usb_open(struct aice_port_param_s *param) -{ - const uint16_t vids[] = { param->vid, 0 }; - const uint16_t pids[] = { param->pid, 0 }; - struct libusb_device_handle *devh; - - if (jtag_libusb_open(vids, pids, &devh, NULL) != ERROR_OK) - return ERROR_FAIL; - - /* BE ***VERY CAREFUL*** ABOUT MAKING CHANGES IN THIS - * AREA!!!!!!!!!!! The behavior of libusb is not completely - * consistent across Windows, Linux, and Mac OS X platforms. - * The actions taken in the following compiler conditionals may - * not agree with published documentation for libusb, but were - * found to be necessary through trials and tribulations. Even - * little tweaks can break one or more platforms, so if you do - * make changes test them carefully on all platforms before - * committing them! - */ - -#if IS_WIN32 == 0 - - libusb_reset_device(devh); - -#if IS_DARWIN == 0 - - int timeout = 5; - /* reopen jlink after usb_reset - * on win32 this may take a second or two to re-enumerate */ - int retval; - while ((retval = jtag_libusb_open(vids, pids, &devh, NULL)) != ERROR_OK) { - usleep(1000); - timeout--; - if (!timeout) - break; - } - if (retval != ERROR_OK) - return ERROR_FAIL; -#endif - -#endif - - /* usb_set_configuration required under win32 */ - libusb_set_configuration(devh, 0); - libusb_claim_interface(devh, 0); - - unsigned int aice_read_ep; - unsigned int aice_write_ep; - - jtag_libusb_choose_interface(devh, &aice_read_ep, &aice_write_ep, -1, -1, -1, LIBUSB_TRANSFER_TYPE_BULK); - LOG_DEBUG("aice_read_ep=0x%x, aice_write_ep=0x%x", aice_read_ep, aice_write_ep); - - aice_handler.usb_read_ep = aice_read_ep; - aice_handler.usb_write_ep = aice_write_ep; - aice_handler.usb_handle = devh; - - return ERROR_OK; -} - -static int aice_usb_read_reg_64(uint32_t coreid, uint32_t num, uint64_t *val) -{ - LOG_DEBUG("aice_usb_read_reg_64, %s", nds32_reg_simple_name(num)); - - uint32_t value; - uint32_t high_value; - - if (aice_read_reg(coreid, num, &value) != ERROR_OK) - value = 0xBBADBEEF; - - aice_read_reg(coreid, R1, &high_value); - - LOG_DEBUG("low: 0x%08" PRIx32 ", high: 0x%08" PRIx32 "\n", value, high_value); - - if (data_endian == AICE_BIG_ENDIAN) - *val = (((uint64_t)high_value) << 32) | value; - else - *val = (((uint64_t)value) << 32) | high_value; - - return ERROR_OK; -} - -static int aice_usb_write_reg_64(uint32_t coreid, uint32_t num, uint64_t val) -{ - uint32_t value; - uint32_t high_value; - - if (data_endian == AICE_BIG_ENDIAN) { - value = val & 0xFFFFFFFF; - high_value = (val >> 32) & 0xFFFFFFFF; - } else { - high_value = val & 0xFFFFFFFF; - value = (val >> 32) & 0xFFFFFFFF; - } - - LOG_DEBUG("aice_usb_write_reg_64, %s, low: 0x%08" PRIx32 ", high: 0x%08" PRIx32 "\n", - nds32_reg_simple_name(num), value, high_value); - - aice_write_reg(coreid, R1, high_value); - return aice_write_reg(coreid, num, value); -} - -static int aice_get_version_info(void) -{ - uint32_t hardware_version; - uint32_t firmware_version; - uint32_t fpga_version; - - if (aice_read_ctrl(AICE_READ_CTRL_GET_HARDWARE_VERSION, &hardware_version) != ERROR_OK) - return ERROR_FAIL; - - if (aice_read_ctrl(AICE_READ_CTRL_GET_FIRMWARE_VERSION, &firmware_version) != ERROR_OK) - return ERROR_FAIL; - - if (aice_read_ctrl(AICE_READ_CTRL_GET_FPGA_VERSION, &fpga_version) != ERROR_OK) - return ERROR_FAIL; - - LOG_INFO("AICE version: hw_ver = 0x%" PRIx32 ", fw_ver = 0x%" PRIx32 ", fpga_ver = 0x%" PRIx32, - hardware_version, firmware_version, fpga_version); - - return ERROR_OK; -} - -#define LINE_BUFFER_SIZE 1024 - -static int aice_execute_custom_script(const char *script) -{ - FILE *script_fd; - char line_buffer[LINE_BUFFER_SIZE]; - char *op_str; - char *reset_str; - uint32_t delay; - uint32_t write_ctrl_value; - bool set_op; - - script_fd = fopen(script, "r"); - if (!script_fd) { - return ERROR_FAIL; - } else { - while (fgets(line_buffer, LINE_BUFFER_SIZE, script_fd)) { - /* execute operations */ - set_op = false; - op_str = strstr(line_buffer, "set"); - if (op_str) { - set_op = true; - goto get_reset_type; - } - - op_str = strstr(line_buffer, "clear"); - if (!op_str) - continue; -get_reset_type: - reset_str = strstr(op_str, "srst"); - if (reset_str) { - if (set_op) - write_ctrl_value = AICE_CUSTOM_DELAY_SET_SRST; - else - write_ctrl_value = AICE_CUSTOM_DELAY_CLEAN_SRST; - goto get_delay; - } - reset_str = strstr(op_str, "dbgi"); - if (reset_str) { - if (set_op) - write_ctrl_value = AICE_CUSTOM_DELAY_SET_DBGI; - else - write_ctrl_value = AICE_CUSTOM_DELAY_CLEAN_DBGI; - goto get_delay; - } - reset_str = strstr(op_str, "trst"); - if (reset_str) { - if (set_op) - write_ctrl_value = AICE_CUSTOM_DELAY_SET_TRST; - else - write_ctrl_value = AICE_CUSTOM_DELAY_CLEAN_TRST; - goto get_delay; - } - continue; -get_delay: - /* get delay */ - delay = strtoul(reset_str + 4, NULL, 0); - write_ctrl_value |= (delay << 16); - - if (aice_write_ctrl(AICE_WRITE_CTRL_CUSTOM_DELAY, - write_ctrl_value) != ERROR_OK) { - fclose(script_fd); - return ERROR_FAIL; - } - } - fclose(script_fd); - } - - return ERROR_OK; -} - -static int aice_usb_set_clock(int set_clock) -{ - if (set_clock & AICE_TCK_CONTROL_TCK_SCAN) { - if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL, - AICE_TCK_CONTROL_TCK_SCAN) != ERROR_OK) - return ERROR_FAIL; - - /* Read out TCK_SCAN clock value */ - uint32_t scan_clock; - if (aice_read_ctrl(AICE_READ_CTRL_GET_ICE_STATE, &scan_clock) != ERROR_OK) - return ERROR_FAIL; - - scan_clock &= 0x0F; - - uint32_t scan_base_freq; - if (scan_clock & 0x8) - scan_base_freq = 48000; /* 48 MHz */ - else - scan_base_freq = 30000; /* 30 MHz */ - - uint32_t set_base_freq; - if (set_clock & 0x8) - set_base_freq = 48000; - else - set_base_freq = 30000; - - uint32_t set_freq; - uint32_t scan_freq; - set_freq = set_base_freq >> (set_clock & 0x7); - scan_freq = scan_base_freq >> (scan_clock & 0x7); - - if (scan_freq < set_freq) { - LOG_ERROR("User specifies higher jtag clock than TCK_SCAN clock"); - return ERROR_FAIL; - } - } - - if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL, set_clock) != ERROR_OK) - return ERROR_FAIL; - - uint32_t check_speed; - if (aice_read_ctrl(AICE_READ_CTRL_GET_ICE_STATE, &check_speed) != ERROR_OK) - return ERROR_FAIL; - - if (((int)check_speed & 0x0F) != set_clock) { - LOG_ERROR("Set jtag clock failed"); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int aice_edm_init(uint32_t coreid) -{ - aice_write_edmsr(coreid, NDS_EDM_SR_DIMBR, 0xFFFF0000); - aice_write_misc(coreid, NDS_EDM_MISC_DIMIR, 0); - - /* unconditionally try to turn on V3_EDM_MODE */ - uint32_t edm_ctl_value; - aice_read_edmsr(coreid, NDS_EDM_SR_EDM_CTL, &edm_ctl_value); - aice_write_edmsr(coreid, NDS_EDM_SR_EDM_CTL, edm_ctl_value | 0x00000040); - - /* clear DBGER */ - aice_write_misc(coreid, NDS_EDM_MISC_DBGER, - NDS_DBGER_DPED | NDS_DBGER_CRST | NDS_DBGER_AT_MAX); - - /* get EDM version */ - uint32_t value_edmcfg; - aice_read_edmsr(coreid, NDS_EDM_SR_EDM_CFG, &value_edmcfg); - core_info[coreid].edm_version = (value_edmcfg >> 16) & 0xFFFF; - - return ERROR_OK; -} - -static bool is_v2_edm(uint32_t coreid) -{ - if ((core_info[coreid].edm_version & 0x1000) == 0) - return true; - else - return false; -} - -static int aice_init_edm_registers(uint32_t coreid, bool clear_dex_use_psw) -{ - /* enable DEH_SEL & MAX_STOP & V3_EDM_MODE & DBGI_MASK */ - uint32_t host_edm_ctl = core_info[coreid].edm_ctl_backup | 0xA000004F; - if (clear_dex_use_psw) - /* After entering debug mode, OpenOCD may set - * DEX_USE_PSW accidentally through backup value - * of target EDM_CTL. - * So, clear DEX_USE_PSW by force. */ - host_edm_ctl &= ~(0x40000000); - - LOG_DEBUG("aice_init_edm_registers - EDM_CTL: 0x%08" PRIx32, host_edm_ctl); - - int result = aice_write_edmsr(coreid, NDS_EDM_SR_EDM_CTL, host_edm_ctl); - - return result; -} - -/** - * EDM_CTL will be modified by OpenOCD as debugging. OpenOCD has the - * responsibility to keep EDM_CTL untouched after debugging. - * - * There are two scenarios to consider: - * 1. single step/running as debugging (running under debug session) - * 2. detached from gdb (exit debug session) - * - * So, we need to bakcup EDM_CTL before halted and restore it after - * running. The difference of these two scenarios is EDM_CTL.DEH_SEL - * is on for scenario 1, and off for scenario 2. - */ -static int aice_backup_edm_registers(uint32_t coreid) -{ - int result = aice_read_edmsr(coreid, NDS_EDM_SR_EDM_CTL, - &core_info[coreid].edm_ctl_backup); - - /* To call aice_backup_edm_registers() after DEX on, DEX_USE_PSW - * may be not correct. (For example, hit breakpoint, then backup - * EDM_CTL. EDM_CTL.DEX_USE_PSW will be cleared.) Because debug - * interrupt will clear DEX_USE_PSW, DEX_USE_PSW is always off after - * DEX is on. It only backups correct value before OpenOCD issues DBGI. - * (Backup EDM_CTL, then issue DBGI actively (refer aice_usb_halt())) */ - if (core_info[coreid].edm_ctl_backup & 0x40000000) - core_info[coreid].dex_use_psw_on = true; - else - core_info[coreid].dex_use_psw_on = false; - - LOG_DEBUG("aice_backup_edm_registers - EDM_CTL: 0x%08" PRIx32 ", DEX_USE_PSW: %s", - core_info[coreid].edm_ctl_backup, - core_info[coreid].dex_use_psw_on ? "on" : "off"); - - return result; -} - -static int aice_restore_edm_registers(uint32_t coreid) -{ - LOG_DEBUG("aice_restore_edm_registers -"); - - /* set DEH_SEL, because target still under EDM control */ - int result = aice_write_edmsr(coreid, NDS_EDM_SR_EDM_CTL, - core_info[coreid].edm_ctl_backup | 0x80000000); - - return result; -} - -static int aice_backup_tmp_registers(uint32_t coreid) -{ - LOG_DEBUG("backup_tmp_registers -"); - - /* backup target DTR first(if the target DTR is valid) */ - uint32_t value_edmsw = 0; - aice_read_edmsr(coreid, NDS_EDM_SR_EDMSW, &value_edmsw); - core_info[coreid].edmsw_backup = value_edmsw; - if (value_edmsw & 0x1) { /* EDMSW.WDV == 1 */ - aice_read_dtr(coreid, &core_info[coreid].target_dtr_backup); - core_info[coreid].target_dtr_valid = true; - - LOG_DEBUG("Backup target DTR: 0x%08" PRIx32, core_info[coreid].target_dtr_backup); - } else { - core_info[coreid].target_dtr_valid = false; - } - - /* Target DTR has been backup, then backup $R0 and $R1 */ - aice_read_reg(coreid, R0, &core_info[coreid].r0_backup); - aice_read_reg(coreid, R1, &core_info[coreid].r1_backup); - - /* backup host DTR(if the host DTR is valid) */ - if (value_edmsw & 0x2) { /* EDMSW.RDV == 1*/ - /* read out host DTR and write into target DTR, then use aice_read_edmsr to - * read out */ - uint32_t instructions[4] = { - MFSR_DTR(R0), /* R0 has already been backup */ - DSB, - MTSR_DTR(R0), - BEQ_MINUS_12 - }; - aice_execute_dim(coreid, instructions, 4); - - aice_read_dtr(coreid, &core_info[coreid].host_dtr_backup); - core_info[coreid].host_dtr_valid = true; - - LOG_DEBUG("Backup host DTR: 0x%08" PRIx32, core_info[coreid].host_dtr_backup); - } else { - core_info[coreid].host_dtr_valid = false; - } - - LOG_DEBUG("r0: 0x%08" PRIx32 ", r1: 0x%08" PRIx32, - core_info[coreid].r0_backup, core_info[coreid].r1_backup); - - return ERROR_OK; -} - -static int aice_restore_tmp_registers(uint32_t coreid) -{ - LOG_DEBUG("restore_tmp_registers - r0: 0x%08" PRIx32 ", r1: 0x%08" PRIx32, - core_info[coreid].r0_backup, core_info[coreid].r1_backup); - - if (core_info[coreid].target_dtr_valid) { - uint32_t instructions[4] = { - SETHI(R0, core_info[coreid].target_dtr_backup >> 12), - ORI(R0, R0, core_info[coreid].target_dtr_backup & 0x00000FFF), - NOP, - BEQ_MINUS_12 - }; - aice_execute_dim(coreid, instructions, 4); - - instructions[0] = MTSR_DTR(R0); - instructions[1] = DSB; - instructions[2] = NOP; - instructions[3] = BEQ_MINUS_12; - aice_execute_dim(coreid, instructions, 4); - - LOG_DEBUG("Restore target DTR: 0x%08" PRIx32, core_info[coreid].target_dtr_backup); - } - - aice_write_reg(coreid, R0, core_info[coreid].r0_backup); - aice_write_reg(coreid, R1, core_info[coreid].r1_backup); - - if (core_info[coreid].host_dtr_valid) { - aice_write_dtr(coreid, core_info[coreid].host_dtr_backup); - - LOG_DEBUG("Restore host DTR: 0x%08" PRIx32, core_info[coreid].host_dtr_backup); - } - - return ERROR_OK; -} - -static int aice_open_device(struct aice_port_param_s *param) -{ - if (aice_usb_open(param) != ERROR_OK) - return ERROR_FAIL; - - if (aice_get_version_info() == ERROR_FAIL) { - LOG_ERROR("Cannot get AICE version!"); - return ERROR_FAIL; - } - - LOG_INFO("AICE initialization started"); - - /* attempt to reset Andes EDM */ - if (aice_reset_box() == ERROR_FAIL) { - LOG_ERROR("Cannot initial AICE box!"); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int aice_usb_set_jtag_clock(uint32_t a_clock) -{ - jtag_clock = a_clock; - - if (aice_usb_set_clock(a_clock) != ERROR_OK) { - LOG_ERROR("Cannot set AICE JTAG clock!"); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int aice_usb_close(void) -{ - jtag_libusb_close(aice_handler.usb_handle); - - free(custom_srst_script); - free(custom_trst_script); - free(custom_restart_script); - return ERROR_OK; -} - -static int aice_core_init(uint32_t coreid) -{ - core_info[coreid].access_channel = NDS_MEMORY_ACC_CPU; - core_info[coreid].memory_select = NDS_MEMORY_SELECT_AUTO; - core_info[coreid].core_state = AICE_TARGET_UNKNOWN; - - return ERROR_OK; -} - -static int aice_usb_idcode(uint32_t *idcode, uint8_t *num_of_idcode) -{ - int retval; - - retval = aice_scan_chain(idcode, num_of_idcode); - if (retval == ERROR_OK) { - for (int i = 0; i < *num_of_idcode; i++) { - aice_core_init(i); - aice_edm_init(i); - } - total_num_of_core = *num_of_idcode; - } - - return retval; -} - -static int aice_usb_halt(uint32_t coreid) -{ - if (core_info[coreid].core_state == AICE_TARGET_HALTED) { - LOG_DEBUG("aice_usb_halt check halted"); - return ERROR_OK; - } - - LOG_DEBUG("aice_usb_halt"); - - /** backup EDM registers */ - aice_backup_edm_registers(coreid); - /** init EDM for host debugging */ - /** no need to clear dex_use_psw, because dbgi will clear it */ - aice_init_edm_registers(coreid, false); - - /** Clear EDM_CTL.DBGIM & EDM_CTL.DBGACKM */ - uint32_t edm_ctl_value = 0; - aice_read_edmsr(coreid, NDS_EDM_SR_EDM_CTL, &edm_ctl_value); - if (edm_ctl_value & 0x3) - aice_write_edmsr(coreid, NDS_EDM_SR_EDM_CTL, edm_ctl_value & ~(0x3)); - - uint32_t dbger = 0; - uint32_t acc_ctl_value = 0; - - core_info[coreid].debug_under_dex_on = false; - aice_read_misc(coreid, NDS_EDM_MISC_DBGER, &dbger); - - if (dbger & NDS_DBGER_AT_MAX) - LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level. -->"); - - if (dbger & NDS_DBGER_DEX) { - if (is_v2_edm(coreid) == false) { - /** debug 'debug mode'. use force_debug to issue dbgi */ - aice_read_misc(coreid, NDS_EDM_MISC_ACC_CTL, &acc_ctl_value); - acc_ctl_value |= 0x8; - aice_write_misc(coreid, NDS_EDM_MISC_ACC_CTL, acc_ctl_value); - core_info[coreid].debug_under_dex_on = true; - - aice_write_misc(coreid, NDS_EDM_MISC_EDM_CMDR, 0); - /* If CPU stalled due to AT_MAX, clear AT_MAX status. */ - if (dbger & NDS_DBGER_AT_MAX) - aice_write_misc(coreid, NDS_EDM_MISC_DBGER, NDS_DBGER_AT_MAX); - } - } else { - /** Issue DBGI normally */ - aice_write_misc(coreid, NDS_EDM_MISC_EDM_CMDR, 0); - /* If CPU stalled due to AT_MAX, clear AT_MAX status. */ - if (dbger & NDS_DBGER_AT_MAX) - aice_write_misc(coreid, NDS_EDM_MISC_DBGER, NDS_DBGER_AT_MAX); - } - - if (aice_check_dbger(coreid, NDS_DBGER_DEX) != ERROR_OK) { - LOG_ERROR("<-- TARGET ERROR! Unable to stop the debug target through DBGI. -->"); - return ERROR_FAIL; - } - - if (core_info[coreid].debug_under_dex_on) { - if (core_info[coreid].dex_use_psw_on == false) { - /* under debug 'debug mode', force $psw to 'debug mode' behavior */ - /* !!!NOTICE!!! this is workaround for debug 'debug mode'. - * it is only for debugging 'debug exception handler' purpose. - * after openocd detaches from target, target behavior is - * undefined. */ - uint32_t ir0_value = 0; - uint32_t debug_mode_ir0_value; - aice_read_reg(coreid, IR0, &ir0_value); - debug_mode_ir0_value = ir0_value | 0x408; /* turn on DEX, set POM = 1 */ - debug_mode_ir0_value &= ~(0x000000C1); /* turn off DT/IT/GIE */ - aice_write_reg(coreid, IR0, debug_mode_ir0_value); - } - } - - /** set EDM_CTL.DBGIM & EDM_CTL.DBGACKM after halt */ - if (edm_ctl_value & 0x3) - aice_write_edmsr(coreid, NDS_EDM_SR_EDM_CTL, edm_ctl_value); - - /* backup r0 & r1 */ - aice_backup_tmp_registers(coreid); - core_info[coreid].core_state = AICE_TARGET_HALTED; - - return ERROR_OK; -} - -static int aice_usb_state(uint32_t coreid, enum aice_target_state_s *state) -{ - uint32_t dbger_value; - uint32_t ice_state; - - int result = aice_read_misc(coreid, NDS_EDM_MISC_DBGER, &dbger_value); - - if (result == ERROR_AICE_TIMEOUT) { - if (aice_read_ctrl(AICE_READ_CTRL_GET_ICE_STATE, &ice_state) != ERROR_OK) { - LOG_ERROR("<-- AICE ERROR! AICE is unplugged. -->"); - return ERROR_FAIL; - } - - if ((ice_state & 0x20) == 0) { - LOG_ERROR("<-- TARGET ERROR! Target is disconnected with AICE. -->"); - return ERROR_FAIL; - } else { - return ERROR_FAIL; - } - } else if (result == ERROR_AICE_DISCONNECT) { - LOG_ERROR("<-- AICE ERROR! AICE is unplugged. -->"); - return ERROR_FAIL; - } - - if ((dbger_value & NDS_DBGER_ILL_SEC_ACC) == NDS_DBGER_ILL_SEC_ACC) { - LOG_ERROR("<-- TARGET ERROR! Insufficient security privilege. -->"); - - /* Clear ILL_SEC_ACC */ - aice_write_misc(coreid, NDS_EDM_MISC_DBGER, NDS_DBGER_ILL_SEC_ACC); - - *state = AICE_TARGET_RUNNING; - core_info[coreid].core_state = AICE_TARGET_RUNNING; - } else if ((dbger_value & NDS_DBGER_AT_MAX) == NDS_DBGER_AT_MAX) { - /* Issue DBGI to exit cpu stall */ - aice_usb_halt(coreid); - - /* Read OIPC to find out the trigger point */ - uint32_t ir11_value; - aice_read_reg(coreid, IR11, &ir11_value); - - LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level; " - "CPU is stalled at 0x%08" PRIx32 " for debugging. -->", ir11_value); - - *state = AICE_TARGET_HALTED; - } else if ((dbger_value & NDS_DBGER_CRST) == NDS_DBGER_CRST) { - LOG_DEBUG("DBGER.CRST is on."); - - *state = AICE_TARGET_RESET; - core_info[coreid].core_state = AICE_TARGET_RUNNING; - - /* Clear CRST */ - aice_write_misc(coreid, NDS_EDM_MISC_DBGER, NDS_DBGER_CRST); - } else if ((dbger_value & NDS_DBGER_DEX) == NDS_DBGER_DEX) { - if (core_info[coreid].core_state == AICE_TARGET_RUNNING) { - /* enter debug mode, init EDM registers */ - /* backup EDM registers */ - aice_backup_edm_registers(coreid); - /* init EDM for host debugging */ - aice_init_edm_registers(coreid, true); - aice_backup_tmp_registers(coreid); - core_info[coreid].core_state = AICE_TARGET_HALTED; - } else if (core_info[coreid].core_state == AICE_TARGET_UNKNOWN) { - /* debug 'debug mode', use force debug to halt core */ - aice_usb_halt(coreid); - } - *state = AICE_TARGET_HALTED; - } else { - *state = AICE_TARGET_RUNNING; - core_info[coreid].core_state = AICE_TARGET_RUNNING; - } - - return ERROR_OK; -} - -static int aice_usb_reset(void) -{ - if (aice_reset_box() != ERROR_OK) - return ERROR_FAIL; - - /* issue TRST */ - if (!custom_trst_script) { - if (aice_write_ctrl(AICE_WRITE_CTRL_JTAG_PIN_CONTROL, - AICE_JTAG_PIN_CONTROL_TRST) != ERROR_OK) - return ERROR_FAIL; - } else { - /* custom trst operations */ - if (aice_execute_custom_script(custom_trst_script) != ERROR_OK) - return ERROR_FAIL; - } - - if (aice_usb_set_clock(jtag_clock) != ERROR_OK) - return ERROR_FAIL; - - return ERROR_OK; -} - -static int aice_issue_srst(uint32_t coreid) -{ - LOG_DEBUG("aice_issue_srst"); - - /* After issuing srst, target will be running. So we need to restore EDM_CTL. */ - aice_restore_edm_registers(coreid); - - if (!custom_srst_script) { - if (aice_write_ctrl(AICE_WRITE_CTRL_JTAG_PIN_CONTROL, - AICE_JTAG_PIN_CONTROL_SRST) != ERROR_OK) - return ERROR_FAIL; - } else { - /* custom srst operations */ - if (aice_execute_custom_script(custom_srst_script) != ERROR_OK) - return ERROR_FAIL; - } - - /* wait CRST infinitely */ - uint32_t dbger_value; - int i = 0; - while (1) { - if (aice_read_misc(coreid, - NDS_EDM_MISC_DBGER, &dbger_value) != ERROR_OK) - return ERROR_FAIL; - - if (dbger_value & NDS_DBGER_CRST) - break; - - if ((i % 30) == 0) - keep_alive(); - i++; - } - - core_info[coreid].host_dtr_valid = false; - core_info[coreid].target_dtr_valid = false; - - core_info[coreid].core_state = AICE_TARGET_RUNNING; - return ERROR_OK; -} - -static int aice_issue_reset_hold(uint32_t coreid) -{ - LOG_DEBUG("aice_issue_reset_hold"); - - /* set no_dbgi_pin to 0 */ - uint32_t pin_status; - aice_read_ctrl(AICE_READ_CTRL_GET_JTAG_PIN_STATUS, &pin_status); - if (pin_status & 0x4) - aice_write_ctrl(AICE_WRITE_CTRL_JTAG_PIN_STATUS, pin_status & (~0x4)); - - /* issue restart */ - if (!custom_restart_script) { - if (aice_write_ctrl(AICE_WRITE_CTRL_JTAG_PIN_CONTROL, - AICE_JTAG_PIN_CONTROL_RESTART) != ERROR_OK) - return ERROR_FAIL; - } else { - /* custom restart operations */ - if (aice_execute_custom_script(custom_restart_script) != ERROR_OK) - return ERROR_FAIL; - } - - if (aice_check_dbger(coreid, NDS_DBGER_CRST | NDS_DBGER_DEX) == ERROR_OK) { - aice_backup_tmp_registers(coreid); - core_info[coreid].core_state = AICE_TARGET_HALTED; - - return ERROR_OK; - } else { - /* set no_dbgi_pin to 1 */ - aice_write_ctrl(AICE_WRITE_CTRL_JTAG_PIN_STATUS, pin_status | 0x4); - - /* issue restart again */ - if (!custom_restart_script) { - if (aice_write_ctrl(AICE_WRITE_CTRL_JTAG_PIN_CONTROL, - AICE_JTAG_PIN_CONTROL_RESTART) != ERROR_OK) - return ERROR_FAIL; - } else { - /* custom restart operations */ - if (aice_execute_custom_script(custom_restart_script) != ERROR_OK) - return ERROR_FAIL; - } - - if (aice_check_dbger(coreid, NDS_DBGER_CRST | NDS_DBGER_DEX) == ERROR_OK) { - aice_backup_tmp_registers(coreid); - core_info[coreid].core_state = AICE_TARGET_HALTED; - - return ERROR_OK; - } - - /* do software reset-and-hold */ - aice_issue_srst(coreid); - aice_usb_halt(coreid); - - uint32_t value_ir3; - aice_read_reg(coreid, IR3, &value_ir3); - aice_write_reg(coreid, PC, value_ir3 & 0xFFFF0000); - } - - return ERROR_FAIL; -} - -static int aice_issue_reset_hold_multi(void) -{ - uint32_t write_ctrl_value = 0; - - /* set SRST */ - write_ctrl_value = AICE_CUSTOM_DELAY_SET_SRST; - write_ctrl_value |= (0x200 << 16); - if (aice_write_ctrl(AICE_WRITE_CTRL_CUSTOM_DELAY, - write_ctrl_value) != ERROR_OK) - return ERROR_FAIL; - - for (uint8_t i = 0 ; i < total_num_of_core ; i++) - aice_write_misc(i, NDS_EDM_MISC_EDM_CMDR, 0); - - /* clear SRST */ - write_ctrl_value = AICE_CUSTOM_DELAY_CLEAN_SRST; - write_ctrl_value |= (0x200 << 16); - if (aice_write_ctrl(AICE_WRITE_CTRL_CUSTOM_DELAY, - write_ctrl_value) != ERROR_OK) - return ERROR_FAIL; - - for (uint8_t i = 0; i < total_num_of_core; i++) - aice_edm_init(i); - - return ERROR_FAIL; -} - -static int aice_usb_assert_srst(uint32_t coreid, enum aice_srst_type_s srst) -{ - if ((srst != AICE_SRST) && (srst != AICE_RESET_HOLD)) - return ERROR_FAIL; - - /* clear DBGER */ - if (aice_write_misc(coreid, NDS_EDM_MISC_DBGER, - NDS_DBGER_CLEAR_ALL) != ERROR_OK) - return ERROR_FAIL; - - int result = ERROR_OK; - if (srst == AICE_SRST) - result = aice_issue_srst(coreid); - else { - if (total_num_of_core == 1) - result = aice_issue_reset_hold(coreid); - else - result = aice_issue_reset_hold_multi(); - } - - /* Clear DBGER.CRST after reset to avoid 'core-reset checking' errors. - * assert_srst is user-intentional reset behavior, so we could - * clear DBGER.CRST safely. - */ - if (aice_write_misc(coreid, - NDS_EDM_MISC_DBGER, NDS_DBGER_CRST) != ERROR_OK) - return ERROR_FAIL; - - return result; -} - -static int aice_usb_run(uint32_t coreid) -{ - LOG_DEBUG("aice_usb_run"); - - uint32_t dbger_value; - if (aice_read_misc(coreid, - NDS_EDM_MISC_DBGER, &dbger_value) != ERROR_OK) - return ERROR_FAIL; - - if ((dbger_value & NDS_DBGER_DEX) != NDS_DBGER_DEX) { - LOG_WARNING("<-- TARGET WARNING! The debug target exited " - "the debug mode unexpectedly. -->"); - return ERROR_FAIL; - } - - /* restore r0 & r1 before free run */ - aice_restore_tmp_registers(coreid); - core_info[coreid].core_state = AICE_TARGET_RUNNING; - - /* clear DBGER */ - aice_write_misc(coreid, NDS_EDM_MISC_DBGER, - NDS_DBGER_CLEAR_ALL); - - /** restore EDM registers */ - /** OpenOCD should restore EDM_CTL **before** to exit debug state. - * Otherwise, following instruction will read wrong EDM_CTL value. - * - * pc -> mfsr $p0, EDM_CTL (single step) - * slli $p0, $p0, 1 - * slri $p0, $p0, 31 - */ - aice_restore_edm_registers(coreid); - - /** execute instructions in DIM */ - uint32_t instructions[4] = { - NOP, - NOP, - NOP, - IRET - }; - int result = aice_execute_dim(coreid, instructions, 4); - - return result; -} - -static int aice_usb_step(uint32_t coreid) -{ - LOG_DEBUG("aice_usb_step"); - - uint32_t ir0_value; - uint32_t ir0_reg_num; - - if (is_v2_edm(coreid) == true) - /* V2 EDM will push interrupt stack as debug exception */ - ir0_reg_num = IR1; - else - ir0_reg_num = IR0; - - /** enable HSS */ - aice_read_reg(coreid, ir0_reg_num, &ir0_value); - if ((ir0_value & 0x800) == 0) { - /** set PSW.HSS */ - ir0_value |= (0x01 << 11); - aice_write_reg(coreid, ir0_reg_num, ir0_value); - } - - if (aice_usb_run(coreid) == ERROR_FAIL) - return ERROR_FAIL; - - int i = 0; - enum aice_target_state_s state; - while (1) { - /* read DBGER */ - if (aice_usb_state(coreid, &state) != ERROR_OK) - return ERROR_FAIL; - - if (state == AICE_TARGET_HALTED) - break; - - int64_t then = 0; - if (i == 30) - then = timeval_ms(); - - if (i >= 30) { - if ((timeval_ms() - then) > 1000) - LOG_WARNING("Timeout (1000ms) waiting for halt to complete"); - - return ERROR_FAIL; - } - i++; - } - - /** disable HSS */ - aice_read_reg(coreid, ir0_reg_num, &ir0_value); - ir0_value &= ~(0x01 << 11); - aice_write_reg(coreid, ir0_reg_num, ir0_value); - - return ERROR_OK; -} - -static int aice_usb_read_mem_b_bus(uint32_t coreid, uint32_t address, uint32_t *data) -{ - return aice_read_mem_b(coreid, address, data); -} - -static int aice_usb_read_mem_h_bus(uint32_t coreid, uint32_t address, uint32_t *data) -{ - return aice_read_mem_h(coreid, address, data); -} - -static int aice_usb_read_mem_w_bus(uint32_t coreid, uint32_t address, uint32_t *data) -{ - return aice_read_mem(coreid, address, data); -} - -static int aice_usb_read_mem_b_dim(uint32_t coreid, uint32_t address, uint32_t *data) -{ - uint32_t value; - uint32_t instructions[4] = { - LBI_BI(R1, R0), - MTSR_DTR(R1), - DSB, - BEQ_MINUS_12 - }; - - aice_execute_dim(coreid, instructions, 4); - - aice_read_dtr(coreid, &value); - *data = value & 0xFF; - - return ERROR_OK; -} - -static int aice_usb_read_mem_h_dim(uint32_t coreid, uint32_t address, uint32_t *data) -{ - uint32_t value; - uint32_t instructions[4] = { - LHI_BI(R1, R0), - MTSR_DTR(R1), - DSB, - BEQ_MINUS_12 - }; - - aice_execute_dim(coreid, instructions, 4); - - aice_read_dtr(coreid, &value); - *data = value & 0xFFFF; - - return ERROR_OK; -} - -static int aice_usb_read_mem_w_dim(uint32_t coreid, uint32_t address, uint32_t *data) -{ - uint32_t instructions[4] = { - LWI_BI(R1, R0), - MTSR_DTR(R1), - DSB, - BEQ_MINUS_12 - }; - - aice_execute_dim(coreid, instructions, 4); - - aice_read_dtr(coreid, data); - - return ERROR_OK; -} - -static int aice_usb_set_address_dim(uint32_t coreid, uint32_t address) -{ - uint32_t instructions[4] = { - SETHI(R0, address >> 12), - ORI(R0, R0, address & 0x00000FFF), - NOP, - BEQ_MINUS_12 - }; - - return aice_execute_dim(coreid, instructions, 4); -} - -static int aice_usb_read_memory_unit(uint32_t coreid, uint32_t addr, uint32_t size, - uint32_t count, uint8_t *buffer) -{ - LOG_DEBUG("aice_usb_read_memory_unit, addr: 0x%08" PRIx32 - ", size: %" PRIu32 ", count: %" PRIu32 "", - addr, size, count); - - if (core_info[coreid].access_channel == NDS_MEMORY_ACC_CPU) - aice_usb_set_address_dim(coreid, addr); - - uint32_t value; - size_t i; - read_mem_func_t read_mem_func; - - switch (size) { - case 1: - if (core_info[coreid].access_channel == NDS_MEMORY_ACC_BUS) - read_mem_func = aice_usb_read_mem_b_bus; - else - read_mem_func = aice_usb_read_mem_b_dim; - - for (i = 0; i < count; i++) { - read_mem_func(coreid, addr, &value); - *buffer++ = (uint8_t)value; - addr++; - } - break; - case 2: - if (core_info[coreid].access_channel == NDS_MEMORY_ACC_BUS) - read_mem_func = aice_usb_read_mem_h_bus; - else - read_mem_func = aice_usb_read_mem_h_dim; - - for (i = 0; i < count; i++) { - read_mem_func(coreid, addr, &value); - uint16_t svalue = value; - memcpy(buffer, &svalue, sizeof(uint16_t)); - buffer += 2; - addr += 2; - } - break; - case 4: - if (core_info[coreid].access_channel == NDS_MEMORY_ACC_BUS) - read_mem_func = aice_usb_read_mem_w_bus; - else - read_mem_func = aice_usb_read_mem_w_dim; - - for (i = 0; i < count; i++) { - read_mem_func(coreid, addr, &value); - memcpy(buffer, &value, sizeof(uint32_t)); - buffer += 4; - addr += 4; - } - break; - } - - return ERROR_OK; -} - -static int aice_usb_write_mem_b_bus(uint32_t coreid, uint32_t address, uint32_t data) -{ - return aice_write_mem_b(coreid, address, data); -} - -static int aice_usb_write_mem_h_bus(uint32_t coreid, uint32_t address, uint32_t data) -{ - return aice_write_mem_h(coreid, address, data); -} - -static int aice_usb_write_mem_w_bus(uint32_t coreid, uint32_t address, uint32_t data) -{ - return aice_write_mem(coreid, address, data); -} - -static int aice_usb_write_mem_b_dim(uint32_t coreid, uint32_t address, uint32_t data) -{ - uint32_t instructions[4] = { - MFSR_DTR(R1), - SBI_BI(R1, R0), - DSB, - BEQ_MINUS_12 - }; - - aice_write_dtr(coreid, data & 0xFF); - aice_execute_dim(coreid, instructions, 4); - - return ERROR_OK; -} - -static int aice_usb_write_mem_h_dim(uint32_t coreid, uint32_t address, uint32_t data) -{ - uint32_t instructions[4] = { - MFSR_DTR(R1), - SHI_BI(R1, R0), - DSB, - BEQ_MINUS_12 - }; - - aice_write_dtr(coreid, data & 0xFFFF); - aice_execute_dim(coreid, instructions, 4); - - return ERROR_OK; -} - -static int aice_usb_write_mem_w_dim(uint32_t coreid, uint32_t address, uint32_t data) -{ - uint32_t instructions[4] = { - MFSR_DTR(R1), - SWI_BI(R1, R0), - DSB, - BEQ_MINUS_12 - }; - - aice_write_dtr(coreid, data); - aice_execute_dim(coreid, instructions, 4); - - return ERROR_OK; -} - -static int aice_usb_write_memory_unit(uint32_t coreid, uint32_t addr, uint32_t size, - uint32_t count, const uint8_t *buffer) -{ - LOG_DEBUG("aice_usb_write_memory_unit, addr: 0x%08" PRIx32 - ", size: %" PRIu32 ", count: %" PRIu32 "", - addr, size, count); - - if (core_info[coreid].access_channel == NDS_MEMORY_ACC_CPU) - aice_usb_set_address_dim(coreid, addr); - - size_t i; - write_mem_func_t write_mem_func; - - switch (size) { - case 1: - if (core_info[coreid].access_channel == NDS_MEMORY_ACC_BUS) - write_mem_func = aice_usb_write_mem_b_bus; - else - write_mem_func = aice_usb_write_mem_b_dim; - - for (i = 0; i < count; i++) { - write_mem_func(coreid, addr, *buffer); - buffer++; - addr++; - } - break; - case 2: - if (core_info[coreid].access_channel == NDS_MEMORY_ACC_BUS) - write_mem_func = aice_usb_write_mem_h_bus; - else - write_mem_func = aice_usb_write_mem_h_dim; - - for (i = 0; i < count; i++) { - uint16_t value; - memcpy(&value, buffer, sizeof(uint16_t)); - - write_mem_func(coreid, addr, value); - buffer += 2; - addr += 2; - } - break; - case 4: - if (core_info[coreid].access_channel == NDS_MEMORY_ACC_BUS) - write_mem_func = aice_usb_write_mem_w_bus; - else - write_mem_func = aice_usb_write_mem_w_dim; - - for (i = 0; i < count; i++) { - uint32_t value; - memcpy(&value, buffer, sizeof(uint32_t)); - - write_mem_func(coreid, addr, value); - buffer += 4; - addr += 4; - } - break; - } - - return ERROR_OK; -} - -static int aice_bulk_read_mem(uint32_t coreid, uint32_t addr, uint32_t count, - uint8_t *buffer) -{ - uint32_t packet_size; - - while (count > 0) { - packet_size = (count >= 0x100) ? 0x100 : count; - - /** set address */ - addr &= 0xFFFFFFFC; - if (aice_write_misc(coreid, NDS_EDM_MISC_SBAR, addr) != ERROR_OK) - return ERROR_FAIL; - - if (aice_fastread_mem(coreid, buffer, - packet_size) != ERROR_OK) - return ERROR_FAIL; - - buffer += (packet_size * 4); - addr += (packet_size * 4); - count -= packet_size; - } - - return ERROR_OK; -} - -static int aice_bulk_write_mem(uint32_t coreid, uint32_t addr, uint32_t count, - const uint8_t *buffer) -{ - uint32_t packet_size; - - while (count > 0) { - packet_size = (count >= 0x100) ? 0x100 : count; - - /** set address */ - addr &= 0xFFFFFFFC; - if (aice_write_misc(coreid, NDS_EDM_MISC_SBAR, addr | 1) != ERROR_OK) - return ERROR_FAIL; - - if (aice_fastwrite_mem(coreid, buffer, - packet_size) != ERROR_OK) - return ERROR_FAIL; - - buffer += (packet_size * 4); - addr += (packet_size * 4); - count -= packet_size; - } - - return ERROR_OK; -} - -static int aice_usb_bulk_read_mem(uint32_t coreid, uint32_t addr, - uint32_t length, uint8_t *buffer) -{ - LOG_DEBUG("aice_usb_bulk_read_mem, addr: 0x%08" PRIx32 ", length: 0x%08" PRIx32, addr, length); - - int retval; - - if (core_info[coreid].access_channel == NDS_MEMORY_ACC_CPU) - aice_usb_set_address_dim(coreid, addr); - - if (core_info[coreid].access_channel == NDS_MEMORY_ACC_CPU) - retval = aice_usb_read_memory_unit(coreid, addr, 4, length / 4, buffer); - else - retval = aice_bulk_read_mem(coreid, addr, length / 4, buffer); - - return retval; -} - -static int aice_usb_bulk_write_mem(uint32_t coreid, uint32_t addr, - uint32_t length, const uint8_t *buffer) -{ - LOG_DEBUG("aice_usb_bulk_write_mem, addr: 0x%08" PRIx32 ", length: 0x%08" PRIx32, addr, length); - - int retval; - - if (core_info[coreid].access_channel == NDS_MEMORY_ACC_CPU) - aice_usb_set_address_dim(coreid, addr); - - if (core_info[coreid].access_channel == NDS_MEMORY_ACC_CPU) - retval = aice_usb_write_memory_unit(coreid, addr, 4, length / 4, buffer); - else - retval = aice_bulk_write_mem(coreid, addr, length / 4, buffer); - - return retval; -} - -static int aice_usb_read_debug_reg(uint32_t coreid, uint32_t addr, uint32_t *val) -{ - if (core_info[coreid].core_state == AICE_TARGET_HALTED) { - if (addr == NDS_EDM_SR_EDMSW) { - *val = core_info[coreid].edmsw_backup; - } else if (addr == NDS_EDM_SR_EDM_DTR) { - if (core_info[coreid].target_dtr_valid) { - /* if EDM_DTR has read out, clear it. */ - *val = core_info[coreid].target_dtr_backup; - core_info[coreid].edmsw_backup &= (~0x1); - core_info[coreid].target_dtr_valid = false; - } else { - *val = 0; - } - } - } - - return aice_read_edmsr(coreid, addr, val); -} - -static int aice_usb_write_debug_reg(uint32_t coreid, uint32_t addr, const uint32_t val) -{ - if (core_info[coreid].core_state == AICE_TARGET_HALTED) { - if (addr == NDS_EDM_SR_EDM_DTR) { - core_info[coreid].host_dtr_backup = val; - core_info[coreid].edmsw_backup |= 0x2; - core_info[coreid].host_dtr_valid = true; - } - } - - return aice_write_edmsr(coreid, addr, val); -} - -static int aice_usb_memory_access(uint32_t coreid, enum nds_memory_access channel) -{ - LOG_DEBUG("aice_usb_memory_access, access channel: %u", channel); - - core_info[coreid].access_channel = channel; - - return ERROR_OK; -} - -static int aice_usb_memory_mode(uint32_t coreid, enum nds_memory_select mem_select) -{ - if (core_info[coreid].memory_select == mem_select) - return ERROR_OK; - - LOG_DEBUG("aice_usb_memory_mode, memory select: %u", mem_select); - - core_info[coreid].memory_select = mem_select; - - if (core_info[coreid].memory_select != NDS_MEMORY_SELECT_AUTO) - aice_write_misc(coreid, NDS_EDM_MISC_ACC_CTL, - core_info[coreid].memory_select - 1); - else - aice_write_misc(coreid, NDS_EDM_MISC_ACC_CTL, - NDS_MEMORY_SELECT_MEM - 1); - - return ERROR_OK; -} - -static int aice_usb_read_tlb(uint32_t coreid, target_addr_t virtual_address, - target_addr_t *physical_address) -{ - LOG_DEBUG("aice_usb_read_tlb, virtual address: 0x%08" TARGET_PRIxADDR, virtual_address); - - uint32_t instructions[4]; - uint32_t probe_result; - uint32_t value_mr3; - uint32_t value_mr4; - uint32_t access_page_size; - uint32_t virtual_offset; - uint32_t physical_page_number; - - aice_write_dtr(coreid, virtual_address); - - /* probe TLB first */ - instructions[0] = MFSR_DTR(R0); - instructions[1] = TLBOP_TARGET_PROBE(R1, R0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - aice_execute_dim(coreid, instructions, 4); - - aice_read_reg(coreid, R1, &probe_result); - - if (probe_result & 0x80000000) - return ERROR_FAIL; - - /* read TLB entry */ - aice_write_dtr(coreid, probe_result & 0x7FF); - - /* probe TLB first */ - instructions[0] = MFSR_DTR(R0); - instructions[1] = TLBOP_TARGET_READ(R0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - aice_execute_dim(coreid, instructions, 4); - - /* TODO: it should backup mr3, mr4 */ - aice_read_reg(coreid, MR3, &value_mr3); - aice_read_reg(coreid, MR4, &value_mr4); - - access_page_size = value_mr4 & 0xF; - if (access_page_size == 0) { /* 4K page */ - virtual_offset = virtual_address & 0x00000FFF; - physical_page_number = value_mr3 & 0xFFFFF000; - } else if (access_page_size == 1) { /* 8K page */ - virtual_offset = virtual_address & 0x00001FFF; - physical_page_number = value_mr3 & 0xFFFFE000; - } else if (access_page_size == 5) { /* 1M page */ - virtual_offset = virtual_address & 0x000FFFFF; - physical_page_number = value_mr3 & 0xFFF00000; - } else { - return ERROR_FAIL; - } - - *physical_address = physical_page_number | virtual_offset; - - return ERROR_OK; -} - -static int aice_usb_init_cache(uint32_t coreid) -{ - LOG_DEBUG("aice_usb_init_cache"); - - uint32_t value_cr1; - uint32_t value_cr2; - - aice_read_reg(coreid, CR1, &value_cr1); - aice_read_reg(coreid, CR2, &value_cr2); - - struct cache_info *icache = &core_info[coreid].icache; - - icache->set = value_cr1 & 0x7; - icache->log2_set = icache->set + 6; - icache->set = 64 << icache->set; - icache->way = ((value_cr1 >> 3) & 0x7) + 1; - icache->line_size = (value_cr1 >> 6) & 0x7; - if (icache->line_size != 0) { - icache->log2_line_size = icache->line_size + 2; - icache->line_size = 8 << (icache->line_size - 1); - } else { - icache->log2_line_size = 0; - } - - LOG_DEBUG("\ticache set: %" PRIu32 ", way: %" PRIu32 ", line size: %" PRIu32 ", " - "log2(set): %" PRIu32 ", log2(line_size): %" PRIu32 "", - icache->set, icache->way, icache->line_size, - icache->log2_set, icache->log2_line_size); - - struct cache_info *dcache = &core_info[coreid].dcache; - - dcache->set = value_cr2 & 0x7; - dcache->log2_set = dcache->set + 6; - dcache->set = 64 << dcache->set; - dcache->way = ((value_cr2 >> 3) & 0x7) + 1; - dcache->line_size = (value_cr2 >> 6) & 0x7; - if (dcache->line_size != 0) { - dcache->log2_line_size = dcache->line_size + 2; - dcache->line_size = 8 << (dcache->line_size - 1); - } else { - dcache->log2_line_size = 0; - } - - LOG_DEBUG("\tdcache set: %" PRIu32 ", way: %" PRIu32 ", line size: %" PRIu32 ", " - "log2(set): %" PRIu32 ", log2(line_size): %" PRIu32 "", - dcache->set, dcache->way, dcache->line_size, - dcache->log2_set, dcache->log2_line_size); - - core_info[coreid].cache_init = true; - - return ERROR_OK; -} - -static int aice_usb_dcache_inval_all(uint32_t coreid) -{ - LOG_DEBUG("aice_usb_dcache_inval_all"); - - uint32_t set_index; - uint32_t way_index; - uint32_t cache_index; - uint32_t instructions[4]; - - instructions[0] = MFSR_DTR(R0); - instructions[1] = L1D_IX_INVAL(R0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - - struct cache_info *dcache = &core_info[coreid].dcache; - - for (set_index = 0; set_index < dcache->set; set_index++) { - for (way_index = 0; way_index < dcache->way; way_index++) { - cache_index = (way_index << (dcache->log2_set + dcache->log2_line_size)) | - (set_index << dcache->log2_line_size); - - if (aice_write_dtr(coreid, cache_index) != ERROR_OK) - return ERROR_FAIL; - - if (aice_execute_dim(coreid, instructions, 4) != ERROR_OK) - return ERROR_FAIL; - } - } - - return ERROR_OK; -} - -static int aice_usb_dcache_va_inval(uint32_t coreid, uint32_t address) -{ - LOG_DEBUG("aice_usb_dcache_va_inval"); - - uint32_t instructions[4]; - - aice_write_dtr(coreid, address); - - instructions[0] = MFSR_DTR(R0); - instructions[1] = L1D_VA_INVAL(R0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - - return aice_execute_dim(coreid, instructions, 4); -} - -static int aice_usb_dcache_wb_all(uint32_t coreid) -{ - LOG_DEBUG("aice_usb_dcache_wb_all"); - - uint32_t set_index; - uint32_t way_index; - uint32_t cache_index; - uint32_t instructions[4]; - - instructions[0] = MFSR_DTR(R0); - instructions[1] = L1D_IX_WB(R0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - - struct cache_info *dcache = &core_info[coreid].dcache; - - for (set_index = 0; set_index < dcache->set; set_index++) { - for (way_index = 0; way_index < dcache->way; way_index++) { - cache_index = (way_index << (dcache->log2_set + dcache->log2_line_size)) | - (set_index << dcache->log2_line_size); - - if (aice_write_dtr(coreid, cache_index) != ERROR_OK) - return ERROR_FAIL; - - if (aice_execute_dim(coreid, instructions, 4) != ERROR_OK) - return ERROR_FAIL; - } - } - - return ERROR_OK; -} - -static int aice_usb_dcache_va_wb(uint32_t coreid, uint32_t address) -{ - LOG_DEBUG("aice_usb_dcache_va_wb"); - - uint32_t instructions[4]; - - aice_write_dtr(coreid, address); - - instructions[0] = MFSR_DTR(R0); - instructions[1] = L1D_VA_WB(R0); - instructions[2] = DSB; - instructions[3] = BEQ_MINUS_12; - - return aice_execute_dim(coreid, instructions, 4); -} - -static int aice_usb_icache_inval_all(uint32_t coreid) -{ - LOG_DEBUG("aice_usb_icache_inval_all"); - - uint32_t set_index; - uint32_t way_index; - uint32_t cache_index; - uint32_t instructions[4]; - - instructions[0] = MFSR_DTR(R0); - instructions[1] = L1I_IX_INVAL(R0); - instructions[2] = ISB; - instructions[3] = BEQ_MINUS_12; - - struct cache_info *icache = &core_info[coreid].icache; - - for (set_index = 0; set_index < icache->set; set_index++) { - for (way_index = 0; way_index < icache->way; way_index++) { - cache_index = (way_index << (icache->log2_set + icache->log2_line_size)) | - (set_index << icache->log2_line_size); - - if (aice_write_dtr(coreid, cache_index) != ERROR_OK) - return ERROR_FAIL; - - if (aice_execute_dim(coreid, instructions, 4) != ERROR_OK) - return ERROR_FAIL; - } - } - - return ERROR_OK; -} - -static int aice_usb_icache_va_inval(uint32_t coreid, uint32_t address) -{ - LOG_DEBUG("aice_usb_icache_va_inval"); - - uint32_t instructions[4]; - - aice_write_dtr(coreid, address); - - instructions[0] = MFSR_DTR(R0); - instructions[1] = L1I_VA_INVAL(R0); - instructions[2] = ISB; - instructions[3] = BEQ_MINUS_12; - - return aice_execute_dim(coreid, instructions, 4); -} - -static int aice_usb_cache_ctl(uint32_t coreid, uint32_t subtype, uint32_t address) -{ - LOG_DEBUG("aice_usb_cache_ctl"); - - int result; - - if (core_info[coreid].cache_init == false) - aice_usb_init_cache(coreid); - - switch (subtype) { - case AICE_CACHE_CTL_L1D_INVALALL: - result = aice_usb_dcache_inval_all(coreid); - break; - case AICE_CACHE_CTL_L1D_VA_INVAL: - result = aice_usb_dcache_va_inval(coreid, address); - break; - case AICE_CACHE_CTL_L1D_WBALL: - result = aice_usb_dcache_wb_all(coreid); - break; - case AICE_CACHE_CTL_L1D_VA_WB: - result = aice_usb_dcache_va_wb(coreid, address); - break; - case AICE_CACHE_CTL_L1I_INVALALL: - result = aice_usb_icache_inval_all(coreid); - break; - case AICE_CACHE_CTL_L1I_VA_INVAL: - result = aice_usb_icache_va_inval(coreid, address); - break; - default: - result = ERROR_FAIL; - break; - } - - return result; -} - -static int aice_usb_set_retry_times(uint32_t a_retry_times) -{ - aice_max_retry_times = a_retry_times; - return ERROR_OK; -} - -static int aice_usb_program_edm(uint32_t coreid, char *command_sequence) -{ - char *command_str; - char *reg_name_0; - char *reg_name_1; - uint32_t data_value; - int i; - - /* init strtok() */ - command_str = strtok(command_sequence, ";"); - if (!command_str) - return ERROR_OK; - - do { - i = 0; - /* process one command */ - while (command_str[i] == ' ' || - command_str[i] == '\n' || - command_str[i] == '\r' || - command_str[i] == '\t') - i++; - - /* skip ' ', '\r', '\n', '\t' */ - command_str = command_str + i; - - if (strncmp(command_str, "write_misc", 10) == 0) { - reg_name_0 = strstr(command_str, "gen_port0"); - reg_name_1 = strstr(command_str, "gen_port1"); - - if (reg_name_0) { - data_value = strtoul(reg_name_0 + 9, NULL, 0); - - if (aice_write_misc(coreid, - NDS_EDM_MISC_GEN_PORT0, data_value) != ERROR_OK) - return ERROR_FAIL; - - } else if (reg_name_1) { - data_value = strtoul(reg_name_1 + 9, NULL, 0); - - if (aice_write_misc(coreid, - NDS_EDM_MISC_GEN_PORT1, data_value) != ERROR_OK) - return ERROR_FAIL; - } else { - LOG_ERROR("program EDM, unsupported misc register: %s", command_str); - } - } else { - LOG_ERROR("program EDM, unsupported command: %s", command_str); - } - - /* update command_str */ - command_str = strtok(NULL, ";"); - - } while (command_str); - - return ERROR_OK; -} - -static int aice_usb_set_command_mode(enum aice_command_mode command_mode) -{ - int retval = ERROR_OK; - - /* flush usb_packets_buffer as users change mode */ - retval = aice_usb_packet_flush(); - - if (command_mode == AICE_COMMAND_MODE_BATCH) { - /* reset batch buffer */ - aice_command_mode = AICE_COMMAND_MODE_NORMAL; - retval = aice_write_ctrl(AICE_WRITE_CTRL_BATCH_CMD_BUF0_CTRL, 0x40000); - } - - aice_command_mode = command_mode; - - return retval; -} - -static int aice_usb_execute(uint32_t coreid, uint32_t *instructions, - uint32_t instruction_num) -{ - uint32_t i, j; - uint8_t current_instruction_num; - uint32_t dim_instructions[4] = {NOP, NOP, NOP, BEQ_MINUS_12}; - - /* To execute 4 instructions as a special case */ - if (instruction_num == 4) - return aice_execute_dim(coreid, instructions, 4); - - for (i = 0 ; i < instruction_num ; i += 3) { - if (instruction_num - i < 3) { - current_instruction_num = instruction_num - i; - for (j = current_instruction_num ; j < 3 ; j++) - dim_instructions[j] = NOP; - } else { - current_instruction_num = 3; - } - - memcpy(dim_instructions, instructions + i, - current_instruction_num * sizeof(uint32_t)); - - /** fill DIM */ - if (aice_write_dim(coreid, - dim_instructions, - 4) != ERROR_OK) - return ERROR_FAIL; - - /** clear DBGER.DPED */ - if (aice_write_misc(coreid, - NDS_EDM_MISC_DBGER, NDS_DBGER_DPED) != ERROR_OK) - return ERROR_FAIL; - - /** execute DIM */ - if (aice_do_execute(coreid) != ERROR_OK) - return ERROR_FAIL; - - /** check DBGER.DPED */ - if (aice_check_dbger(coreid, NDS_DBGER_DPED) != ERROR_OK) { - - LOG_ERROR("<-- TARGET ERROR! Debug operations do not finish properly:" - "0x%08" PRIx32 " 0x%08" PRIx32 " 0x%08" PRIx32 " 0x%08" PRIx32 ". -->", - dim_instructions[0], - dim_instructions[1], - dim_instructions[2], - dim_instructions[3]); - return ERROR_FAIL; - } - } - - return ERROR_OK; -} - -static int aice_usb_set_custom_srst_script(const char *script) -{ - custom_srst_script = strdup(script); - - return ERROR_OK; -} - -static int aice_usb_set_custom_trst_script(const char *script) -{ - custom_trst_script = strdup(script); - - return ERROR_OK; -} - -static int aice_usb_set_custom_restart_script(const char *script) -{ - custom_restart_script = strdup(script); - - return ERROR_OK; -} - -static int aice_usb_set_count_to_check_dbger(uint32_t count_to_check) -{ - aice_count_to_check_dbger = count_to_check; - - return ERROR_OK; -} - -static int aice_usb_set_data_endian(uint32_t coreid, - enum aice_target_endian target_data_endian) -{ - data_endian = target_data_endian; - - return ERROR_OK; -} - -static int fill_profiling_batch_commands(uint32_t coreid, uint32_t reg_no) -{ - uint32_t dim_instructions[4]; - - aice_usb_set_command_mode(AICE_COMMAND_MODE_BATCH); - - /* halt */ - if (aice_write_misc(coreid, NDS_EDM_MISC_EDM_CMDR, 0) != ERROR_OK) - return ERROR_FAIL; - - /* backup $r0 */ - dim_instructions[0] = MTSR_DTR(0); - dim_instructions[1] = DSB; - dim_instructions[2] = NOP; - dim_instructions[3] = BEQ_MINUS_12; - if (aice_write_dim(coreid, dim_instructions, 4) != ERROR_OK) - return ERROR_FAIL; - aice_read_dtr_to_buffer(coreid, AICE_BATCH_DATA_BUFFER_0); - - /* get samples */ - if (nds32_reg_type(reg_no) == NDS32_REG_TYPE_GPR) { - /* general registers */ - dim_instructions[0] = MTSR_DTR(reg_no); - dim_instructions[1] = DSB; - dim_instructions[2] = NOP; - dim_instructions[3] = BEQ_MINUS_12; - } else if (nds32_reg_type(reg_no) == NDS32_REG_TYPE_SPR) { - /* user special registers */ - dim_instructions[0] = MFUSR_G0(0, nds32_reg_sr_index(reg_no)); - dim_instructions[1] = MTSR_DTR(0); - dim_instructions[2] = DSB; - dim_instructions[3] = BEQ_MINUS_12; - } else { /* system registers */ - dim_instructions[0] = MFSR(0, nds32_reg_sr_index(reg_no)); - dim_instructions[1] = MTSR_DTR(0); - dim_instructions[2] = DSB; - dim_instructions[3] = BEQ_MINUS_12; - } - if (aice_write_dim(coreid, dim_instructions, 4) != ERROR_OK) - return ERROR_FAIL; - aice_read_dtr_to_buffer(coreid, AICE_BATCH_DATA_BUFFER_1); - - /* restore $r0 */ - aice_write_dtr_from_buffer(coreid, AICE_BATCH_DATA_BUFFER_0); - dim_instructions[0] = MFSR_DTR(0); - dim_instructions[1] = DSB; - dim_instructions[2] = NOP; - dim_instructions[3] = IRET; /* free run */ - if (aice_write_dim(coreid, dim_instructions, 4) != ERROR_OK) - return ERROR_FAIL; - - aice_command_mode = AICE_COMMAND_MODE_NORMAL; - - /* use BATCH_BUFFER_WRITE to fill command-batch-buffer */ - if (aice_batch_buffer_write(AICE_BATCH_COMMAND_BUFFER_0, - usb_out_packets_buffer, - (usb_out_packets_buffer_length + 3) / 4) != ERROR_OK) - return ERROR_FAIL; - - usb_out_packets_buffer_length = 0; - usb_in_packets_buffer_length = 0; - - return ERROR_OK; -} - -static int aice_usb_profiling(uint32_t coreid, uint32_t interval, uint32_t iteration, - uint32_t reg_no, uint32_t *samples, uint32_t *num_samples) -{ - uint32_t iteration_count; - uint32_t this_iteration; - int retval = ERROR_OK; - const uint32_t MAX_ITERATION = 250; - - *num_samples = 0; - - /* init DIM size */ - if (aice_write_ctrl(AICE_WRITE_CTRL_BATCH_DIM_SIZE, 4) != ERROR_OK) - return ERROR_FAIL; - - /* Use AICE_BATCH_DATA_BUFFER_0 to read/write $DTR. - * Set it to circular buffer */ - if (aice_write_ctrl(AICE_WRITE_CTRL_BATCH_DATA_BUF0_CTRL, 0xC0000) != ERROR_OK) - return ERROR_FAIL; - - fill_profiling_batch_commands(coreid, reg_no); - - iteration_count = 0; - while (iteration_count < iteration) { - if (iteration - iteration_count < MAX_ITERATION) - this_iteration = iteration - iteration_count; - else - this_iteration = MAX_ITERATION; - - /* set number of iterations */ - uint32_t val_iteration; - val_iteration = interval << 16 | this_iteration; - if (aice_write_ctrl(AICE_WRITE_CTRL_BATCH_ITERATION, - val_iteration) != ERROR_OK) { - retval = ERROR_FAIL; - goto end_profiling; - } - - /* init AICE_WRITE_CTRL_BATCH_DATA_BUF1_CTRL to store $PC */ - if (aice_write_ctrl(AICE_WRITE_CTRL_BATCH_DATA_BUF1_CTRL, - 0x40000) != ERROR_OK) { - retval = ERROR_FAIL; - goto end_profiling; - } - - aice_usb_run(coreid); - - /* enable BATCH command */ - if (aice_write_ctrl(AICE_WRITE_CTRL_BATCH_CTRL, - 0x80000000) != ERROR_OK) { - aice_usb_halt(coreid); - retval = ERROR_FAIL; - goto end_profiling; - } - - /* wait a while (AICE bug, workaround) */ - alive_sleep(this_iteration); - - /* check status */ - uint32_t i; - uint32_t batch_status = 0; - - i = 0; - while (1) { - aice_read_ctrl(AICE_READ_CTRL_BATCH_STATUS, &batch_status); - - if (batch_status & 0x1) { - break; - } else if (batch_status & 0xE) { - aice_usb_halt(coreid); - retval = ERROR_FAIL; - goto end_profiling; - } - - if ((i % 30) == 0) - keep_alive(); - - i++; - } - - aice_usb_halt(coreid); - - /* get samples from batch data buffer */ - if (aice_batch_buffer_read(AICE_BATCH_DATA_BUFFER_1, - samples + iteration_count, this_iteration) != ERROR_OK) { - retval = ERROR_FAIL; - goto end_profiling; - } - - iteration_count += this_iteration; - } - -end_profiling: - *num_samples = iteration_count; - - return retval; -} - -/** */ -struct aice_port_api_s aice_usb_api = { - /** */ - .open = aice_open_device, - /** */ - .close = aice_usb_close, - /** */ - .idcode = aice_usb_idcode, - /** */ - .state = aice_usb_state, - /** */ - .reset = aice_usb_reset, - /** */ - .assert_srst = aice_usb_assert_srst, - /** */ - .run = aice_usb_run, - /** */ - .halt = aice_usb_halt, - /** */ - .step = aice_usb_step, - /** */ - .read_reg = aice_usb_read_reg, - /** */ - .write_reg = aice_usb_write_reg, - /** */ - .read_reg_64 = aice_usb_read_reg_64, - /** */ - .write_reg_64 = aice_usb_write_reg_64, - /** */ - .read_mem_unit = aice_usb_read_memory_unit, - /** */ - .write_mem_unit = aice_usb_write_memory_unit, - /** */ - .read_mem_bulk = aice_usb_bulk_read_mem, - /** */ - .write_mem_bulk = aice_usb_bulk_write_mem, - /** */ - .read_debug_reg = aice_usb_read_debug_reg, - /** */ - .write_debug_reg = aice_usb_write_debug_reg, - /** */ - .set_jtag_clock = aice_usb_set_jtag_clock, - /** */ - .memory_access = aice_usb_memory_access, - /** */ - .memory_mode = aice_usb_memory_mode, - /** */ - .read_tlb = aice_usb_read_tlb, - /** */ - .cache_ctl = aice_usb_cache_ctl, - /** */ - .set_retry_times = aice_usb_set_retry_times, - /** */ - .program_edm = aice_usb_program_edm, - /** */ - .set_command_mode = aice_usb_set_command_mode, - /** */ - .execute = aice_usb_execute, - /** */ - .set_custom_srst_script = aice_usb_set_custom_srst_script, - /** */ - .set_custom_trst_script = aice_usb_set_custom_trst_script, - /** */ - .set_custom_restart_script = aice_usb_set_custom_restart_script, - /** */ - .set_count_to_check_dbger = aice_usb_set_count_to_check_dbger, - /** */ - .set_data_endian = aice_usb_set_data_endian, - /** */ - .profiling = aice_usb_profiling, -}; diff --git a/src/jtag/aice/aice_usb.h b/src/jtag/aice/aice_usb.h deleted file mode 100644 index 04021de3b2..0000000000 --- a/src/jtag/aice/aice_usb.h +++ /dev/null @@ -1,133 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 by Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_JTAG_AICE_AICE_USB_H -#define OPENOCD_JTAG_AICE_AICE_USB_H - -#include "aice_port.h" - -/* AICE USB timeout value */ -#define AICE_USB_TIMEOUT 5000 - -/* AICE USB buffer size */ -#define AICE_IN_BUFFER_SIZE 2048 -#define AICE_OUT_BUFFER_SIZE 2048 -#define AICE_IN_PACKETS_BUFFER_SIZE 2048 -#define AICE_OUT_PACKETS_BUFFER_SIZE 2048 -#define AICE_IN_BATCH_COMMAND_SIZE 512 -#define AICE_OUT_BATCH_COMMAND_SIZE 512 -#define AICE_IN_PACK_COMMAND_SIZE 2048 -#define AICE_OUT_PACK_COMMAND_SIZE 2048 - -/* Constants for AICE command READ_CTRL */ -#define AICE_READ_CTRL_GET_ICE_STATE 0x00 -#define AICE_READ_CTRL_GET_HARDWARE_VERSION 0x01 -#define AICE_READ_CTRL_GET_FPGA_VERSION 0x02 -#define AICE_READ_CTRL_GET_FIRMWARE_VERSION 0x03 -#define AICE_READ_CTRL_GET_JTAG_PIN_STATUS 0x04 -#define AICE_READ_CTRL_BATCH_BUF_INFO 0x22 -#define AICE_READ_CTRL_BATCH_STATUS 0x23 -#define AICE_READ_CTRL_BATCH_BUF0_STATE 0x31 -#define AICE_READ_CTRL_BATCH_BUF4_STATE 0x39 -#define AICE_READ_CTRL_BATCH_BUF5_STATE 0x3b - -/* Constants for AICE command WRITE_CTRL */ -#define AICE_WRITE_CTRL_TCK_CONTROL 0x00 -#define AICE_WRITE_CTRL_JTAG_PIN_CONTROL 0x01 -#define AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS 0x02 -#define AICE_WRITE_CTRL_RESERVED 0x03 -#define AICE_WRITE_CTRL_JTAG_PIN_STATUS 0x04 -#define AICE_WRITE_CTRL_CUSTOM_DELAY 0x0d -#define AICE_WRITE_CTRL_BATCH_CTRL 0x20 -#define AICE_WRITE_CTRL_BATCH_ITERATION 0x21 -#define AICE_WRITE_CTRL_BATCH_DIM_SIZE 0x22 -#define AICE_WRITE_CTRL_BATCH_CMD_BUF0_CTRL 0x30 -#define AICE_WRITE_CTRL_BATCH_DATA_BUF0_CTRL 0x38 -#define AICE_WRITE_CTRL_BATCH_DATA_BUF1_CTRL 0x3a - -#define AICE_BATCH_COMMAND_BUFFER_0 0x0 -#define AICE_BATCH_COMMAND_BUFFER_1 0x1 -#define AICE_BATCH_COMMAND_BUFFER_2 0x2 -#define AICE_BATCH_COMMAND_BUFFER_3 0x3 -#define AICE_BATCH_DATA_BUFFER_0 0x4 -#define AICE_BATCH_DATA_BUFFER_1 0x5 -#define AICE_BATCH_DATA_BUFFER_2 0x6 -#define AICE_BATCH_DATA_BUFFER_3 0x7 - -/* Constants for AICE command WRITE_CTRL:TCK_CONTROL */ -#define AICE_TCK_CONTROL_TCK3048 0x08 -#define AICE_TCK_CONTROL_TCK_SCAN 0x10 - -/* Constants for AICE command WRITE_CTRL:JTAG_PIN_CONTROL */ -#define AICE_JTAG_PIN_CONTROL_SRST 0x01 -#define AICE_JTAG_PIN_CONTROL_TRST 0x02 -#define AICE_JTAG_PIN_CONTROL_STOP 0x04 -#define AICE_JTAG_PIN_CONTROL_RESTART 0x08 - -/* Constants for AICE command WRITE_CTRL:TCK_CONTROL */ -#define AICE_TCK_CONTROL_TCK_SCAN 0x10 - -/* Custom SRST/DBGI/TRST */ -#define AICE_CUSTOM_DELAY_SET_SRST 0x01 -#define AICE_CUSTOM_DELAY_CLEAN_SRST 0x02 -#define AICE_CUSTOM_DELAY_SET_DBGI 0x04 -#define AICE_CUSTOM_DELAY_CLEAN_DBGI 0x08 -#define AICE_CUSTOM_DELAY_SET_TRST 0x10 -#define AICE_CUSTOM_DELAY_CLEAN_TRST 0x20 - -struct aice_usb_handler_s { - unsigned int usb_read_ep; - unsigned int usb_write_ep; - struct libusb_device_handle *usb_handle; -}; - -struct cache_info { - uint32_t set; - uint32_t way; - uint32_t line_size; - - uint32_t log2_set; - uint32_t log2_line_size; -}; - -struct aice_nds32_info { - uint32_t edm_version; - uint32_t r0_backup; - uint32_t r1_backup; - uint32_t host_dtr_backup; - uint32_t target_dtr_backup; - uint32_t edmsw_backup; - uint32_t edm_ctl_backup; - bool debug_under_dex_on; - bool dex_use_psw_on; - bool host_dtr_valid; - bool target_dtr_valid; - enum nds_memory_access access_channel; - enum nds_memory_select memory_select; - enum aice_target_state_s core_state; - bool cache_init; - struct cache_info icache; - struct cache_info dcache; -}; - -extern struct aice_port_api_s aice_usb_api; - -int aice_read_ctrl(uint32_t address, uint32_t *data); -int aice_write_ctrl(uint32_t address, uint32_t data); - -#endif /* OPENOCD_JTAG_AICE_AICE_USB_H */ diff --git a/src/jtag/commands.c b/src/jtag/commands.c index 206c5e8f52..c36c219233 100644 --- a/src/jtag/commands.c +++ b/src/jtag/commands.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -11,19 +13,6 @@ * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -44,7 +33,7 @@ struct cmd_queue_page { static struct cmd_queue_page *cmd_queue_pages; static struct cmd_queue_page *cmd_queue_pages_tail; -struct jtag_command *jtag_command_queue; +static struct jtag_command *jtag_command_queue; static struct jtag_command **next_command_pointer = &jtag_command_queue; void jtag_queue_command(struct jtag_command *cmd) @@ -158,6 +147,11 @@ void jtag_command_queue_reset(void) next_command_pointer = &jtag_command_queue; } +struct jtag_command *jtag_command_queue_get(void) +{ + return jtag_command_queue; +} + /** * Copy a struct scan_field for insertion into the queue. * diff --git a/src/jtag/commands.h b/src/jtag/commands.h index c0375964cd..a1096daa77 100644 --- a/src/jtag/commands.h +++ b/src/jtag/commands.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_COMMANDS_H @@ -160,13 +149,11 @@ struct jtag_command { struct jtag_command *next; }; -/** The current queue of jtag_command_s structures. */ -extern struct jtag_command *jtag_command_queue; - void *cmd_queue_alloc(size_t size); void jtag_queue_command(struct jtag_command *cmd); void jtag_command_queue_reset(void); +struct jtag_command *jtag_command_queue_get(void); void jtag_scan_field_clone(struct scan_field *dst, const struct scan_field *src); enum scan_type jtag_scan_type(const struct scan_command *cmd); diff --git a/src/jtag/core.c b/src/jtag/core.c index bbc9877ee9..c84d5aa3d3 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * @@ -11,19 +13,6 @@ * * * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -147,14 +136,19 @@ int jtag_error_clear(void) /************/ -static bool jtag_poll = 1; +static bool jtag_poll = true; +static bool jtag_poll_en = true; bool is_jtag_poll_safe(void) { /* Polling can be disabled explicitly with set_enabled(false). + * It can also be masked with mask(). * It is also implicitly disabled while TRST is active and * while SRST is gating the JTAG clock. */ + if (!jtag_poll_en) + return false; + if (!transport_is_jtag()) return jtag_poll; @@ -173,6 +167,18 @@ void jtag_poll_set_enabled(bool value) jtag_poll = value; } +bool jtag_poll_mask(void) +{ + bool retval = jtag_poll_en; + jtag_poll_en = false; + return retval; +} + +void jtag_poll_unmask(bool saved) +{ + jtag_poll_en = saved; +} + /************/ struct jtag_tap *jtag_all_taps(void) @@ -945,9 +951,9 @@ int default_interface_jtag_execute_queue(void) return ERROR_OK; } - int result = adapter_driver->jtag_ops->execute_queue(); + struct jtag_command *cmd = jtag_command_queue_get(); + int result = adapter_driver->jtag_ops->execute_queue(cmd); - struct jtag_command *cmd = jtag_command_queue; while (debug_level >= LOG_LVL_DEBUG_IO && cmd) { switch (cmd->type) { case JTAG_SCAN: @@ -1043,7 +1049,7 @@ static int jtag_reset_callback(enum jtag_event event, void *priv) /* current instruction is either BYPASS or IDCODE */ buf_set_ones(tap->cur_instr, tap->ir_length); - tap->bypass = 1; + tap->bypass = true; } return ERROR_OK; @@ -1171,7 +1177,7 @@ static bool jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned ma static bool jtag_examine_chain_match_tap(const struct jtag_tap *tap) { - if (tap->expected_ids_cnt == 0 || !tap->hasidcode) + if (tap->expected_ids_cnt == 0 || !tap->has_idcode) return true; /* optionally ignore the JTAG version field - bits 28-31 of IDCODE */ @@ -1277,13 +1283,13 @@ static int jtag_examine_chain(void) /* Zero for LSB indicates a device in bypass */ LOG_INFO("TAP %s does not have valid IDCODE (idcode=0x%" PRIx32 ")", tap->dotted_name, idcode); - tap->hasidcode = false; + tap->has_idcode = false; tap->idcode = 0; bit_count += 1; } else { /* Friendly devices support IDCODE */ - tap->hasidcode = true; + tap->has_idcode = true; tap->idcode = idcode; jtag_examine_chain_display(LOG_LVL_INFO, "tap/device found", tap->dotted_name, idcode); @@ -1458,7 +1464,7 @@ void jtag_tap_init(struct jtag_tap *tap) buf_set_u32(tap->expected_mask, 0, ir_len_bits, tap->ir_capture_mask); /* TAP will be in bypass mode after jtag_validate_ircapture() */ - tap->bypass = 1; + tap->bypass = true; buf_set_ones(tap->cur_instr, tap->ir_length); /* register the reset callback for the TAP */ diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index 7f0d75c6fc..2a58ac8d5f 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libocdjtagdrivers.la %C%_libocdjtagdrivers_la_LIBADD = @@ -8,8 +10,10 @@ noinst_LTLIBRARIES += %D%/libocdjtagdrivers.la %C%_libocdjtagdrivers_la_CPPFLAGS = $(AM_CPPFLAGS) ULINK_FIRMWARE = %D%/OpenULINK +ANGIE_FILES = %D%/angie EXTRA_DIST += $(ULINK_FIRMWARE) \ + $(ANGIE_FILES) \ %D%/usb_blaster/README.CheapClone \ %D%/Makefile.rlink \ %D%/rlink_call.m4 \ @@ -107,6 +111,9 @@ endif if PRESTO DRIVERFILES += %D%/presto.c endif +if ESP_USB_JTAG +DRIVERFILES += %D%/esp_usb_jtag.c +endif if USBPROG DRIVERFILES += %D%/usbprog.c endif @@ -119,6 +126,12 @@ ulinkdir = $(pkgdatadir)/OpenULINK dist_ulink_DATA = $(ULINK_FIRMWARE)/ulink_firmware.hex %C%_libocdjtagdrivers_la_LIBADD += -lm endif +if ANGIE +DRIVERFILES += %D%/angie.c +angiedir = $(pkgdatadir)/angie +dist_angie_DATA = $(ANGIE_FILES)/angie_firmware.bin $(ANGIE_FILES)/angie_bitstream.bit +%C%_libocdjtagdrivers_la_LIBADD += -lm +endif if VSLLINK DRIVERFILES += %D%/versaloon/usbtoxxx/usbtogpio.c DRIVERFILES += %D%/versaloon/usbtoxxx/usbtojtagraw.c @@ -149,6 +162,9 @@ endif if RSHIM DRIVERFILES += %D%/rshim.c endif +if DMEM +DRIVERFILES += %D%/dmem.c +endif if OSBDM DRIVERFILES += %D%/osbdm.c endif @@ -186,6 +202,9 @@ endif if XDS110 DRIVERFILES += %D%/xds110.c endif +if AM335XGPIO +DRIVERFILES += %D%/am335xgpio.c +endif DRIVERHEADERS = \ %D%/bitbang.h \ diff --git a/src/jtag/drivers/Makefile.rlink b/src/jtag/drivers/Makefile.rlink index 6168332c8c..538228dac8 100644 --- a/src/jtag/drivers/Makefile.rlink +++ b/src/jtag/drivers/Makefile.rlink @@ -1,20 +1,9 @@ -#*************************************************************************** -#* Copyright (C) 2008 Lou Deluxe * -#* lou.openocd012@fixit.nospammail.net * -#* * -#* 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/>. * -#*************************************************************************** +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Copyright (C) 2008 Lou Deluxe +# lou.openocd012@fixit.nospammail.net +# TOP = ../../.. INTERFACE_NAME = rlink diff --git a/src/jtag/drivers/OpenULINK/Makefile b/src/jtag/drivers/OpenULINK/Makefile index 9f6acc660a..d65edcb166 100644 --- a/src/jtag/drivers/OpenULINK/Makefile +++ b/src/jtag/drivers/OpenULINK/Makefile @@ -1,20 +1,9 @@ -############################################################################ -# Copyright (C) 2011 by Martin Schmoelzer # -# <martin.schmoelzer@student.tuwien.ac.at> # -# # -# 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/>. # -############################################################################ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Copyright (C) 2011 by Martin Schmoelzer +# <martin.schmoelzer@student.tuwien.ac.at> +# # Define the name of our tools. Some distributions (e. g. Fedora) prefix # the SDCC executables, change this accordingly! diff --git a/src/jtag/drivers/OpenULINK/include/common.h b/src/jtag/drivers/OpenULINK/include/common.h index 56222fe6c7..8f41fd078c 100644 --- a/src/jtag/drivers/OpenULINK/include/common.h +++ b/src/jtag/drivers/OpenULINK/include/common.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * - * * - * 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/>. * ***************************************************************************/ #ifndef __COMMON_H diff --git a/src/jtag/drivers/OpenULINK/include/delay.h b/src/jtag/drivers/OpenULINK/include/delay.h index ed454be9b5..be0d762ba1 100644 --- a/src/jtag/drivers/OpenULINK/include/delay.h +++ b/src/jtag/drivers/OpenULINK/include/delay.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * - * * - * 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/>. * ***************************************************************************/ #ifndef __DELAY_H diff --git a/src/jtag/drivers/OpenULINK/include/io.h b/src/jtag/drivers/OpenULINK/include/io.h index 497c235a25..1330ebdfa0 100644 --- a/src/jtag/drivers/OpenULINK/include/io.h +++ b/src/jtag/drivers/OpenULINK/include/io.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * - * * - * 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/>. * ***************************************************************************/ #ifndef __IO_H diff --git a/src/jtag/drivers/OpenULINK/include/jtag.h b/src/jtag/drivers/OpenULINK/include/jtag.h index fa492b9ed3..1b5c3af15e 100644 --- a/src/jtag/drivers/OpenULINK/include/jtag.h +++ b/src/jtag/drivers/OpenULINK/include/jtag.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * - * * - * 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/>. * ***************************************************************************/ #ifndef __JTAG_H diff --git a/src/jtag/drivers/OpenULINK/include/main.h b/src/jtag/drivers/OpenULINK/include/main.h index 9e7dd5a868..d399c33961 100644 --- a/src/jtag/drivers/OpenULINK/include/main.h +++ b/src/jtag/drivers/OpenULINK/include/main.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * - * * - * 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/>. * ***************************************************************************/ #ifndef __MAIN_H diff --git a/src/jtag/drivers/OpenULINK/include/msgtypes.h b/src/jtag/drivers/OpenULINK/include/msgtypes.h index f761a845f1..ae61ddbf90 100644 --- a/src/jtag/drivers/OpenULINK/include/msgtypes.h +++ b/src/jtag/drivers/OpenULINK/include/msgtypes.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * - * * - * 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/>. * ***************************************************************************/ /** diff --git a/src/jtag/drivers/OpenULINK/include/protocol.h b/src/jtag/drivers/OpenULINK/include/protocol.h index 0b6a7d67dd..91b5640335 100644 --- a/src/jtag/drivers/OpenULINK/include/protocol.h +++ b/src/jtag/drivers/OpenULINK/include/protocol.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * - * * - * 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/>. * ***************************************************************************/ #ifndef __PROTOCOL_H diff --git a/src/jtag/drivers/OpenULINK/include/reg_ezusb.h b/src/jtag/drivers/OpenULINK/include/reg_ezusb.h index 4988367db0..6c38ab6ea4 100644 --- a/src/jtag/drivers/OpenULINK/include/reg_ezusb.h +++ b/src/jtag/drivers/OpenULINK/include/reg_ezusb.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * - * * - * 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/>. * ***************************************************************************/ #ifndef REG_EZUSB_H diff --git a/src/jtag/drivers/OpenULINK/include/usb.h b/src/jtag/drivers/OpenULINK/include/usb.h index 9a261fed00..30968b3e28 100644 --- a/src/jtag/drivers/OpenULINK/include/usb.h +++ b/src/jtag/drivers/OpenULINK/include/usb.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * - * * - * 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/>. * ***************************************************************************/ #ifndef __USB_H diff --git a/src/jtag/drivers/OpenULINK/src/USBJmpTb.a51 b/src/jtag/drivers/OpenULINK/src/USBJmpTb.a51 index f10ad484f9..f62508b7ed 100644 --- a/src/jtag/drivers/OpenULINK/src/USBJmpTb.a51 +++ b/src/jtag/drivers/OpenULINK/src/USBJmpTb.a51 @@ -1,20 +1,9 @@ -;--------------------------------------------------------------------------; -; Copyright (C) 2011-2013 by Martin Schmoelzer ; -; <martin.schmoelzer@student.tuwien.ac.at> ; -; ; -; 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/>. ; -;--------------------------------------------------------------------------; +; SPDX-License-Identifier: GPL-2.0-or-later + +; +; Copyright (C) 2011-2013 by Martin Schmoelzer +; <martin.schmoelzer@student.tuwien.ac.at> +; .module JUMPTABLE .globl USB_AutoVector diff --git a/src/jtag/drivers/OpenULINK/src/delay.c b/src/jtag/drivers/OpenULINK/src/delay.c index 326056768e..b68e8148a8 100644 --- a/src/jtag/drivers/OpenULINK/src/delay.c +++ b/src/jtag/drivers/OpenULINK/src/delay.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * - * * - * 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/>. * ***************************************************************************/ #include "delay.h" diff --git a/src/jtag/drivers/OpenULINK/src/jtag.c b/src/jtag/drivers/OpenULINK/src/jtag.c index c76f034e8c..c9253a3414 100644 --- a/src/jtag/drivers/OpenULINK/src/jtag.c +++ b/src/jtag/drivers/OpenULINK/src/jtag.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * - * * - * 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/>. * ***************************************************************************/ #include "jtag.h" diff --git a/src/jtag/drivers/OpenULINK/src/main.c b/src/jtag/drivers/OpenULINK/src/main.c index f331c9ebf8..51d3a3b947 100644 --- a/src/jtag/drivers/OpenULINK/src/main.c +++ b/src/jtag/drivers/OpenULINK/src/main.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * - * * - * 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/>. * ***************************************************************************/ #include "main.h" diff --git a/src/jtag/drivers/OpenULINK/src/protocol.c b/src/jtag/drivers/OpenULINK/src/protocol.c index f8f84ed48a..b3d562236d 100644 --- a/src/jtag/drivers/OpenULINK/src/protocol.c +++ b/src/jtag/drivers/OpenULINK/src/protocol.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * - * * - * 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/>. * ***************************************************************************/ #include "protocol.h" diff --git a/src/jtag/drivers/OpenULINK/src/usb.c b/src/jtag/drivers/OpenULINK/src/usb.c index 032b23b579..408e212178 100644 --- a/src/jtag/drivers/OpenULINK/src/usb.c +++ b/src/jtag/drivers/OpenULINK/src/usb.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011-2013 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * - * * - * 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/>. * ***************************************************************************/ /** diff --git a/src/jtag/drivers/am335xgpio.c b/src/jtag/drivers/am335xgpio.c new file mode 100644 index 0000000000..cfe41c3be5 --- /dev/null +++ b/src/jtag/drivers/am335xgpio.c @@ -0,0 +1,509 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Steve Marple, stevemarple@googlemail.com * + * * + * Based on bcm2835gpio.c and linuxgpiod.c * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <jtag/adapter.h> +#include <jtag/interface.h> +#include <transport/transport.h> +#include "bitbang.h" + +#include <sys/mman.h> + +/* GPIO register base addresses. Values taken from "AM335x and AMIC110 Sitara + * Processors Technical Reference Manual", Chapter 2 Memory Map. + */ +#define AM335XGPIO_NUM_GPIO_PER_CHIP 32 +#define AM335XGPIO_NUM_GPIO_CHIPS 4 +#define AM335XGPIO_GPIO0_HW_ADDR 0x44E07000 +#define AM335XGPIO_GPIO1_HW_ADDR 0x4804C000 +#define AM335XGPIO_GPIO2_HW_ADDR 0x481AC000 +#define AM335XGPIO_GPIO3_HW_ADDR 0x481AE000 + +/* 32-bit offsets from GPIO chip base address. Values taken from "AM335x and + * AMIC110 Sitara Processors Technical Reference Manual", Chapter 25 + * General-Purpose Input/Output. + */ +#define AM335XGPIO_GPIO_OE_OFFSET (0x134 / 4) +#define AM335XGPIO_GPIO_DATAIN_OFFSET (0x138 / 4) +#define AM335XGPIO_GPIO_DATAOUT_OFFSET (0x13C / 4) /* DATAOUT register uses 0 for output, 1 for input */ +#define AM335XGPIO_GPIO_CLEARDATAOUT_OFFSET (0x190 / 4) +#define AM335XGPIO_GPIO_SETDATAOUT_OFFSET (0x194 / 4) + +#define AM335XGPIO_READ_REG(chip_num, offset) \ + (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset))) + +#define AM335XGPIO_WRITE_REG(chip_num, offset, value) \ + (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset)) = (value)) + +#define AM335XGPIO_SET_REG_BITS(chip_num, offset, bit_mask) \ + (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset)) |= (bit_mask)) + +#define AM335XGPIO_CLEAR_REG_BITS(chip_num, offset, bit_mask) \ + (*(am335xgpio_gpio_chip_mmap_addr[(chip_num)] + (offset)) &= ~(bit_mask)) + +#define AM335XGPIO_SET_INPUT(gpio_config) \ + AM335XGPIO_SET_REG_BITS((gpio_config)->chip_num, AM335XGPIO_GPIO_OE_OFFSET, BIT((gpio_config)->gpio_num)) +#define AM335XGPIO_SET_OUTPUT(gpio_config) \ + AM335XGPIO_CLEAR_REG_BITS((gpio_config)->chip_num, AM335XGPIO_GPIO_OE_OFFSET, BIT((gpio_config)->gpio_num)) +#define AM335XGPIO_SET_HIGH(gpio_config) \ + AM335XGPIO_WRITE_REG((gpio_config)->chip_num, AM335XGPIO_GPIO_SETDATAOUT_OFFSET, BIT((gpio_config)->gpio_num)) +#define AM335XGPIO_SET_LOW(gpio_config) \ + AM335XGPIO_WRITE_REG((gpio_config)->chip_num, AM335XGPIO_GPIO_CLEARDATAOUT_OFFSET, BIT((gpio_config)->gpio_num)) + +enum amx335gpio_initial_gpio_mode { + AM335XGPIO_GPIO_MODE_INPUT, + AM335XGPIO_GPIO_MODE_OUTPUT_LOW, + AM335XGPIO_GPIO_MODE_OUTPUT_HIGH, +}; + +static const uint32_t am335xgpio_gpio_chip_hw_addr[AM335XGPIO_NUM_GPIO_CHIPS] = { + AM335XGPIO_GPIO0_HW_ADDR, + AM335XGPIO_GPIO1_HW_ADDR, + AM335XGPIO_GPIO2_HW_ADDR, + AM335XGPIO_GPIO3_HW_ADDR, +}; + +/* Memory-mapped address pointers */ +static volatile uint32_t *am335xgpio_gpio_chip_mmap_addr[AM335XGPIO_NUM_GPIO_CHIPS]; + +static int dev_mem_fd; +static enum amx335gpio_initial_gpio_mode initial_gpio_mode[ADAPTER_GPIO_IDX_NUM]; + +/* Transition delay coefficients */ +static int speed_coeff = 600000; +static int speed_offset = 575; +static unsigned int jtag_delay; + +static const struct adapter_gpio_config *adapter_gpio_config; + +static bool is_gpio_config_valid(const struct adapter_gpio_config *gpio_config) +{ + return gpio_config->chip_num < AM335XGPIO_NUM_GPIO_CHIPS + && gpio_config->gpio_num < AM335XGPIO_NUM_GPIO_PER_CHIP; +} + +static int get_gpio_value(const struct adapter_gpio_config *gpio_config) +{ + unsigned int shift = gpio_config->gpio_num; + uint32_t value = AM335XGPIO_READ_REG(gpio_config->chip_num, AM335XGPIO_GPIO_DATAIN_OFFSET); + value = (value >> shift) & 1; + return value ^ (gpio_config->active_low ? 1 : 0); +} + +static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int value) +{ + value = value ^ (gpio_config->active_low ? 1 : 0); + switch (gpio_config->drive) { + case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL: + if (value) + AM335XGPIO_SET_HIGH(gpio_config); + else + AM335XGPIO_SET_LOW(gpio_config); + /* For performance reasons assume the GPIO is already set as an output + * and therefore the call can be omitted here. + */ + break; + case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN: + if (value) { + AM335XGPIO_SET_INPUT(gpio_config); + } else { + AM335XGPIO_SET_LOW(gpio_config); + AM335XGPIO_SET_OUTPUT(gpio_config); + } + break; + case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE: + if (value) { + AM335XGPIO_SET_HIGH(gpio_config); + AM335XGPIO_SET_OUTPUT(gpio_config); + } else { + AM335XGPIO_SET_INPUT(gpio_config); + } + break; + } +} + +static enum amx335gpio_initial_gpio_mode get_gpio_mode(const struct adapter_gpio_config *gpio_config) +{ + if (AM335XGPIO_READ_REG(gpio_config->chip_num, AM335XGPIO_GPIO_OE_OFFSET) & BIT(gpio_config->gpio_num)) + return AM335XGPIO_GPIO_MODE_INPUT; + + /* Return output level too so that pin mode can be fully restored */ + if (AM335XGPIO_READ_REG(gpio_config->chip_num, AM335XGPIO_GPIO_DATAOUT_OFFSET) & BIT(gpio_config->gpio_num)) + return AM335XGPIO_GPIO_MODE_OUTPUT_HIGH; + return AM335XGPIO_GPIO_MODE_OUTPUT_LOW; +} + +static const char *get_gpio_mode_name(enum amx335gpio_initial_gpio_mode gpio_mode) +{ + switch (gpio_mode) { + case AM335XGPIO_GPIO_MODE_INPUT: + return "input"; + case AM335XGPIO_GPIO_MODE_OUTPUT_LOW: + return "output (low)"; + case AM335XGPIO_GPIO_MODE_OUTPUT_HIGH: + return "output (high)"; + } + return "unknown"; +} + +static void initialize_gpio(enum adapter_gpio_config_index idx) +{ + if (!is_gpio_config_valid(&adapter_gpio_config[idx])) + return; + + initial_gpio_mode[idx] = get_gpio_mode(&adapter_gpio_config[idx]); + LOG_DEBUG("saved GPIO mode for %s (GPIO %d %d): %s", + adapter_gpio_get_name(idx), adapter_gpio_config[idx].chip_num, adapter_gpio_config[idx].gpio_num, + get_gpio_mode_name(initial_gpio_mode[idx])); + + if (adapter_gpio_config[idx].pull != ADAPTER_GPIO_PULL_NONE) { + LOG_WARNING("am335xgpio does not support pull-up or pull-down settings (signal %s)", + adapter_gpio_get_name(idx)); + } + + switch (adapter_gpio_config[idx].init_state) { + case ADAPTER_GPIO_INIT_STATE_INACTIVE: + set_gpio_value(&adapter_gpio_config[idx], 0); + break; + case ADAPTER_GPIO_INIT_STATE_ACTIVE: + set_gpio_value(&adapter_gpio_config[idx], 1); + break; + case ADAPTER_GPIO_INIT_STATE_INPUT: + AM335XGPIO_SET_INPUT(&adapter_gpio_config[idx]); + break; + } + + /* Direction for non push-pull is already set by set_gpio_value() */ + if (adapter_gpio_config[idx].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL + && adapter_gpio_config[idx].init_state != ADAPTER_GPIO_INIT_STATE_INPUT) + AM335XGPIO_SET_OUTPUT(&adapter_gpio_config[idx]); +} + +static void restore_gpio(enum adapter_gpio_config_index idx) +{ + if (is_gpio_config_valid(&adapter_gpio_config[idx])) { + switch (initial_gpio_mode[idx]) { + case AM335XGPIO_GPIO_MODE_INPUT: + AM335XGPIO_SET_INPUT(&adapter_gpio_config[idx]); + break; + case AM335XGPIO_GPIO_MODE_OUTPUT_LOW: + AM335XGPIO_SET_LOW(&adapter_gpio_config[idx]); + AM335XGPIO_SET_OUTPUT(&adapter_gpio_config[idx]); + break; + case AM335XGPIO_GPIO_MODE_OUTPUT_HIGH: + AM335XGPIO_SET_HIGH(&adapter_gpio_config[idx]); + AM335XGPIO_SET_OUTPUT(&adapter_gpio_config[idx]); + break; + } + } +} + +static bb_value_t am335xgpio_read(void) +{ + return get_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TDO]) ? BB_HIGH : BB_LOW; +} + +static int am335xgpio_write(int tck, int tms, int tdi) +{ + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TDI], tdi); + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TMS], tms); + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TCK], tck); /* Write clock last */ + + for (unsigned int i = 0; i < jtag_delay; ++i) + asm volatile (""); + + return ERROR_OK; +} + +static int am335xgpio_swd_write(int swclk, int swdio) +{ + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO], swdio); + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK], swclk); /* Write clock last */ + + for (unsigned int i = 0; i < jtag_delay; ++i) + asm volatile (""); + + return ERROR_OK; +} + +/* (1) assert or (0) deassert reset lines */ +static int am335xgpio_reset(int trst, int srst) +{ + /* As the "adapter reset_config" command keeps the srst and trst gpio drive + * mode settings in sync we can use our standard set_gpio_value() function + * that honours drive mode and active low. + */ + if (is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_SRST])) + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SRST], srst); + + if (is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_TRST])) + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TRST], trst); + + LOG_DEBUG("trst %d gpio: %d %d, srst %d gpio: %d %d", + trst, + (int)adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].chip_num, + (int)adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].gpio_num, + srst, + (int)adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].chip_num, + (int)adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].gpio_num); + return ERROR_OK; +} + +static void am335xgpio_swdio_drive(bool is_output) +{ + if (is_output) { + if (is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR])) + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 1); + AM335XGPIO_SET_OUTPUT(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO]); + } else { + AM335XGPIO_SET_INPUT(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO]); + if (is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR])) + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 0); + } +} + +static int am335xgpio_swdio_read(void) +{ + return get_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO]); +} + +static int am335xgpio_blink(int on) +{ + if (is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_LED])) + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_LED], on); + + return ERROR_OK; +} + +static struct bitbang_interface am335xgpio_bitbang = { + .read = am335xgpio_read, + .write = am335xgpio_write, + .swdio_read = am335xgpio_swdio_read, + .swdio_drive = am335xgpio_swdio_drive, + .swd_write = am335xgpio_swd_write, + .blink = am335xgpio_blink +}; + +static int am335xgpio_khz(int khz, int *jtag_speed) +{ + if (!khz) { + LOG_DEBUG("RCLK not supported"); + return ERROR_FAIL; + } + *jtag_speed = speed_coeff / khz - speed_offset; + if (*jtag_speed < 0) + *jtag_speed = 0; + return ERROR_OK; +} + +static int am335xgpio_speed_div(int speed, int *khz) +{ + *khz = speed_coeff / (speed + speed_offset); + return ERROR_OK; +} + +static int am335xgpio_speed(int speed) +{ + jtag_delay = speed; + return ERROR_OK; +} + +COMMAND_HANDLER(am335xgpio_handle_speed_coeffs) +{ + if (CMD_ARGC == 2) { + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset); + } + + command_print(CMD, "AM335x GPIO config: speed_coeffs = %d, speed_offset = %d", + speed_coeff, speed_offset); + return ERROR_OK; +} + +static const struct command_registration am335xgpio_subcommand_handlers[] = { + { + .name = "speed_coeffs", + .handler = am335xgpio_handle_speed_coeffs, + .mode = COMMAND_CONFIG, + .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.", + .usage = "[SPEED_COEFF SPEED_OFFSET]", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration am335xgpio_command_handlers[] = { + { + .name = "am335xgpio", + .mode = COMMAND_ANY, + .help = "perform am335xgpio management", + .chain = am335xgpio_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static const char * const am335xgpio_transports[] = { "jtag", "swd", NULL }; + +static struct jtag_interface am335xgpio_interface = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = bitbang_execute_queue, +}; + +static bool am335xgpio_jtag_mode_possible(void) +{ + if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_TCK])) + return false; + if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_TMS])) + return false; + if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_TDI])) + return false; + if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_TDO])) + return false; + return true; +} + +static bool am335xgpio_swd_mode_possible(void) +{ + if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK])) + return false; + if (!is_gpio_config_valid(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO])) + return false; + return true; +} + +static void am335xgpio_munmap(void) +{ + for (unsigned int i = 0; i < AM335XGPIO_NUM_GPIO_CHIPS && am335xgpio_gpio_chip_mmap_addr[i] != MAP_FAILED; ++i) + if (munmap((void *)am335xgpio_gpio_chip_mmap_addr[i], sysconf(_SC_PAGE_SIZE)) < 0) + LOG_ERROR("Cannot unmap GPIO memory for chip %d: %s", i, strerror(errno)); +} + +static int am335xgpio_init(void) +{ + LOG_INFO("AM335x GPIO JTAG/SWD bitbang driver"); + + bitbang_interface = &am335xgpio_bitbang; + adapter_gpio_config = adapter_gpio_get_config(); + + if (transport_is_jtag() && !am335xgpio_jtag_mode_possible()) { + LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode"); + return ERROR_JTAG_INIT_FAILED; + } + + if (transport_is_swd() && !am335xgpio_swd_mode_possible()) { + LOG_ERROR("Require swclk and swdio gpio for SWD mode"); + return ERROR_JTAG_INIT_FAILED; + } + + dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC); + if (dev_mem_fd < 0) { + LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem"); + dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC); + } + if (dev_mem_fd < 0) { + LOG_ERROR("open: %s", strerror(errno)); + return ERROR_JTAG_INIT_FAILED; + } + + for (unsigned int i = 0; i < AM335XGPIO_NUM_GPIO_CHIPS; ++i) { + am335xgpio_gpio_chip_mmap_addr[i] = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE, + MAP_SHARED, dev_mem_fd, am335xgpio_gpio_chip_hw_addr[i]); + + if (am335xgpio_gpio_chip_mmap_addr[i] == MAP_FAILED) { + LOG_ERROR("mmap: %s", strerror(errno)); + am335xgpio_munmap(); + close(dev_mem_fd); + return ERROR_JTAG_INIT_FAILED; + } + } + close(dev_mem_fd); + + /* Configure JTAG/SWD signals. Default directions and initial states are handled + * by adapter.c and "adapter gpio" command. + */ + if (transport_is_jtag()) { + initialize_gpio(ADAPTER_GPIO_IDX_TDO); + initialize_gpio(ADAPTER_GPIO_IDX_TDI); + initialize_gpio(ADAPTER_GPIO_IDX_TMS); + initialize_gpio(ADAPTER_GPIO_IDX_TCK); + initialize_gpio(ADAPTER_GPIO_IDX_TRST); + } + + if (transport_is_swd()) { + /* swdio and its buffer should be initialized in the order that prevents + * two outputs from being connected together. This will occur if the + * swdio GPIO of the AM335x is configured as an output while its + * external buffer is configured to send the swdio signal from the + * target to the AM335x. + */ + if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].init_state == ADAPTER_GPIO_INIT_STATE_INPUT) { + initialize_gpio(ADAPTER_GPIO_IDX_SWDIO); + initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR); + } else { + initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR); + initialize_gpio(ADAPTER_GPIO_IDX_SWDIO); + } + + initialize_gpio(ADAPTER_GPIO_IDX_SWCLK); + } + + initialize_gpio(ADAPTER_GPIO_IDX_SRST); + initialize_gpio(ADAPTER_GPIO_IDX_LED); + + return ERROR_OK; +} + +static int am335xgpio_quit(void) +{ + if (transport_is_jtag()) { + restore_gpio(ADAPTER_GPIO_IDX_TDO); + restore_gpio(ADAPTER_GPIO_IDX_TDI); + restore_gpio(ADAPTER_GPIO_IDX_TMS); + restore_gpio(ADAPTER_GPIO_IDX_TCK); + restore_gpio(ADAPTER_GPIO_IDX_TRST); + } + + if (transport_is_swd()) { + /* Restore swdio/swdio_dir to their initial modes, even if that means + * connecting two outputs. Begin by making swdio an input so that the + * current and final states of swdio and swdio_dir do not have to be + * considered to calculate the safe restoration order. + */ + AM335XGPIO_SET_INPUT(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO]); + restore_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR); + restore_gpio(ADAPTER_GPIO_IDX_SWDIO); + + restore_gpio(ADAPTER_GPIO_IDX_SWCLK); + } + + restore_gpio(ADAPTER_GPIO_IDX_SRST); + restore_gpio(ADAPTER_GPIO_IDX_LED); + + am335xgpio_munmap(); + + return ERROR_OK; +} + +struct adapter_driver am335xgpio_adapter_driver = { + .name = "am335xgpio", + .transports = am335xgpio_transports, + .commands = am335xgpio_command_handlers, + + .init = am335xgpio_init, + .quit = am335xgpio_quit, + .reset = am335xgpio_reset, + .speed = am335xgpio_speed, + .khz = am335xgpio_khz, + .speed_div = am335xgpio_speed_div, + + .jtag_ops = &am335xgpio_interface, + .swd_ops = &bitbang_swd, +}; diff --git a/src/jtag/drivers/amt_jtagaccel.c b/src/jtag/drivers/amt_jtagaccel.c index c204f237af..b28ce62ffb 100644 --- a/src/jtag/drivers/amt_jtagaccel.c +++ b/src/jtag/drivers/amt_jtagaccel.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -328,9 +317,9 @@ static void amt_jtagaccel_scan(bool ir_scan, enum scan_type type, uint8_t *buffe tap_set_state(tap_get_end_state()); } -static int amt_jtagaccel_execute_queue(void) +static int amt_jtagaccel_execute_queue(struct jtag_command *cmd_queue) { - struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ + struct jtag_command *cmd = cmd_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; diff --git a/src/jtag/drivers/angie.c b/src/jtag/drivers/angie.c new file mode 100644 index 0000000000..c024667bdb --- /dev/null +++ b/src/jtag/drivers/angie.c @@ -0,0 +1,2400 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*************************************************************************** + File : angie.c * + Contents : OpenOCD driver code for NanoXplore USB-JTAG ANGIE * + adapter hardware. * + Based on openULINK driver code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + <aboudjelida@nanoxplore.com> * + <ahmederrachedbjld@gmail.com> * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include "helper/system.h" +#include <helper/types.h> +#include <jtag/interface.h> +#include <jtag/commands.h> +#include <target/image.h> +#include <libusb.h> +#include "libusb_helper.h" +#include "angie/include/msgtypes.h" + +/** USB Vendor ID of ANGIE device in unconfigured state (no firmware loaded + * yet) or with its firmware. */ +#define ANGIE_VID 0x584e + +/** USB Product ID of ANGIE device in unconfigured state (no firmware loaded + * yet) or with its firmware. */ +#define ANGIE_PID 0x414F +#define ANGIE_PID_2 0x424e +#define ANGIE_PID_3 0x4255 +#define ANGIE_PID_4 0x4355 +#define ANGIE_PID_5 0x4a55 + +/** Address of EZ-USB ANGIE CPU Control & Status register. This register can be + * written by issuing a Control EP0 vendor request. */ +#define CPUCS_REG 0xE600 + +/** USB Control EP0 bRequest: "Firmware Load". */ +#define REQUEST_FIRMWARE_LOAD 0xA0 + +/** Value to write into CPUCS to put EZ-USB ANGIE into reset. */ +#define CPU_RESET 0x01 + +/** Value to write into CPUCS to put EZ-USB ANGIE out of reset. */ +#define CPU_START 0x00 + +/** Base address of firmware in EZ-USB ANGIE code space. */ +#define FIRMWARE_ADDR 0x0000 + +/** USB interface number */ +#define USB_INTERFACE 0 + +/** Delay (in microseconds) to wait while EZ-USB performs ReNumeration. */ +#define ANGIE_RENUMERATION_DELAY_US 1500000 + +/** Default location of ANGIE firmware image. */ +#define ANGIE_FIRMWARE_FILE PKGDATADIR "/angie/angie_firmware.bin" + +/** Default location of ANGIE firmware image. */ +#define ANGIE_BITSTREAM_FILE PKGDATADIR "/angie/angie_bitstream.bit" + +/** Maximum size of a single firmware section. Entire EZ-USB ANGIE code space = 16kB */ +#define SECTION_BUFFERSIZE 16384 + +/** Tuning of OpenOCD SCAN commands split into multiple ANGIE commands. */ +#define SPLIT_SCAN_THRESHOLD 10 + +/** ANGIE hardware type */ +enum angie_type { + ANGIE, +}; + +enum angie_payload_direction { + PAYLOAD_DIRECTION_OUT, + PAYLOAD_DIRECTION_IN +}; + +enum angie_delay_type { + DELAY_CLOCK_TCK, + DELAY_CLOCK_TMS, + DELAY_SCAN_IN, + DELAY_SCAN_OUT, + DELAY_SCAN_IO +}; + +/** + * ANGIE command (ANGIE command queue element). + * + * For the OUT direction payload, things are quite easy: Payload is stored + * in a rather small array (up to 63 bytes), the payload is always allocated + * by the function generating the command and freed by angie_clear_queue(). + * + * For the IN direction payload, things get a little bit more complicated: + * The maximum IN payload size for a single command is 64 bytes. Assume that + * a single OpenOCD command needs to scan 256 bytes. This results in the + * generation of four ANGIE commands. The function generating these + * commands shall allocate an uint8_t[256] array. Each command's #payload_in + * pointer shall point to the corresponding offset where IN data shall be + * placed, while #payload_in_start shall point to the first element of the 256 + * byte array. + * - first command: #payload_in_start + 0 + * - second command: #payload_in_start + 64 + * - third command: #payload_in_start + 128 + * - fourth command: #payload_in_start + 192 + * + * The last command sets #needs_postprocessing to true. + */ +struct angie_cmd { + uint8_t id; /**< ANGIE command ID */ + + uint8_t *payload_out; /**< Pointer where OUT payload shall be stored */ + uint8_t payload_out_size; /**< OUT direction payload size for this command */ + + uint8_t *payload_in_start; /**< Pointer to first element of IN payload array */ + uint8_t *payload_in; /**< Pointer where IN payload shall be stored */ + uint8_t payload_in_size; /**< IN direction payload size for this command */ + + /** Indicates if this command needs post-processing */ + bool needs_postprocessing; + + /** Indicates if angie_clear_queue() should free payload_in_start */ + bool free_payload_in_start; + + /** Pointer to corresponding OpenOCD command for post-processing */ + struct jtag_command *cmd_origin; + + struct angie_cmd *next; /**< Pointer to next command (linked list) */ +}; + +/** Describes one driver instance */ +struct angie { + struct libusb_context *libusb_ctx; + struct libusb_device_handle *usb_device_handle; + enum angie_type type; + + unsigned int ep_in; /**< IN endpoint number */ + unsigned int ep_out; /**< OUT endpoint number */ + + /* delay value for "SLOW_CLOCK commands" in [0:255] range in units of 4 us; + -1 means no need for delay */ + int delay_scan_in; /**< Delay value for SCAN_IN commands */ + int delay_scan_out; /**< Delay value for SCAN_OUT commands */ + int delay_scan_io; /**< Delay value for SCAN_IO commands */ + int delay_clock_tck; /**< Delay value for CLOCK_TMS commands */ + int delay_clock_tms; /**< Delay value for CLOCK_TCK commands */ + + int commands_in_queue; /**< Number of commands in queue */ + struct angie_cmd *queue_start; /**< Pointer to first command in queue */ + struct angie_cmd *queue_end; /**< Pointer to last command in queue */ +}; + +/**************************** Function Prototypes *****************************/ + +/* USB helper functions */ +static int angie_usb_open(struct angie *device); +static int angie_usb_close(struct angie *device); + +/* ANGIE MCU (Cypress EZ-USB) specific functions */ +static int angie_cpu_reset(struct angie *device, char reset_bit); +static int angie_load_firmware_and_renumerate(struct angie *device, const char *filename, + uint32_t delay_us); +static int angie_load_firmware(struct angie *device, const char *filename); +static int angie_load_bitstream(struct angie *device, const char *filename); +static int angie_i2c_write(struct angie *device, uint8_t *i2c_data, uint8_t i2c_data_size); +static int angie_io_extender_config(struct angie *device, uint8_t i2c_adr, uint8_t cfg_value); +static int angie_write_firmware_section(struct angie *device, + struct image *firmware_image, int section_index); + +/* Generic helper functions */ +static void angie_dump_signal_states(uint8_t input_signals, uint8_t output_signals); + +/* ANGIE command generation helper functions */ +static int angie_allocate_payload(struct angie_cmd *angie_cmd, int size, + enum angie_payload_direction direction); + +/* ANGIE command queue helper functions */ +static int angie_get_queue_size(struct angie *device, + enum angie_payload_direction direction); +static void angie_clear_queue(struct angie *device); +static int angie_append_queue(struct angie *device, struct angie_cmd *angie_cmd); +static int angie_execute_queued_commands(struct angie *device, int timeout_ms); + +static void angie_dump_queue(struct angie *device); + +static int angie_append_scan_cmd(struct angie *device, + enum scan_type scan_type, + int scan_size_bits, + uint8_t *tdi, + uint8_t *tdo_start, + uint8_t *tdo, + uint8_t tms_count_start, + uint8_t tms_sequence_start, + uint8_t tms_count_end, + uint8_t tms_sequence_end, + struct jtag_command *origin, + bool postprocess); +static int angie_append_clock_tms_cmd(struct angie *device, uint8_t count, + uint8_t sequence); +static int angie_append_clock_tck_cmd(struct angie *device, uint16_t count); +static int angie_append_get_signals_cmd(struct angie *device); +static int angie_append_set_signals_cmd(struct angie *device, uint8_t low, + uint8_t high); +static int angie_append_sleep_cmd(struct angie *device, uint32_t us); +static int angie_append_configure_tck_cmd(struct angie *device, + int delay_scan_in, + int delay_scan_out, + int delay_scan_io, + int delay_tck, + int delay_tms); +static int angie_append_test_cmd(struct angie *device); + +/* ANGIE TCK frequency helper functions */ +static int angie_calculate_delay(enum angie_delay_type type, long f, int *delay); + +/* Interface between ANGIE and OpenOCD */ +static void angie_set_end_state(tap_state_t endstate); +static int angie_queue_statemove(struct angie *device); + +static int angie_queue_scan(struct angie *device, struct jtag_command *cmd); +static int angie_queue_tlr_reset(struct angie *device, struct jtag_command *cmd); +static int angie_queue_runtest(struct angie *device, struct jtag_command *cmd); +static int angie_queue_pathmove(struct angie *device, struct jtag_command *cmd); +static int angie_queue_sleep(struct angie *device, struct jtag_command *cmd); +static int angie_queue_stableclocks(struct angie *device, struct jtag_command *cmd); + +static int angie_post_process_scan(struct angie_cmd *angie_cmd); +static int angie_post_process_queue(struct angie *device); + +/* adapter driver functions */ +static int angie_execute_queue(struct jtag_command *cmd_queue); +static int angie_khz(int khz, int *jtag_speed); +static int angie_speed(int speed); +static int angie_speed_div(int speed, int *khz); +static int angie_init(void); +static int angie_quit(void); +static int angie_reset(int trst, int srst); + +/****************************** Global Variables ******************************/ + +static struct angie *angie_handle; + +/**************************** USB helper functions ****************************/ + +/** + * Opens the ANGIE device + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_usb_open(struct angie *device) +{ + struct libusb_device_handle *usb_device_handle; + const uint16_t vids[] = {ANGIE_VID, ANGIE_VID, ANGIE_VID, ANGIE_VID, ANGIE_VID, 0}; + const uint16_t pids[] = {ANGIE_PID, ANGIE_PID_2, ANGIE_PID_3, ANGIE_PID_4, ANGIE_PID_5, 0}; + + int ret = jtag_libusb_open(vids, pids, NULL, &usb_device_handle, NULL); + + if (ret != ERROR_OK) { + LOG_ERROR("Could not find and open ANGIE"); + return ret; + } + + device->usb_device_handle = usb_device_handle; + device->type = ANGIE; + + return ERROR_OK; +} + +/** + * Releases the ANGIE interface and closes the USB device handle. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_usb_close(struct angie *device) +{ + if (device->usb_device_handle) { + if (libusb_release_interface(device->usb_device_handle, 0) != 0) { + LOG_ERROR("Could not release interface 0"); + return ERROR_FAIL; + } + + jtag_libusb_close(device->usb_device_handle); + device->usb_device_handle = NULL; + } + return ERROR_OK; +} + +/******************* ANGIE CPU (EZ-USB) specific functions ********************/ + +/** + * Writes '0' or '1' to the CPUCS register, putting the EZ-USB CPU into reset + * or out of reset. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param reset_bit 0 to put CPU into reset, 1 to put CPU out of reset. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_cpu_reset(struct angie *device, char reset_bit) +{ + return jtag_libusb_control_transfer(device->usb_device_handle, + (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE), + REQUEST_FIRMWARE_LOAD, CPUCS_REG, 0, &reset_bit, 1, LIBUSB_TIMEOUT_MS, NULL); +} + +/** + * Puts the ANGIE's EZ-USB microcontroller into reset state, downloads + * the firmware image, resumes the microcontroller and re-enumerates + * USB devices. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * The usb_handle member will be modified during re-enumeration. + * @param filename path to the Intel HEX file containing the firmware image. + * @param delay_us the delay to wait for the device to re-enumerate. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_load_firmware_and_renumerate(struct angie *device, + const char *filename, uint32_t delay_us) +{ + int ret; + + /* Basic process: After downloading the firmware, the ANGIE will disconnect + * itself and re-connect after a short amount of time so we have to close + * the handle and re-enumerate USB devices */ + + ret = angie_load_firmware(device, filename); + if (ret != ERROR_OK) + return ret; + + ret = angie_usb_close(device); + if (ret != ERROR_OK) + return ret; + + usleep(delay_us); + + ret = angie_usb_open(device); + if (ret != ERROR_OK) + return ret; + + ret = libusb_claim_interface(angie_handle->usb_device_handle, 0); + if (ret != LIBUSB_SUCCESS) + return ERROR_FAIL; + + return ERROR_OK; +} + +/** + * Downloads a firmware image to the ANGIE's EZ-USB microcontroller + * over the USB bus. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param filename an absolute or relative path to the Intel HEX file + * containing the firmware image. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_load_firmware(struct angie *device, const char *filename) +{ + struct image angie_firmware_image; + int ret; + + ret = angie_cpu_reset(device, CPU_RESET); + if (ret != ERROR_OK) { + LOG_ERROR("Could not halt ANGIE CPU"); + return ret; + } + + angie_firmware_image.base_address = 0; + angie_firmware_image.base_address_set = false; + + ret = image_open(&angie_firmware_image, filename, "bin"); + if (ret != ERROR_OK) { + LOG_ERROR("Could not load firmware image"); + return ret; + } + + /* Download all sections in the image to ANGIE */ + for (unsigned int i = 0; i < angie_firmware_image.num_sections; i++) { + ret = angie_write_firmware_section(device, &angie_firmware_image, i); + if (ret != ERROR_OK) { + LOG_ERROR("Could not write firmware section"); + return ret; + } + } + + image_close(&angie_firmware_image); + + ret = angie_cpu_reset(device, CPU_START); + if (ret != ERROR_OK) { + LOG_ERROR("Could not restart ANGIE CPU"); + return ret; + } + + return ERROR_OK; +} + +/** + * Downloads a bitstream file to the ANGIE's FPGA through the EZ-USB microcontroller + * over the USB bus. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param filename an absolute or relative path to the Xilinx .bit file + * containing the bitstream data. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_load_bitstream(struct angie *device, const char *filename) +{ + int ret, transferred; + const char *bitstream_file_path = filename; + FILE *bitstream_file = NULL; + char *bitstream_data = NULL; + size_t bitstream_size = 0; + uint8_t gpifcnt[4]; + + /* Open the bitstream file */ + bitstream_file = fopen(bitstream_file_path, "rb"); + if (!bitstream_file) { + LOG_ERROR("Failed to open bitstream file: %s\n", bitstream_file_path); + return ERROR_FAIL; + } + + /* Get the size of the bitstream file */ + fseek(bitstream_file, 0, SEEK_END); + bitstream_size = ftell(bitstream_file); + fseek(bitstream_file, 0, SEEK_SET); + + /* Allocate memory for the bitstream data */ + bitstream_data = malloc(bitstream_size); + if (!bitstream_data) { + LOG_ERROR("Failed to allocate memory for bitstream data."); + fclose(bitstream_file); + return ERROR_FAIL; + } + + /* Read the bitstream data from the file */ + if (fread(bitstream_data, 1, bitstream_size, bitstream_file) != bitstream_size) { + LOG_ERROR("Failed to read bitstream data."); + free(bitstream_data); + fclose(bitstream_file); + return ERROR_FAIL; + } + + h_u32_to_be(gpifcnt, bitstream_size); + + /* CFGopen */ + ret = jtag_libusb_control_transfer(device->usb_device_handle, + 0x00, 0xB0, 0, 0, (char *)gpifcnt, 4, LIBUSB_TIMEOUT_MS, &transferred); + if (ret != ERROR_OK) { + LOG_ERROR("Failed opencfg"); + /* Abort if libusb sent less data than requested */ + return ERROR_FAIL; + } + + /* Send the bitstream data to the microcontroller */ + int actual_length = 0; + ret = jtag_libusb_bulk_write(device->usb_device_handle, 0x02, bitstream_data, bitstream_size, 1000, &actual_length); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to send bitstream data: %s", libusb_strerror(ret)); + free(bitstream_data); + fclose(bitstream_file); + return ERROR_FAIL; + } + + LOG_INFO("Bitstream sent successfully."); + + /* Clean up */ + free(bitstream_data); + fclose(bitstream_file); + + /* CFGclose */ + transferred = 0; + ret = jtag_libusb_control_transfer(device->usb_device_handle, + 0x00, 0xB1, 0, 0, NULL, 0, LIBUSB_TIMEOUT_MS, &transferred); + if (ret != ERROR_OK) { + LOG_ERROR("Failed cfgclose"); + /* Abort if libusb sent less data than requested */ + return ERROR_FAIL; + } + return ERROR_OK; +} + +/** + * Send an i2c write operation to dev-board components. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param i2c_data table of i2c data that we want to write to slave device. + * @param i2c_data_size the size of i2c data table. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_i2c_write(struct angie *device, uint8_t *i2c_data, uint8_t i2c_data_size) +{ + char i2c_data_buffer[i2c_data_size + 2]; + char buffer_received[1]; + int ret, transferred; + i2c_data_buffer[0] = 0; // write = 0 + i2c_data_buffer[1] = i2c_data_size - 1; // i2c_data count (without address) + + for (uint8_t i = 0; i < i2c_data_size; i++) + i2c_data_buffer[i + 2] = i2c_data[i]; + + // Send i2c packet to Dev-board and configure its clock source / + ret = jtag_libusb_bulk_write(device->usb_device_handle, 0x06, i2c_data_buffer, + i2c_data_size + 2, 1000, &transferred); + if (ret != ERROR_OK) { + LOG_ERROR("Error in i2c clock gen configuration : ret ERROR"); + return ret; + } + if (transferred != i2c_data_size + 2) { + LOG_ERROR("Error in i2c clock gen configuration : bytes transferred"); + return ERROR_FAIL; + } + + usleep(500); + + // Receive packet from ANGIE / + ret = jtag_libusb_bulk_write(device->usb_device_handle, 0x88, buffer_received, 1, 1000, &transferred); + if (ret != ERROR_OK) { + LOG_ERROR("Error in i2c clock gen configuration : ret ERROR"); + return ret; + } + return ERROR_OK; +} + +/** + * Configure dev-board gpio extender modules by configuring their + * register 3 and register 1 responsible for IO directions and values. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param i2c_adr i2c address of the gpio extender. + * @param cfg_value IOs configuration to be written in register Number 3. + * @param value the IOs value to be written in register Number 1. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_io_extender_config(struct angie *device, uint8_t i2c_adr, uint8_t cfg_value) +{ + uint8_t ioconfig[3] = {i2c_adr, 3, cfg_value}; + int ret = angie_i2c_write(device, ioconfig, 3); + if (ret != ERROR_OK) + return ret; + + usleep(500); + return ret; +} + +/** + * Send one contiguous firmware section to the ANGIE's EZ-USB microcontroller + * over the USB bus. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param firmware_image pointer to the firmware image that contains the section + * which should be sent to the ANGIE's EZ-USB microcontroller. + * @param section_index index of the section within the firmware image. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_write_firmware_section(struct angie *device, + struct image *firmware_image, int section_index) +{ + int addr, bytes_remaining, chunk_size; + uint8_t data[SECTION_BUFFERSIZE]; + uint8_t *data_ptr = data; + uint16_t size; + size_t size_read; + int ret, transferred; + + size = (uint16_t)firmware_image->sections[section_index].size; + addr = (uint16_t)firmware_image->sections[section_index].base_address; + + LOG_DEBUG("section %02i at addr 0x%04x (size 0x%04" PRIx16 ")", section_index, addr, + size); + + /* Copy section contents to local buffer */ + ret = image_read_section(firmware_image, section_index, 0, size, data, + &size_read); + + if (ret != ERROR_OK) + return ret; + if (size_read != size) + return ERROR_FAIL; + + bytes_remaining = size; + + /* Send section data in chunks of up to 64 bytes to ANGIE */ + while (bytes_remaining > 0) { + if (bytes_remaining > 64) + chunk_size = 64; + else + chunk_size = bytes_remaining; + + ret = jtag_libusb_control_transfer(device->usb_device_handle, + (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE), + REQUEST_FIRMWARE_LOAD, addr, FIRMWARE_ADDR, (char *)data_ptr, + chunk_size, LIBUSB_TIMEOUT_MS, &transferred); + + if (ret != ERROR_OK) + return ret; + + if (transferred != chunk_size) { + /* Abort if libusb sent less data than requested */ + return ERROR_FAIL; + } + + bytes_remaining -= chunk_size; + addr += chunk_size; + data_ptr += chunk_size; + } + + return ERROR_OK; +} + +/************************** Generic helper functions **************************/ + +/** + * Print state of interesting signals via LOG_INFO(). + * + * @param input_signals input signal states as returned by CMD_GET_SIGNALS + * @param output_signals output signal states as returned by CMD_GET_SIGNALS + */ +static void angie_dump_signal_states(uint8_t input_signals, uint8_t output_signals) +{ + LOG_INFO("ANGIE signal states: TDI: %i, TDO: %i, TMS: %i, TCK: %i, TRST: %i " + "SRST: %i", + (output_signals & SIGNAL_TDI ? 1 : 0), + (input_signals & SIGNAL_TDO ? 1 : 0), + (output_signals & SIGNAL_TMS ? 1 : 0), + (output_signals & SIGNAL_TCK ? 1 : 0), + (output_signals & SIGNAL_TRST ? 1 : 0), + (output_signals & SIGNAL_SRST ? 1 : 0)); +} + +/**************** ANGIE command generation helper functions ***************/ + +/** + * Allocate and initialize space in memory for ANGIE command payload. + * + * @param angie_cmd pointer to command whose payload should be allocated. + * @param size the amount of memory to allocate (bytes). + * @param direction which payload to allocate. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_allocate_payload(struct angie_cmd *angie_cmd, int size, + enum angie_payload_direction direction) +{ + uint8_t *payload; + + payload = calloc(size, sizeof(uint8_t)); + + if (!payload) { + LOG_ERROR("Could not allocate ANGIE command payload: out of memory"); + return ERROR_FAIL; + } + + switch (direction) { + case PAYLOAD_DIRECTION_OUT: + if (angie_cmd->payload_out) { + LOG_ERROR("BUG: Duplicate payload allocation for ANGIE command"); + free(payload); + return ERROR_FAIL; + } + angie_cmd->payload_out = payload; + angie_cmd->payload_out_size = size; + break; + case PAYLOAD_DIRECTION_IN: + if (angie_cmd->payload_in_start) { + LOG_ERROR("BUG: Duplicate payload allocation for ANGIE command"); + free(payload); + return ERROR_FAIL; + } + + angie_cmd->payload_in_start = payload; + angie_cmd->payload_in = payload; + angie_cmd->payload_in_size = size; + + /* By default, free payload_in_start in angie_clear_queue(). Commands + * that do not want this behavior (e. g. split scans) must turn it off + * separately! */ + angie_cmd->free_payload_in_start = true; + + break; + } + + return ERROR_OK; +} + +/****************** ANGIE command queue helper functions ******************/ + +/** + * Get the current number of bytes in the queue, including command IDs. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param direction the transfer direction for which to get byte count. + * @return the number of bytes currently stored in the queue for the specified + * direction. + */ +static int angie_get_queue_size(struct angie *device, + enum angie_payload_direction direction) +{ + struct angie_cmd *current = device->queue_start; + int sum = 0; + + while (current) { + switch (direction) { + case PAYLOAD_DIRECTION_OUT: + sum += current->payload_out_size + 1; /* + 1 byte for Command ID */ + break; + case PAYLOAD_DIRECTION_IN: + sum += current->payload_in_size; + break; + } + + current = current->next; + } + + return sum; +} + +/** + * Clear the ANGIE command queue. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + */ +static void angie_clear_queue(struct angie *device) +{ + struct angie_cmd *current = device->queue_start; + struct angie_cmd *next = NULL; + + while (current) { + /* Save pointer to next element */ + next = current->next; + + /* Free payloads: OUT payload can be freed immediately */ + free(current->payload_out); + current->payload_out = NULL; + + /* IN payload MUST be freed ONLY if no other commands use the + * payload_in_start buffer */ + if (current->free_payload_in_start) { + free(current->payload_in_start); + current->payload_in_start = NULL; + current->payload_in = NULL; + } + + /* Free queue element */ + free(current); + + /* Proceed with next element */ + current = next; + } + + device->commands_in_queue = 0; + device->queue_start = NULL; + device->queue_end = NULL; +} + +/** + * Add a command to the ANGIE command queue. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param angie_cmd pointer to command that shall be appended to the ANGIE + * command queue. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_queue(struct angie *device, struct angie_cmd *angie_cmd) +{ + int newsize_out, newsize_in; + int ret = ERROR_OK; + + newsize_out = angie_get_queue_size(device, PAYLOAD_DIRECTION_OUT) + 1 + + angie_cmd->payload_out_size; + + newsize_in = angie_get_queue_size(device, PAYLOAD_DIRECTION_IN) + + angie_cmd->payload_in_size; + + /* Check if the current command can be appended to the queue */ + if (newsize_out > 64 || newsize_in > 64) { + /* New command does not fit. Execute all commands in queue before starting + * new queue with the current command as first entry. */ + ret = angie_execute_queued_commands(device, LIBUSB_TIMEOUT_MS); + + if (ret == ERROR_OK) + ret = angie_post_process_queue(device); + + if (ret == ERROR_OK) + angie_clear_queue(device); + } + + if (!device->queue_start) { + /* Queue was empty */ + device->commands_in_queue = 1; + + device->queue_start = angie_cmd; + device->queue_end = angie_cmd; + } else { + /* There are already commands in the queue */ + device->commands_in_queue++; + + device->queue_end->next = angie_cmd; + device->queue_end = angie_cmd; + } + + if (ret != ERROR_OK) + angie_clear_queue(device); + + return ret; +} + +/** + * Sends all queued ANGIE commands to the ANGIE for execution. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param timeout_ms + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_execute_queued_commands(struct angie *device, int timeout_ms) +{ + struct angie_cmd *current; + int ret, i, index_out, index_in, count_out, count_in, transferred; + uint8_t buffer[64]; + + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) + angie_dump_queue(device); + + index_out = 0; + count_out = 0; + count_in = 0; + + for (current = device->queue_start; current; current = current->next) { + /* Add command to packet */ + buffer[index_out] = current->id; + index_out++; + count_out++; + + for (i = 0; i < current->payload_out_size; i++) + buffer[index_out + i] = current->payload_out[i]; + index_out += current->payload_out_size; + count_in += current->payload_in_size; + count_out += current->payload_out_size; + } + + /* Send packet to ANGIE */ + ret = jtag_libusb_bulk_write(device->usb_device_handle, device->ep_out, + (char *)buffer, count_out, timeout_ms, &transferred); + if (ret != ERROR_OK) { + LOG_ERROR("Libusb bulk write queued commands failed."); + return ret; + } + if (transferred != count_out) { + LOG_ERROR("Libusb bulk write queued commands failed: transferred byte count"); + return ERROR_FAIL; + } + + /* Wait for response if commands contain IN payload data */ + if (count_in > 0) { + ret = jtag_libusb_bulk_write(device->usb_device_handle, device->ep_in, + (char *)buffer, count_in, timeout_ms, &transferred); + if (ret != ERROR_OK) { + LOG_ERROR("Libusb bulk write input payload data failed"); + return ret; + } + if (transferred != count_in) { + LOG_ERROR("Libusb bulk write input payload data failed: transferred byte count"); + return ERROR_FAIL; + } + + /* Write back IN payload data */ + index_in = 0; + for (current = device->queue_start; current; current = current->next) { + for (i = 0; i < current->payload_in_size; i++) { + current->payload_in[i] = buffer[index_in]; + index_in++; + } + } + } + return ERROR_OK; +} + +/** + * Convert an ANGIE command ID (\a id) to a human-readable string. + * + * @param id the ANGIE command ID. + * @return the corresponding human-readable string. + */ +static const char *angie_cmd_id_string(uint8_t id) +{ + switch (id) { + case CMD_SCAN_IN: + return "CMD_SCAN_IN"; + case CMD_SLOW_SCAN_IN: + return "CMD_SLOW_SCAN_IN"; + case CMD_SCAN_OUT: + return "CMD_SCAN_OUT"; + case CMD_SLOW_SCAN_OUT: + return "CMD_SLOW_SCAN_OUT"; + case CMD_SCAN_IO: + return "CMD_SCAN_IO"; + case CMD_SLOW_SCAN_IO: + return "CMD_SLOW_SCAN_IO"; + case CMD_CLOCK_TMS: + return "CMD_CLOCK_TMS"; + case CMD_SLOW_CLOCK_TMS: + return "CMD_SLOW_CLOCK_TMS"; + case CMD_CLOCK_TCK: + return "CMD_CLOCK_TCK"; + case CMD_SLOW_CLOCK_TCK: + return "CMD_SLOW_CLOCK_TCK"; + case CMD_SLEEP_US: + return "CMD_SLEEP_US"; + case CMD_SLEEP_MS: + return "CMD_SLEEP_MS"; + case CMD_GET_SIGNALS: + return "CMD_GET_SIGNALS"; + case CMD_SET_SIGNALS: + return "CMD_SET_SIGNALS"; + case CMD_CONFIGURE_TCK_FREQ: + return "CMD_CONFIGURE_TCK_FREQ"; + case CMD_SET_LEDS: + return "CMD_SET_LEDS"; + case CMD_TEST: + return "CMD_TEST"; + default: + return "CMD_UNKNOWN"; + } +} + +/** + * Print one ANGIE command to stdout. + * + * @param angie_cmd pointer to ANGIE command. + */ +static void angie_dump_command(struct angie_cmd *angie_cmd) +{ + char hex[64 * 3]; + for (int i = 0; i < angie_cmd->payload_out_size; i++) + sprintf(hex + 3 * i, "%02" PRIX8 " ", angie_cmd->payload_out[i]); + + hex[3 * angie_cmd->payload_out_size - 1] = 0; + LOG_DEBUG_IO(" %-22s | OUT size = %" PRIi8 ", bytes = %s", + angie_cmd_id_string(angie_cmd->id), angie_cmd->payload_out_size, hex); + + LOG_DEBUG_IO("\n | IN size = %" PRIi8 "\n", angie_cmd->payload_in_size); +} + +/** + * Print the ANGIE command queue to stdout. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + */ +static void angie_dump_queue(struct angie *device) +{ + struct angie_cmd *current; + + LOG_DEBUG_IO("ANGIE command queue:\n"); + + for (current = device->queue_start; current; current = current->next) + angie_dump_command(current); +} + +/** + * Perform JTAG scan + * + * Creates and appends a JTAG scan command to the ANGIE command queue. + * A JTAG scan consists of three steps: + * - Move to the desired SHIFT state, depending on scan type (IR/DR scan). + * - Shift TDI data into the JTAG chain, optionally reading the TDO pin. + * - Move to the desired end state. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param scan_type the type of the scan (IN, OUT, IO (bidirectional)). + * @param scan_size_bits number of bits to shift into the JTAG chain. + * @param tdi pointer to array containing TDI data. + * @param tdo_start pointer to first element of array where TDO data shall be + * stored. See #angie_cmd for details. + * @param tdo pointer to array where TDO data shall be stored + * @param tms_count_start number of TMS state transitions to perform BEFORE + * shifting data into the JTAG chain. + * @param tms_sequence_start sequence of TMS state transitions that will be + * performed BEFORE shifting data into the JTAG chain. + * @param tms_count_end number of TMS state transitions to perform AFTER + * shifting data into the JTAG chain. + * @param tms_sequence_end sequence of TMS state transitions that will be + * performed AFTER shifting data into the JTAG chain. + * @param origin pointer to OpenOCD command that generated this scan command. + * @param postprocess whether this command needs to be post-processed after + * execution. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_scan_cmd(struct angie *device, enum scan_type scan_type, + int scan_size_bits, uint8_t *tdi, uint8_t *tdo_start, uint8_t *tdo, + uint8_t tms_count_start, uint8_t tms_sequence_start, uint8_t tms_count_end, + uint8_t tms_sequence_end, struct jtag_command *origin, bool postprocess) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret, i, scan_size_bytes; + uint8_t bits_last_byte; + + if (!cmd) + return ERROR_FAIL; + + /* Check size of command. USB buffer can hold 64 bytes, 1 byte is command ID, + * 5 bytes are setup data -> 58 remaining payload bytes for TDI data */ + if (scan_size_bits > (58 * 8)) { + LOG_ERROR("BUG: Tried to create CMD_SCAN_IO ANGIE command with too" + " large payload"); + free(cmd); + return ERROR_FAIL; + } + + scan_size_bytes = DIV_ROUND_UP(scan_size_bits, 8); + + bits_last_byte = scan_size_bits % 8; + if (bits_last_byte == 0) + bits_last_byte = 8; + + /* Allocate out_payload depending on scan type */ + switch (scan_type) { + case SCAN_IN: + if (device->delay_scan_in < 0) + cmd->id = CMD_SCAN_IN; + else + cmd->id = CMD_SLOW_SCAN_IN; + ret = angie_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_IN); + break; + case SCAN_OUT: + if (device->delay_scan_out < 0) + cmd->id = CMD_SCAN_OUT; + else + cmd->id = CMD_SLOW_SCAN_OUT; + ret = angie_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); + break; + case SCAN_IO: + if (device->delay_scan_io < 0) + cmd->id = CMD_SCAN_IO; + else + cmd->id = CMD_SLOW_SCAN_IO; + ret = angie_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); + break; + default: + LOG_ERROR("BUG: 'append scan cmd' encountered an unknown scan type"); + ret = ERROR_FAIL; + break; + } + + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + /* Build payload_out that is common to all scan types */ + cmd->payload_out[0] = scan_size_bytes & 0xFF; + cmd->payload_out[1] = bits_last_byte & 0xFF; + cmd->payload_out[2] = ((tms_count_start & 0x0F) << 4) | (tms_count_end & 0x0F); + cmd->payload_out[3] = tms_sequence_start; + cmd->payload_out[4] = tms_sequence_end; + + /* Setup payload_out for types with OUT transfer */ + if (scan_type == SCAN_OUT || scan_type == SCAN_IO) { + for (i = 0; i < scan_size_bytes; i++) + cmd->payload_out[i + 5] = tdi[i]; + } + + /* Setup payload_in pointers for types with IN transfer */ + if (scan_type == SCAN_IN || scan_type == SCAN_IO) { + cmd->payload_in_start = tdo_start; + cmd->payload_in = tdo; + cmd->payload_in_size = scan_size_bytes; + } + + cmd->needs_postprocessing = postprocess; + cmd->cmd_origin = origin; + + /* For scan commands, we free payload_in_start only when the command is + * the last in a series of split commands or a stand-alone command */ + cmd->free_payload_in_start = postprocess; + + return angie_append_queue(device, cmd); +} + +/** + * Perform TAP state transitions + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param count defines the number of TCK clock cycles generated (up to 8). + * @param sequence defines the TMS pin levels for each state transition. The + * Least-Significant Bit is read first. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_clock_tms_cmd(struct angie *device, uint8_t count, + uint8_t sequence) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + if (device->delay_clock_tms < 0) + cmd->id = CMD_CLOCK_TMS; + else + cmd->id = CMD_SLOW_CLOCK_TMS; + + /* CMD_CLOCK_TMS has two OUT payload bytes and zero IN payload bytes */ + ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + cmd->payload_out[0] = count; + cmd->payload_out[1] = sequence; + + return angie_append_queue(device, cmd); +} + +/** + * Generate a defined amount of TCK clock cycles + * + * All other JTAG signals are left unchanged. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param count the number of TCK clock cycles to generate. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_clock_tck_cmd(struct angie *device, uint16_t count) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + if (device->delay_clock_tck < 0) + cmd->id = CMD_CLOCK_TCK; + else + cmd->id = CMD_SLOW_CLOCK_TCK; + + /* CMD_CLOCK_TCK has two OUT payload bytes and zero IN payload bytes */ + ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + cmd->payload_out[0] = count & 0xff; + cmd->payload_out[1] = (count >> 8) & 0xff; + + return angie_append_queue(device, cmd); +} + +/** + * Read JTAG signals. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_get_signals_cmd(struct angie *device) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + cmd->id = CMD_GET_SIGNALS; + cmd->needs_postprocessing = true; + + /* CMD_GET_SIGNALS has two IN payload bytes */ + ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_IN); + + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + return angie_append_queue(device, cmd); +} + +/** + * Arbitrarily set JTAG output signals. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param low defines which signals will be de-asserted. Each bit corresponds + * to a JTAG signal: + * - SIGNAL_TDI + * - SIGNAL_TMS + * - SIGNAL_TCK + * - SIGNAL_TRST + * - SIGNAL_BRKIN + * - SIGNAL_RESET + * - SIGNAL_OCDSE + * @param high defines which signals will be asserted. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_set_signals_cmd(struct angie *device, uint8_t low, + uint8_t high) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + cmd->id = CMD_SET_SIGNALS; + + /* CMD_SET_SIGNALS has two OUT payload bytes and zero IN payload bytes */ + ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); + + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + cmd->payload_out[0] = low; + cmd->payload_out[1] = high; + + return angie_append_queue(device, cmd); +} + +/** + * Sleep for a pre-defined number of microseconds + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param us the number microseconds to sleep. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_sleep_cmd(struct angie *device, uint32_t us) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + cmd->id = CMD_SLEEP_US; + + /* CMD_SLEEP_US has two OUT payload bytes and zero IN payload bytes */ + ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); + + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + cmd->payload_out[0] = us & 0x00ff; + cmd->payload_out[1] = (us >> 8) & 0x00ff; + + return angie_append_queue(device, cmd); +} + +/** + * Set TCK delay counters + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param delay_scan_in delay count top value in jtag_slow_scan_in() function. + * @param delay_scan_out delay count top value in jtag_slow_scan_out() function. + * @param delay_scan_io delay count top value in jtag_slow_scan_io() function. + * @param delay_tck delay count top value in jtag_clock_tck() function. + * @param delay_tms delay count top value in jtag_slow_clock_tms() function. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_configure_tck_cmd(struct angie *device, int delay_scan_in, + int delay_scan_out, int delay_scan_io, int delay_tck, int delay_tms) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + cmd->id = CMD_CONFIGURE_TCK_FREQ; + + /* CMD_CONFIGURE_TCK_FREQ has five OUT payload bytes and zero + * IN payload bytes */ + ret = angie_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_OUT); + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + if (delay_scan_in < 0) + cmd->payload_out[0] = 0; + else + cmd->payload_out[0] = (uint8_t)delay_scan_in; + + if (delay_scan_out < 0) + cmd->payload_out[1] = 0; + else + cmd->payload_out[1] = (uint8_t)delay_scan_out; + + if (delay_scan_io < 0) + cmd->payload_out[2] = 0; + else + cmd->payload_out[2] = (uint8_t)delay_scan_io; + + if (delay_tck < 0) + cmd->payload_out[3] = 0; + else + cmd->payload_out[3] = (uint8_t)delay_tck; + + if (delay_tms < 0) + cmd->payload_out[4] = 0; + else + cmd->payload_out[4] = (uint8_t)delay_tms; + + return angie_append_queue(device, cmd); +} + +/** + * Test command. Used to check if the ANGIE device is ready to accept new + * commands. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_test_cmd(struct angie *device) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + cmd->id = CMD_TEST; + + /* CMD_TEST has one OUT payload byte and zero IN payload bytes */ + ret = angie_allocate_payload(cmd, 1, PAYLOAD_DIRECTION_OUT); + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + cmd->payload_out[0] = 0xAA; + + return angie_append_queue(device, cmd); +} + +/****************** ANGIE TCK frequency helper functions ******************/ + +/** + * Calculate delay values for a given TCK frequency. + * + * The ANGIE firmware uses five different speed values for different + * commands. These speed values are calculated in these functions. + * + * The five different commands which support variable TCK frequency are + * implemented twice in the firmware: + * 1. Maximum possible frequency without any artificial delay + * 2. Variable frequency with artificial linear delay loop + * + * To set the ANGIE to maximum frequency, it is only necessary to use the + * corresponding command IDs. To set the ANGIE to a lower frequency, the + * delay loop top values have to be calculated first. Then, a + * CMD_CONFIGURE_TCK_FREQ command needs to be sent to the ANGIE device. + * + * The delay values are described by linear equations: + * t = k * x + d + * (t = period, k = constant, x = delay value, d = constant) + * + * Thus, the delay can be calculated as in the following equation: + * x = (t - d) / k + * + * The constants in these equations have been determined and validated by + * measuring the frequency resulting from different delay values. + * + * @param type for which command to calculate the delay value. + * @param f TCK frequency for which to calculate the delay value in Hz. + * @param delay where to store resulting delay value. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_calculate_delay(enum angie_delay_type type, long f, int *delay) +{ + float t_us, x, x_ceil; + + /* Calculate period of requested TCK frequency */ + t_us = 1000000.0 / f; + + switch (type) { + case DELAY_CLOCK_TCK: + x = (t_us - 6.0) / 4; + break; + case DELAY_CLOCK_TMS: + x = (t_us - 8.5) / 4; + break; + case DELAY_SCAN_IN: + x = (t_us - 8.8308) / 4; + break; + case DELAY_SCAN_OUT: + x = (t_us - 10.527) / 4; + break; + case DELAY_SCAN_IO: + x = (t_us - 13.132) / 4; + break; + default: + return ERROR_FAIL; + break; + } + + /* Check if the delay value is negative. This happens when a frequency is + * requested that is too high for the delay loop implementation. In this + * case, set delay value to zero. */ + if (x < 0) + x = 0; + + /* We need to convert the exact delay value to an integer. Therefore, we + * round the exact value UP to ensure that the resulting frequency is NOT + * higher than the requested frequency. */ + x_ceil = ceilf(x); + + /* Check if the value is within limits */ + if (x_ceil > 255) + return ERROR_FAIL; + + *delay = (int)x_ceil; + + return ERROR_OK; +} + +/** + * Calculate frequency for a given delay value. + * + * Similar to the #angie_calculate_delay function, this function calculates the + * TCK frequency for a given delay value by using linear equations of the form: + * t = k * x + d + * (t = period, k = constant, x = delay value, d = constant) + * + * @param type for which command to calculate the delay value. + * @param delay value for which to calculate the resulting TCK frequency. + * @return the resulting TCK frequency + */ +static long angie_calculate_frequency(enum angie_delay_type type, int delay) +{ + float t_us, f_float; + + if (delay > 255) + return 0; + + switch (type) { + case DELAY_CLOCK_TCK: + if (delay < 0) + t_us = 2.666; + else + t_us = (4.0 * delay) + 6.0; + break; + case DELAY_CLOCK_TMS: + if (delay < 0) + t_us = 5.666; + else + t_us = (4.0 * delay) + 8.5; + break; + case DELAY_SCAN_IN: + if (delay < 0) + t_us = 5.5; + else + t_us = (4.0 * delay) + 8.8308; + break; + case DELAY_SCAN_OUT: + if (delay < 0) + t_us = 7.0; + else + t_us = (4.0 * delay) + 10.527; + break; + case DELAY_SCAN_IO: + if (delay < 0) + t_us = 9.926; + else + t_us = (4.0 * delay) + 13.132; + break; + default: + return 0; + } + + f_float = 1000000.0 / t_us; + return roundf(f_float); +} + +/******************* Interface between ANGIE and OpenOCD ******************/ + +/** + * Sets the end state follower (see interface.h) if \a endstate is a stable + * state. + * + * @param endstate the state the end state follower should be set to. + */ +static void angie_set_end_state(tap_state_t endstate) +{ + if (tap_is_state_stable(endstate)) + tap_set_end_state(endstate); + else + LOG_ERROR("BUG: %s is not a valid end state", tap_state_name(endstate)); +} + +/** + * Move from the current TAP state to the current TAP end state. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_statemove(struct angie *device) +{ + uint8_t tms_sequence, tms_count; + int ret; + + if (tap_get_state() == tap_get_end_state()) { + /* Do nothing if we are already there */ + return ERROR_OK; + } + + tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + + ret = angie_append_clock_tms_cmd(device, tms_count, tms_sequence); + + if (ret == ERROR_OK) + tap_set_state(tap_get_end_state()); + + return ret; +} + +/** + * Perform a scan operation on a JTAG register. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_scan(struct angie *device, struct jtag_command *cmd) +{ + uint32_t scan_size_bits, scan_size_bytes, bits_last_scan; + uint32_t scans_max_payload, bytecount; + uint8_t *tdi_buffer_start = NULL, *tdi_buffer = NULL; + uint8_t *tdo_buffer_start = NULL, *tdo_buffer = NULL; + + uint8_t first_tms_count, first_tms_sequence; + uint8_t last_tms_count, last_tms_sequence; + + uint8_t tms_count_pause, tms_sequence_pause; + uint8_t tms_count_resume, tms_sequence_resume; + + uint8_t tms_count_start, tms_sequence_start; + uint8_t tms_count_end, tms_sequence_end; + + enum scan_type type; + int ret; + + /* Determine scan size */ + scan_size_bits = jtag_scan_size(cmd->cmd.scan); + scan_size_bytes = DIV_ROUND_UP(scan_size_bits, 8); + + /* Determine scan type (IN/OUT/IO) */ + type = jtag_scan_type(cmd->cmd.scan); + + /* Determine number of scan commands with maximum payload */ + scans_max_payload = scan_size_bytes / 58; + + /* Determine size of last shift command */ + bits_last_scan = scan_size_bits - (scans_max_payload * 58 * 8); + + /* Allocate TDO buffer if required */ + if (type == SCAN_IN || type == SCAN_IO) { + tdo_buffer_start = calloc(sizeof(uint8_t), scan_size_bytes); + + if (!tdo_buffer_start) + return ERROR_FAIL; + + tdo_buffer = tdo_buffer_start; + } + + /* Fill TDI buffer if required */ + if (type == SCAN_OUT || type == SCAN_IO) { + jtag_build_buffer(cmd->cmd.scan, &tdi_buffer_start); + tdi_buffer = tdi_buffer_start; + } + + /* Get TAP state transitions */ + if (cmd->cmd.scan->ir_scan) { + angie_set_end_state(TAP_IRSHIFT); + first_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + first_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + + tap_set_state(TAP_IRSHIFT); + tap_set_end_state(cmd->cmd.scan->end_state); + last_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + last_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + + /* TAP state transitions for split scans */ + tms_count_pause = tap_get_tms_path_len(TAP_IRSHIFT, TAP_IRPAUSE); + tms_sequence_pause = tap_get_tms_path(TAP_IRSHIFT, TAP_IRPAUSE); + tms_count_resume = tap_get_tms_path_len(TAP_IRPAUSE, TAP_IRSHIFT); + tms_sequence_resume = tap_get_tms_path(TAP_IRPAUSE, TAP_IRSHIFT); + } else { + angie_set_end_state(TAP_DRSHIFT); + first_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + first_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + + tap_set_state(TAP_DRSHIFT); + tap_set_end_state(cmd->cmd.scan->end_state); + last_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + last_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + + /* TAP state transitions for split scans */ + tms_count_pause = tap_get_tms_path_len(TAP_DRSHIFT, TAP_DRPAUSE); + tms_sequence_pause = tap_get_tms_path(TAP_DRSHIFT, TAP_DRPAUSE); + tms_count_resume = tap_get_tms_path_len(TAP_DRPAUSE, TAP_DRSHIFT); + tms_sequence_resume = tap_get_tms_path(TAP_DRPAUSE, TAP_DRSHIFT); + } + + /* Generate scan commands */ + bytecount = scan_size_bytes; + while (bytecount > 0) { + if (bytecount == scan_size_bytes) { + /* This is the first scan */ + tms_count_start = first_tms_count; + tms_sequence_start = first_tms_sequence; + } else { + /* Resume from previous scan */ + tms_count_start = tms_count_resume; + tms_sequence_start = tms_sequence_resume; + } + + if (bytecount > 58) { /* Full scan, at least one scan will follow */ + tms_count_end = tms_count_pause; + tms_sequence_end = tms_sequence_pause; + + ret = angie_append_scan_cmd(device, + type, + 58 * 8, + tdi_buffer, + tdo_buffer_start, + tdo_buffer, + tms_count_start, + tms_sequence_start, + tms_count_end, + tms_sequence_end, + cmd, + false); + + bytecount -= 58; + + /* Update TDI and TDO buffer pointers */ + if (tdi_buffer_start) + tdi_buffer += 58; + if (tdo_buffer_start) + tdo_buffer += 58; + } else if (bytecount == 58) { /* Full scan, no further scans */ + tms_count_end = last_tms_count; + tms_sequence_end = last_tms_sequence; + + ret = angie_append_scan_cmd(device, + type, + 58 * 8, + tdi_buffer, + tdo_buffer_start, + tdo_buffer, + tms_count_start, + tms_sequence_start, + tms_count_end, + tms_sequence_end, + cmd, + true); + + bytecount = 0; + } else {/* Scan with less than maximum payload, no further scans */ + tms_count_end = last_tms_count; + tms_sequence_end = last_tms_sequence; + + ret = angie_append_scan_cmd(device, + type, + bits_last_scan, + tdi_buffer, + tdo_buffer_start, + tdo_buffer, + tms_count_start, + tms_sequence_start, + tms_count_end, + tms_sequence_end, + cmd, + true); + + bytecount = 0; + } + + if (ret != ERROR_OK) { + free(tdi_buffer_start); + free(tdo_buffer_start); + return ret; + } + } + + free(tdi_buffer_start); + + /* Set current state to the end state requested by the command */ + tap_set_state(cmd->cmd.scan->end_state); + + return ERROR_OK; +} + +/** + * Move the TAP into the Test Logic Reset state. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_tlr_reset(struct angie *device, struct jtag_command *cmd) +{ + int ret = angie_append_clock_tms_cmd(device, 5, 0xff); + + if (ret == ERROR_OK) + tap_set_state(TAP_RESET); + + return ret; +} + +/** + * Run Test. + * + * Generate TCK clock cycles while remaining + * in the Run-Test/Idle state. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_runtest(struct angie *device, struct jtag_command *cmd) +{ + int ret; + + /* Only perform statemove if the TAP currently isn't in the TAP_IDLE state */ + if (tap_get_state() != TAP_IDLE) { + angie_set_end_state(TAP_IDLE); + angie_queue_statemove(device); + } + + /* Generate the clock cycles */ + ret = angie_append_clock_tck_cmd(device, cmd->cmd.runtest->num_cycles); + if (ret != ERROR_OK) + return ret; + + /* Move to end state specified in command */ + if (cmd->cmd.runtest->end_state != tap_get_state()) { + tap_set_end_state(cmd->cmd.runtest->end_state); + angie_queue_statemove(device); + } + + return ERROR_OK; +} + +/** + * Execute a JTAG_RESET command + * + * @param device + * @param trst indicate if trst signal is activated. + * @param srst indicate if srst signal is activated. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_reset(int trst, int srst) +{ + struct angie *device = angie_handle; + uint8_t low = 0, high = 0; + + if (trst) { + tap_set_state(TAP_RESET); + low |= SIGNAL_TRST; + } else { + high |= SIGNAL_TRST; + } + + if (srst) + low |= SIGNAL_SRST; + else + high |= SIGNAL_SRST; + + int ret = angie_append_set_signals_cmd(device, low, high); + if (ret != ERROR_OK) + return ret; + + ret = angie_execute_queued_commands(device, LIBUSB_TIMEOUT_MS); + if (ret != ERROR_OK) + return ret; + + angie_clear_queue(device); + + return ERROR_OK; +} + +/** + * Move to one TAP state or several states in succession. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_pathmove(struct angie *device, struct jtag_command *cmd) +{ + int ret, i, num_states, batch_size, state_count; + tap_state_t *path; + uint8_t tms_sequence; + + num_states = cmd->cmd.pathmove->num_states; + path = cmd->cmd.pathmove->path; + state_count = 0; + + while (num_states > 0) { + tms_sequence = 0; + + /* Determine batch size */ + if (num_states >= 8) + batch_size = 8; + else + batch_size = num_states; + + for (i = 0; i < batch_size; i++) { + if (tap_state_transition(tap_get_state(), false) == path[state_count]) { + /* Append '0' transition: clear bit 'i' in tms_sequence */ + buf_set_u32(&tms_sequence, i, 1, 0x0); + } else if (tap_state_transition(tap_get_state(), true) + == path[state_count]) { + /* Append '1' transition: set bit 'i' in tms_sequence */ + buf_set_u32(&tms_sequence, i, 1, 0x1); + } else { + /* Invalid state transition */ + LOG_ERROR("BUG: %s -> %s isn't a valid TAP state transition", + tap_state_name(tap_get_state()), + tap_state_name(path[state_count])); + return ERROR_FAIL; + } + + tap_set_state(path[state_count]); + state_count++; + num_states--; + } + + /* Append CLOCK_TMS command to ANGIE command queue */ + LOG_INFO("pathmove batch: count = %i, sequence = 0x%" PRIx8 "", batch_size, tms_sequence); + ret = angie_append_clock_tms_cmd(angie_handle, batch_size, tms_sequence); + if (ret != ERROR_OK) + return ret; + } + + return ERROR_OK; +} + +/** + * Sleep for a specific amount of time. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_sleep(struct angie *device, struct jtag_command *cmd) +{ + /* IMPORTANT! Due to the time offset in command execution introduced by + * command queueing, this needs to be implemented in the ANGIE device */ + return angie_append_sleep_cmd(device, cmd->cmd.sleep->us); +} + +/** + * Generate TCK cycles while remaining in a stable state. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + */ +static int angie_queue_stableclocks(struct angie *device, struct jtag_command *cmd) +{ + int ret; + unsigned int num_cycles; + + if (!tap_is_state_stable(tap_get_state())) { + LOG_ERROR("JTAG_STABLECLOCKS: state not stable"); + return ERROR_FAIL; + } + + num_cycles = cmd->cmd.stableclocks->num_cycles; + + /* TMS stays either high (Test Logic Reset state) or low (all other states) */ + if (tap_get_state() == TAP_RESET) + ret = angie_append_set_signals_cmd(device, 0, SIGNAL_TMS); + else + ret = angie_append_set_signals_cmd(device, SIGNAL_TMS, 0); + + if (ret != ERROR_OK) + return ret; + + while (num_cycles > 0) { + if (num_cycles > 0xFFFF) { + /* ANGIE CMD_CLOCK_TCK can generate up to 0xFFFF (uint16_t) cycles */ + ret = angie_append_clock_tck_cmd(device, 0xFFFF); + num_cycles -= 0xFFFF; + } else { + ret = angie_append_clock_tck_cmd(device, num_cycles); + num_cycles = 0; + } + + if (ret != ERROR_OK) + return ret; + } + + return ERROR_OK; +} + +/** + * Post-process JTAG_SCAN command + * + * @param angie_cmd pointer to ANGIE command that shall be processed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_post_process_scan(struct angie_cmd *angie_cmd) +{ + struct jtag_command *cmd = angie_cmd->cmd_origin; + int ret; + + switch (jtag_scan_type(cmd->cmd.scan)) { + case SCAN_IN: + case SCAN_IO: + ret = jtag_read_buffer(angie_cmd->payload_in_start, cmd->cmd.scan); + break; + case SCAN_OUT: + /* Nothing to do for OUT scans */ + ret = ERROR_OK; + break; + default: + LOG_ERROR("BUG: angie post process scan encountered an unknown JTAG scan type"); + ret = ERROR_FAIL; + break; + } + + return ret; +} + +/** + * Perform post-processing of commands after ANGIE queue has been executed. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_post_process_queue(struct angie *device) +{ + struct angie_cmd *current; + struct jtag_command *openocd_cmd; + int ret; + + current = device->queue_start; + + while (current) { + openocd_cmd = current->cmd_origin; + + /* Check if a corresponding OpenOCD command is stored for this + * ANGIE command */ + if (current->needs_postprocessing && openocd_cmd) { + switch (openocd_cmd->type) { + case JTAG_SCAN: + ret = angie_post_process_scan(current); + break; + case JTAG_TLR_RESET: + case JTAG_RUNTEST: + case JTAG_PATHMOVE: + case JTAG_SLEEP: + case JTAG_STABLECLOCKS: + /* Nothing to do for these commands */ + ret = ERROR_OK; + break; + default: + ret = ERROR_FAIL; + LOG_ERROR("BUG: angie post process queue encountered unknown JTAG " + "command type"); + break; + } + + if (ret != ERROR_OK) + return ret; + } + + current = current->next; + } + + return ERROR_OK; +} + +/**************************** JTAG driver functions ***************************/ + +/** + * Executes the JTAG Command Queue. + * + * This is done in three stages: First, all OpenOCD commands are processed into + * queued ANGIE commands. Next, the ANGIE command queue is sent to the + * ANGIE device and data received from the ANGIE device is cached. Finally, + * the post-processing function writes back data to the corresponding OpenOCD + * commands. + * + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_execute_queue(struct jtag_command *cmd_queue) +{ + struct jtag_command *cmd = cmd_queue; + int ret; + + while (cmd) { + switch (cmd->type) { + case JTAG_SCAN: + ret = angie_queue_scan(angie_handle, cmd); + break; + case JTAG_TLR_RESET: + ret = angie_queue_tlr_reset(angie_handle, cmd); + break; + case JTAG_RUNTEST: + ret = angie_queue_runtest(angie_handle, cmd); + break; + case JTAG_PATHMOVE: + ret = angie_queue_pathmove(angie_handle, cmd); + break; + case JTAG_SLEEP: + ret = angie_queue_sleep(angie_handle, cmd); + break; + case JTAG_STABLECLOCKS: + ret = angie_queue_stableclocks(angie_handle, cmd); + break; + default: + ret = ERROR_FAIL; + LOG_ERROR("BUG: encountered unknown JTAG command type"); + break; + } + + if (ret != ERROR_OK) + return ret; + + cmd = cmd->next; + } + + if (angie_handle->commands_in_queue > 0) { + ret = angie_execute_queued_commands(angie_handle, LIBUSB_TIMEOUT_MS); + if (ret != ERROR_OK) + return ret; + + ret = angie_post_process_queue(angie_handle); + if (ret != ERROR_OK) + return ret; + + angie_clear_queue(angie_handle); + } + + return ERROR_OK; +} + +/** + * Set the TCK frequency of the ANGIE adapter. + * + * @param khz desired JTAG TCK frequency. + * @param jtag_speed where to store corresponding adapter-specific speed value. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_khz(int khz, int *jtag_speed) +{ + int ret; + + if (khz == 0) { + LOG_ERROR("RCLK not supported"); + return ERROR_FAIL; + } + + /* CLOCK_TCK commands are decoupled from others. Therefore, the frequency + * setting can be done independently from all other commands. */ + if (khz >= 375) { + angie_handle->delay_clock_tck = -1; + } else { + ret = angie_calculate_delay(DELAY_CLOCK_TCK, khz * 1000, + &angie_handle->delay_clock_tck); + if (ret != ERROR_OK) + return ret; + } + + /* SCAN_{IN,OUT,IO} commands invoke CLOCK_TMS commands. Therefore, if the + * requested frequency goes below the maximum frequency for SLOW_CLOCK_TMS + * commands, all SCAN commands MUST also use the variable frequency + * implementation! */ + if (khz >= 176) { + angie_handle->delay_clock_tms = -1; + angie_handle->delay_scan_in = -1; + angie_handle->delay_scan_out = -1; + angie_handle->delay_scan_io = -1; + } else { + ret = angie_calculate_delay(DELAY_CLOCK_TMS, khz * 1000, + &angie_handle->delay_clock_tms); + if (ret != ERROR_OK) + return ret; + + ret = angie_calculate_delay(DELAY_SCAN_IN, khz * 1000, + &angie_handle->delay_scan_in); + if (ret != ERROR_OK) + return ret; + + ret = angie_calculate_delay(DELAY_SCAN_OUT, khz * 1000, + &angie_handle->delay_scan_out); + if (ret != ERROR_OK) + return ret; + + ret = angie_calculate_delay(DELAY_SCAN_IO, khz * 1000, + &angie_handle->delay_scan_io); + if (ret != ERROR_OK) + return ret; + } + + LOG_DEBUG_IO("ANGIE TCK setup: delay_tck = %i (%li Hz),", + angie_handle->delay_clock_tck, + angie_calculate_frequency(DELAY_CLOCK_TCK, angie_handle->delay_clock_tck)); + LOG_DEBUG_IO(" delay_tms = %i (%li Hz),", + angie_handle->delay_clock_tms, + angie_calculate_frequency(DELAY_CLOCK_TMS, angie_handle->delay_clock_tms)); + LOG_DEBUG_IO(" delay_scan_in = %i (%li Hz),", + angie_handle->delay_scan_in, + angie_calculate_frequency(DELAY_SCAN_IN, angie_handle->delay_scan_in)); + LOG_DEBUG_IO(" delay_scan_out = %i (%li Hz),", + angie_handle->delay_scan_out, + angie_calculate_frequency(DELAY_SCAN_OUT, angie_handle->delay_scan_out)); + LOG_DEBUG_IO(" delay_scan_io = %i (%li Hz),", + angie_handle->delay_scan_io, + angie_calculate_frequency(DELAY_SCAN_IO, angie_handle->delay_scan_io)); + + /* Configure the ANGIE device with the new delay values */ + ret = angie_append_configure_tck_cmd(angie_handle, + angie_handle->delay_scan_in, + angie_handle->delay_scan_out, + angie_handle->delay_scan_io, + angie_handle->delay_clock_tck, + angie_handle->delay_clock_tms); + + if (ret != ERROR_OK) + return ret; + + *jtag_speed = khz; + + return ERROR_OK; +} + +/** + * Set the TCK frequency of the ANGIE adapter. + * + * Because of the way the TCK frequency is set up in the ANGIE firmware, + * there are five different speed settings. To simplify things, the + * adapter-specific speed setting value is identical to the TCK frequency in + * khz. + * + * @param speed desired adapter-specific speed value. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_speed(int speed) +{ + int dummy; + + return angie_khz(speed, &dummy); +} + +/** + * Convert adapter-specific speed value to corresponding TCK frequency in kHz. + * + * Because of the way the TCK frequency is set up in the ANGIE firmware, + * there are five different speed settings. To simplify things, the + * adapter-specific speed setting value is identical to the TCK frequency in + * khz. + * + * @param speed adapter-specific speed value. + * @param khz where to store corresponding TCK frequency in kHz. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_speed_div(int speed, int *khz) +{ + *khz = speed; + + return ERROR_OK; +} + +/** + * Initiates the firmware download to the ANGIE adapter and prepares + * the USB handle. + * + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_init(void) +{ + int ret, transferred; + char str_manufacturer[20]; + bool download_firmware = false; + char dummy[64]; + uint8_t input_signals, output_signals; + + angie_handle = calloc(1, sizeof(struct angie)); + + if (!angie_handle) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + ret = angie_usb_open(angie_handle); + if (ret != ERROR_OK) { + free(angie_handle); + angie_handle = NULL; + return ret; + } + + /* Get String Descriptor to determine if firmware needs to be loaded */ + ret = libusb_get_string_descriptor_ascii(angie_handle->usb_device_handle, 1, (unsigned char *)str_manufacturer, 20); + if (ret < 0) { + /* Could not get descriptor -> Unconfigured or original Keil firmware */ + download_firmware = true; + } else { + /* We got a String Descriptor, check if it is the correct one */ + if (strncmp(str_manufacturer, "NanoXplore, SAS.", 16) != 0) + download_firmware = true; + } + + if (download_firmware) { + LOG_INFO("Loading ANGIE firmware. This is reversible by power-cycling ANGIE device."); + if (libusb_claim_interface(angie_handle->usb_device_handle, 0) != LIBUSB_SUCCESS) { + LOG_ERROR("Could not claim interface 0"); + return ERROR_FAIL; + } + ret = angie_load_firmware_and_renumerate(angie_handle, + ANGIE_FIRMWARE_FILE, ANGIE_RENUMERATION_DELAY_US); + if (ret != ERROR_OK) { + LOG_ERROR("Could not download firmware and re-numerate ANGIE"); + angie_quit(); + return ret; + } + ret = angie_load_bitstream(angie_handle, ANGIE_BITSTREAM_FILE); + if (ret != ERROR_OK) { + LOG_ERROR("Could not download bitstream"); + angie_quit(); + return ret; + } + if (libusb_release_interface(angie_handle->usb_device_handle, 0) != LIBUSB_SUCCESS) { + LOG_ERROR("Fail release interface 0"); + return ERROR_FAIL; + } + if (libusb_claim_interface(angie_handle->usb_device_handle, 1) != LIBUSB_SUCCESS) { + LOG_ERROR("Could not claim interface 1"); + return ERROR_FAIL; + } + /* Configure io extender 23: all input */ + ret = angie_io_extender_config(angie_handle, 0x23, 0xFF); + if (ret != ERROR_OK) { + LOG_ERROR("Could not configure io extender 23"); + return ret; + } + if (libusb_release_interface(angie_handle->usb_device_handle, 1) != LIBUSB_SUCCESS) { + LOG_ERROR("Fail release interface 1"); + return ERROR_FAIL; + } + } else { + LOG_INFO("ANGIE device is already running ANGIE firmware"); + } + + /* Get ANGIE USB IN/OUT endpoints and claim the interface 0 */ + ret = jtag_libusb_choose_interface(angie_handle->usb_device_handle, + &angie_handle->ep_in, &angie_handle->ep_out, 0xFF, 0, 0, -1); + if (ret != ERROR_OK) { + LOG_ERROR("Choose and claim interface failed"); + angie_quit(); + return ret; + } + + /* Initialize ANGIE command queue */ + angie_clear_queue(angie_handle); + + /* Issue one test command with short timeout */ + ret = angie_append_test_cmd(angie_handle); + if (ret != ERROR_OK) { + LOG_ERROR("Append test command failed."); + angie_quit(); + return ret; + } + + ret = angie_execute_queued_commands(angie_handle, 200); + if (ret != ERROR_OK) { + /* Sending test command failed. The ANGIE device may be forever waiting for + * the host to fetch an USB Bulk IN packet (e. g. OpenOCD crashed or was + * shut down by the user via Ctrl-C. Try to retrieve this Bulk IN packet. */ + + ret = jtag_libusb_bulk_write(angie_handle->usb_device_handle, angie_handle->ep_in, + dummy, 64, 200, &transferred); + + if (ret != ERROR_OK || transferred == 0) { + /* Bulk IN transfer failed -> unrecoverable error condition */ + LOG_ERROR("Cannot communicate with ANGIE device. Disconnect ANGIE from " + "the USB port and re-connect, then re-run OpenOCD"); + angie_quit(); + return ERROR_FAIL; + } + /* Successfully received Bulk IN packet -> continue */ + LOG_INFO("Recovered from lost Bulk IN packet"); + } + + angie_clear_queue(angie_handle); + + /* Execute get signals command */ + ret = angie_append_get_signals_cmd(angie_handle); + if (ret != ERROR_OK) { + LOG_ERROR("Append get signals command failed"); + angie_quit(); + return ret; + } + ret = angie_execute_queued_commands(angie_handle, 200); + if (ret != ERROR_OK) { + LOG_ERROR("Execute get signals command failed"); + angie_quit(); + return ret; + } + + /* Post-process the single CMD_GET_SIGNALS command */ + input_signals = angie_handle->queue_start->payload_in[0]; + output_signals = angie_handle->queue_start->payload_in[1]; + angie_dump_signal_states(input_signals, output_signals); + + angie_clear_queue(angie_handle); + + return ERROR_OK; +} + +/** + * Closes the USB handle for the ANGIE device. + * + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_quit(void) +{ + int ret = angie_usb_close(angie_handle); + free(angie_handle); + angie_handle = NULL; + + return ret; +} + +static struct jtag_interface angie_interface = { + .execute_queue = angie_execute_queue, +}; + +struct adapter_driver angie_adapter_driver = { + .name = "angie", + .transports = jtag_only, + + .init = angie_init, + .quit = angie_quit, + .reset = angie_reset, + .speed = angie_speed, + .khz = angie_khz, + .speed_div = angie_speed_div, + + .jtag_ops = &angie_interface, +}; diff --git a/src/jtag/drivers/angie/README b/src/jtag/drivers/angie/README new file mode 100644 index 0000000000..c727154c48 --- /dev/null +++ b/src/jtag/drivers/angie/README @@ -0,0 +1,3 @@ +This folder contain only the files needed by ANGIE's driver. +You will find the complete ANGIE's firmware and the bitstream's code source in +contrib/firmware. diff --git a/src/jtag/drivers/angie/angie_bitstream.bit b/src/jtag/drivers/angie/angie_bitstream.bit new file mode 100644 index 0000000000..7b3a88f7c8 Binary files /dev/null and b/src/jtag/drivers/angie/angie_bitstream.bit differ diff --git a/src/jtag/drivers/angie/angie_firmware.bin b/src/jtag/drivers/angie/angie_firmware.bin new file mode 100644 index 0000000000..68486ef8f0 Binary files /dev/null and b/src/jtag/drivers/angie/angie_firmware.bin differ diff --git a/src/jtag/drivers/angie/include/msgtypes.h b/src/jtag/drivers/angie/include/msgtypes.h new file mode 100644 index 0000000000..fb045e98c3 --- /dev/null +++ b/src/jtag/drivers/angie/include/msgtypes.h @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + +**************************************************************************** + File : msgtypes.h * + Contents : Definition of the commands supported by NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + <aboudjelida@nanoxplore.com> * + <ahmederrachedbjld@gmail.com> * +*****************************************************************************/ + +/** + * @file + * Definition of the commands supported by the ANGIE firmware. + * + * Basically, two types of commands can be distinguished: + * - Commands with fixed payload size + * - Commands with variable payload size + * + * SCAN commands (in all variations) carry payloads of variable size, all + * other commands carry payloads of fixed size. + * + * In the case of SCAN commands, the payload size (n) is calculated by + * dividing the scan_size_bits variable by 8, rounding up the result. + * + * Offset zero always contains the command ID. + * + **************************************************************************** + * CMD_SCAN_IN, CMD_SLOW_SCAN_IN: * + * * + * OUT: * + * offset 1: scan_size_bytes * + * offset 2: bits_last_byte * + * offset 3: tms_count_start + tms_count_end * + * offset 4: tms_sequence_start * + * offset 5: tms_sequence_end * + * * + * IN: * + * offset 0..n: TDO data * + **************************************************************************** + * CMD_SCAN_OUT, CMD_SLOW_SCAN_OUT: * + * * + * OUT: * + * offset 1: scan_size_bytes * + * offset 2: bits_last_byte * + * offset 3: tms_count_start + tms_count_end * + * offset 4: tms_sequence_start * + * offset 5: tms_sequence_end * + * offset 6..x: TDI data * + **************************************************************************** + * CMD_SCAN_IO, CMD_SLOW_SCAN_IO: * + * * + * OUT: * + * offset 1: scan_size_bytes * + * offset 2: bits_last_byte * + * offset 3: tms_count_start + tms_count_end * + * offset 4: tms_sequence_start * + * offset 5: tms_sequence_end * + * offset 6..x: TDI data * + * * + * IN: * + * offset 0..n: TDO data * + **************************************************************************** + * CMD_CLOCK_TMS, CMD_SLOW_CLOCK_TMS: * + * * + * OUT: * + * offset 1: tms_count * + * offset 2: tms_sequence * + **************************************************************************** + * CMD_CLOCK_TCK, CMD_SLOW_CLOCK_TCK: * + * * + * OUT: * + * offset 1: low byte of tck_count * + * offset 2: high byte of tck_count * + **************************************************************************** + * CMD_CLOCK_SLEEP_US: * + * * + * OUT: * + * offset 1: low byte of sleep_us * + * offset 2: high byte of sleep_us * + **************************************************************************** + * CMD_CLOCK_SLEEP_MS: * + * * + * OUT: * + * offset 1: low byte of sleep_ms * + * offset 2: high byte of sleep_ms * + **************************************************************************** + * CMD_GET_SIGNALS: * + * * + * IN: * + * offset 0: current state of input signals * + * offset 1: current state of output signals * + **************************************************************************** + * CMD_SET_SIGNALS: * + * * + * OUT: * + * offset 1: signals that should be de-asserted * + * offset 2: signals that should be asserted * + **************************************************************************** + * CMD_CONFIGURE_TCK_FREQ: * + * * + * OUT: * + * offset 1: delay value for scan_in function * + * offset 2: delay value for scan_out function * + * offset 3: delay value for scan_io function * + * offset 4: delay value for clock_tck function * + * offset 5: delay value for clock_tms function * + **************************************************************************** + * CMD_SET_LEDS: * + * * + * OUT: * + * offset 1: LED states: * + * Bit 0: turn COM LED on * + * Bit 1: turn RUN LED on * + * Bit 2: turn COM LED off * + * Bit 3: turn RUN LED off * + * Bits 7..4: Reserved * + **************************************************************************** + * CMD_TEST: * + * * + * OUT: * + * offset 1: unused dummy value * + **************************************************************************** + */ + +#ifndef __MSGTYPES_H +#define __MSGTYPES_H + +/* + * Command IDs: + * + * Bits 7..6: Reserved, should always be zero + * Bits 5..0: Command ID. There are 62 usable IDs. Of this 63 available IDs, + * the IDs 0x00..0x1F are commands with variable payload size, + * the IDs 0x20..0x3F are commands with fixed payload size. + */ + +#define CMD_ID_MASK 0x3F + +/* Commands with variable payload size */ +#define CMD_SCAN_IN 0x00 +#define CMD_SLOW_SCAN_IN 0x01 +#define CMD_SCAN_OUT 0x02 +#define CMD_SLOW_SCAN_OUT 0x03 +#define CMD_SCAN_IO 0x04 +#define CMD_SLOW_SCAN_IO 0x05 + +/* Commands with fixed payload size */ +#define CMD_CLOCK_TMS 0x20 +#define CMD_SLOW_CLOCK_TMS 0x21 +#define CMD_CLOCK_TCK 0x22 +#define CMD_SLOW_CLOCK_TCK 0x23 +#define CMD_SLEEP_US 0x24 +#define CMD_SLEEP_MS 0x25 +#define CMD_GET_SIGNALS 0x26 +#define CMD_SET_SIGNALS 0x27 +#define CMD_CONFIGURE_TCK_FREQ 0x28 +#define CMD_SET_LEDS 0x29 +#define CMD_TEST 0x2A + +/* JTAG signal definition for jtag_get_signals() -- Input signals! */ +#define SIGNAL_TDO 1 + +/* JTAG signal definition for jtag_get_signals() -- Output signals! */ +#define SIGNAL_TDI 8 +#define SIGNAL_TMS 2 +#define SIGNAL_TCK 4 +#define SIGNAL_TRST 1 +#define SIGNAL_SRST 32 + +#endif diff --git a/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c index 703378940b..4c50c54c9b 100644 --- a/src/jtag/drivers/arm-jtag-ew.c +++ b/src/jtag/drivers/arm-jtag-ew.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 by Dimitar Dimitrov <dinuxbg@gmail.com> * * based on Dominic Rath's and Benedikt Sauter's usbprog.c * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -96,9 +85,9 @@ static struct armjtagew *armjtagew_handle; /************************************************************************** * External interface implementation */ -static int armjtagew_execute_queue(void) +static int armjtagew_execute_queue(struct jtag_command *cmd_queue) { - struct jtag_command *cmd = jtag_command_queue; + struct jtag_command *cmd = cmd_queue; int scan_size; enum scan_type type; uint8_t *buffer; @@ -224,7 +213,7 @@ static int armjtagew_init(void) armjtagew_handle = armjtagew_usb_open(); - if (armjtagew_handle == 0) { + if (!armjtagew_handle) { LOG_ERROR( "Cannot find ARM-JTAG-EW Interface! Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; @@ -688,7 +677,7 @@ static struct armjtagew *armjtagew_usb_open(void) const uint16_t pids[] = { USB_PID, 0 }; struct libusb_device_handle *dev; - if (jtag_libusb_open(vids, pids, &dev, NULL) != ERROR_OK) + if (jtag_libusb_open(vids, pids, NULL, &dev, NULL) != ERROR_OK) return NULL; struct armjtagew *result = malloc(sizeof(struct armjtagew)); @@ -787,17 +776,12 @@ static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length) static void armjtagew_debug_buffer(uint8_t *buffer, int length) { - char line[81]; - char s[4]; - int i; - int j; + char line[8 + 3 * BYTES_PER_LINE + 1]; - for (i = 0; i < length; i += BYTES_PER_LINE) { - snprintf(line, 5, "%04x", i); - for (j = i; j < i + BYTES_PER_LINE && j < length; j++) { - snprintf(s, 4, " %02x", buffer[j]); - strcat(line, s); - } + for (int i = 0; i < length; i += BYTES_PER_LINE) { + int n = snprintf(line, 9, "%04x", i); + for (int j = i; j < i + BYTES_PER_LINE && j < length; j++) + n += snprintf(line + n, 4, " %02x", buffer[j]); LOG_DEBUG("%s", line); /* Prevent GDB timeout (writing to log might take some time) */ diff --git a/src/jtag/drivers/at91rm9200.c b/src/jtag/drivers/at91rm9200.c index 7bb5d85538..ba9ee5e34d 100644 --- a/src/jtag/drivers/at91rm9200.c +++ b/src/jtag/drivers/at91rm9200.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006 by Anders Larsen * * al@alarsen.net * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -118,7 +107,7 @@ static int at91rm9200_quit(void); static struct bitbang_interface at91rm9200_bitbang = { .read = at91rm9200_read, .write = at91rm9200_write, - .blink = 0 + .blink = NULL, }; static bb_value_t at91rm9200_read(void) @@ -168,8 +157,12 @@ COMMAND_HANDLER(at91rm9200_handle_device_command) return ERROR_COMMAND_SYNTAX_ERROR; /* only if the device name wasn't overwritten by cmdline */ - if (at91rm9200_device == 0) { + if (!at91rm9200_device) { at91rm9200_device = malloc(strlen(CMD_ARGV[0]) + sizeof(char)); + if (!at91rm9200_device) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } strcpy(at91rm9200_device, CMD_ARGV[0]); } diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index b7a4d998cd..ff10b0a78c 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -1,318 +1,300 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2013 by Paul Fertser, fercerpav@gmail.com * * * * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au * * Based on at91rm9200.c (c) Anders Larsen * * and RPi GPIO examples by Gert van Loo & Dom * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif +#include <jtag/adapter.h> #include <jtag/interface.h> #include <transport/transport.h> #include "bitbang.h" #include <sys/mman.h> -uint32_t bcm2835_peri_base = 0x20000000; +static char *bcm2835_peri_mem_dev; +static off_t bcm2835_peri_base = 0x20000000; #define BCM2835_GPIO_BASE (bcm2835_peri_base + 0x200000) /* GPIO controller */ #define BCM2835_PADS_GPIO_0_27 (bcm2835_peri_base + 0x100000) #define BCM2835_PADS_GPIO_0_27_OFFSET (0x2c / 4) +/* See "GPIO Function Select Registers (GPFSELn)" in "Broadcom BCM2835 ARM Peripherals" datasheet. */ +#define BCM2835_GPIO_MODE_INPUT 0 +#define BCM2835_GPIO_MODE_OUTPUT 1 + /* GPIO setup macros */ #define MODE_GPIO(g) (*(pio_base+((g)/10))>>(((g)%10)*3) & 7) #define INP_GPIO(g) do { *(pio_base+((g)/10)) &= ~(7<<(((g)%10)*3)); } while (0) #define SET_MODE_GPIO(g, m) do { /* clear the mode bits first, then set as necessary */ \ INP_GPIO(g); \ *(pio_base+((g)/10)) |= ((m)<<(((g)%10)*3)); } while (0) -#define OUT_GPIO(g) SET_MODE_GPIO(g, 1) +#define OUT_GPIO(g) SET_MODE_GPIO(g, BCM2835_GPIO_MODE_OUTPUT) #define GPIO_SET (*(pio_base+7)) /* sets bits which are 1, ignores bits which are 0 */ #define GPIO_CLR (*(pio_base+10)) /* clears bits which are 1, ignores bits which are 0 */ #define GPIO_LEV (*(pio_base+13)) /* current level of the pin */ static int dev_mem_fd; -static volatile uint32_t *pio_base; - -static bb_value_t bcm2835gpio_read(void); -static int bcm2835gpio_write(int tck, int tms, int tdi); - -static int bcm2835_swdio_read(void); -static void bcm2835_swdio_drive(bool is_output); -static int bcm2835gpio_swd_write(int swclk, int swdio); - -static int bcm2835gpio_init(void); -static int bcm2835gpio_quit(void); - -static struct bitbang_interface bcm2835gpio_bitbang = { - .read = bcm2835gpio_read, - .write = bcm2835gpio_write, - .swdio_read = bcm2835_swdio_read, - .swdio_drive = bcm2835_swdio_drive, - .swd_write = bcm2835gpio_swd_write, - .blink = NULL -}; - -/* GPIO numbers for each signal. Negative values are invalid */ -static int tck_gpio = -1; -static int tck_gpio_mode; -static int tms_gpio = -1; -static int tms_gpio_mode; -static int tdi_gpio = -1; -static int tdi_gpio_mode; -static int tdo_gpio = -1; -static int tdo_gpio_mode; -static int trst_gpio = -1; -static int trst_gpio_mode; -static int srst_gpio = -1; -static int srst_gpio_mode; -static int swclk_gpio = -1; -static int swclk_gpio_mode; -static int swdio_gpio = -1; -static int swdio_gpio_mode; -static int swdio_dir_gpio = -1; -static int swdio_dir_gpio_mode; +static volatile uint32_t *pio_base = MAP_FAILED; +static volatile uint32_t *pads_base = MAP_FAILED; /* Transition delay coefficients */ static int speed_coeff = 113714; static int speed_offset = 28; static unsigned int jtag_delay; -static bb_value_t bcm2835gpio_read(void) -{ - return (GPIO_LEV & 1<<tdo_gpio) ? BB_HIGH : BB_LOW; -} +static const struct adapter_gpio_config *adapter_gpio_config; +static struct initial_gpio_state { + unsigned int mode; + unsigned int output_level; +} initial_gpio_state[ADAPTER_GPIO_IDX_NUM]; +static uint32_t initial_drive_strength_etc; -static int bcm2835gpio_write(int tck, int tms, int tdi) +static inline const char *bcm2835_get_mem_dev(void) { - uint32_t set = tck<<tck_gpio | tms<<tms_gpio | tdi<<tdi_gpio; - uint32_t clear = !tck<<tck_gpio | !tms<<tms_gpio | !tdi<<tdi_gpio; + if (bcm2835_peri_mem_dev) + return bcm2835_peri_mem_dev; - GPIO_SET = set; - GPIO_CLR = clear; - - for (unsigned int i = 0; i < jtag_delay; i++) - asm volatile (""); - - return ERROR_OK; + return "/dev/gpiomem"; } -static int bcm2835gpio_swd_write(int swclk, int swdio) +static inline void bcm2835_gpio_synchronize(void) { - uint32_t set = swclk << swclk_gpio | swdio << swdio_gpio; - uint32_t clear = !swclk << swclk_gpio | !swdio << swdio_gpio; - - GPIO_SET = set; - GPIO_CLR = clear; + /* Ensure that previous writes to GPIO registers are flushed out of + * the inner shareable domain to prevent pipelined writes to the + * same address being merged. + */ + __sync_synchronize(); +} +static inline void bcm2835_delay(void) +{ for (unsigned int i = 0; i < jtag_delay; i++) asm volatile (""); - - return ERROR_OK; } -/* (1) assert or (0) deassert reset lines */ -static int bcm2835gpio_reset(int trst, int srst) +static bool is_gpio_config_valid(enum adapter_gpio_config_index idx) { - uint32_t set = 0; - uint32_t clear = 0; - - if (trst_gpio > 0) { - set |= !trst<<trst_gpio; - clear |= trst<<trst_gpio; - } - - if (srst_gpio > 0) { - set |= !srst<<srst_gpio; - clear |= srst<<srst_gpio; - } - - GPIO_SET = set; - GPIO_CLR = clear; - - return ERROR_OK; + /* Only chip 0 is supported, accept unset value (-1) too */ + return adapter_gpio_config[idx].gpio_num <= 31; } -static void bcm2835_swdio_drive(bool is_output) +static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int value) { - if (swdio_dir_gpio > 0) { - if (is_output) { - GPIO_SET = 1 << swdio_dir_gpio; - OUT_GPIO(swdio_gpio); + value = value ^ (gpio_config->active_low ? 1 : 0); + switch (gpio_config->drive) { + case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL: + if (value) + GPIO_SET = 1 << gpio_config->gpio_num; + else + GPIO_CLR = 1 << gpio_config->gpio_num; + /* For performance reasons assume the GPIO is already set as an output + * and therefore the call can be omitted here. + */ + break; + case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN: + if (value) { + INP_GPIO(gpio_config->gpio_num); } else { - INP_GPIO(swdio_gpio); - GPIO_CLR = 1 << swdio_dir_gpio; + GPIO_CLR = 1 << gpio_config->gpio_num; + OUT_GPIO(gpio_config->gpio_num); } - } else { - if (is_output) - OUT_GPIO(swdio_gpio); - else - INP_GPIO(swdio_gpio); + break; + case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE: + if (value) { + GPIO_SET = 1 << gpio_config->gpio_num; + OUT_GPIO(gpio_config->gpio_num); + } else { + INP_GPIO(gpio_config->gpio_num); + } + break; } + bcm2835_gpio_synchronize(); } -static int bcm2835_swdio_read(void) +static void restore_gpio(enum adapter_gpio_config_index idx) { - return !!(GPIO_LEV & 1 << swdio_gpio); -} - -static int bcm2835gpio_khz(int khz, int *jtag_speed) -{ - if (!khz) { - LOG_DEBUG("RCLK not supported"); - return ERROR_FAIL; + if (is_gpio_config_valid(idx)) { + SET_MODE_GPIO(adapter_gpio_config[idx].gpio_num, initial_gpio_state[idx].mode); + if (initial_gpio_state[idx].mode == BCM2835_GPIO_MODE_OUTPUT) { + if (initial_gpio_state[idx].output_level) + GPIO_SET = 1 << adapter_gpio_config[idx].gpio_num; + else + GPIO_CLR = 1 << adapter_gpio_config[idx].gpio_num; + } } - *jtag_speed = speed_coeff/khz - speed_offset; - if (*jtag_speed < 0) - *jtag_speed = 0; - return ERROR_OK; + bcm2835_gpio_synchronize(); } -static int bcm2835gpio_speed_div(int speed, int *khz) +static void initialize_gpio(enum adapter_gpio_config_index idx) { - *khz = speed_coeff/(speed + speed_offset); - return ERROR_OK; -} + if (!is_gpio_config_valid(idx)) + return; + + initial_gpio_state[idx].mode = MODE_GPIO(adapter_gpio_config[idx].gpio_num); + unsigned int shift = adapter_gpio_config[idx].gpio_num; + initial_gpio_state[idx].output_level = (GPIO_LEV >> shift) & 1; + LOG_DEBUG("saved GPIO mode for %s (GPIO %d %d): %d", + adapter_gpio_get_name(idx), adapter_gpio_config[idx].chip_num, adapter_gpio_config[idx].gpio_num, + initial_gpio_state[idx].mode); + + if (adapter_gpio_config[idx].pull != ADAPTER_GPIO_PULL_NONE) { + LOG_WARNING("BCM2835 GPIO does not support pull-up or pull-down settings (signal %s)", + adapter_gpio_get_name(idx)); + } -static int bcm2835gpio_speed(int speed) -{ - jtag_delay = speed; - return ERROR_OK; -} + switch (adapter_gpio_config[idx].init_state) { + case ADAPTER_GPIO_INIT_STATE_INACTIVE: + set_gpio_value(&adapter_gpio_config[idx], 0); + break; + case ADAPTER_GPIO_INIT_STATE_ACTIVE: + set_gpio_value(&adapter_gpio_config[idx], 1); + break; + case ADAPTER_GPIO_INIT_STATE_INPUT: + INP_GPIO(adapter_gpio_config[idx].gpio_num); + break; + } -static int is_gpio_valid(int gpio) -{ - return gpio >= 0 && gpio <= 31; + /* Direction for non push-pull is already set by set_gpio_value() */ + if (adapter_gpio_config[idx].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL + && adapter_gpio_config[idx].init_state != ADAPTER_GPIO_INIT_STATE_INPUT) + OUT_GPIO(adapter_gpio_config[idx].gpio_num); + bcm2835_gpio_synchronize(); } -COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionums) +static bb_value_t bcm2835gpio_read(void) { - if (CMD_ARGC == 4) { - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio); - COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio); - COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio); - COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio); - } else if (CMD_ARGC != 0) { - return ERROR_COMMAND_SYNTAX_ERROR; - } + unsigned int shift = adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].gpio_num; + uint32_t value = (GPIO_LEV >> shift) & 1; + return value ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].active_low ? BB_HIGH : BB_LOW); - command_print(CMD, - "BCM2835 GPIO config: tck = %d, tms = %d, tdi = %d, tdo = %d", - tck_gpio, tms_gpio, tdi_gpio, tdo_gpio); - - return ERROR_OK; } -COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tck) +static int bcm2835gpio_write(int tck, int tms, int tdi) { - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio); + uint32_t set = tck << adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num | + tms << adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num | + tdi << adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num; + uint32_t clear = !tck << adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num | + !tms << adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num | + !tdi << adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num; - command_print(CMD, "BCM2835 GPIO config: tck = %d", tck_gpio); - return ERROR_OK; -} + GPIO_SET = set; + GPIO_CLR = clear; + bcm2835_gpio_synchronize(); -COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tms) -{ - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio); + bcm2835_delay(); - command_print(CMD, "BCM2835 GPIO config: tms = %d", tms_gpio); return ERROR_OK; } -COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdo) +/* Requires push-pull drive mode for swclk and swdio */ +static int bcm2835gpio_swd_write_fast(int swclk, int swdio) { - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio); + swclk = swclk ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].active_low ? 1 : 0); + swdio = swdio ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low ? 1 : 0); - command_print(CMD, "BCM2835 GPIO config: tdo = %d", tdo_gpio); - return ERROR_OK; -} + uint32_t set = swclk << adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num | + swdio << adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num; + uint32_t clear = !swclk << adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num | + !swdio << adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num; -COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_tdi) -{ - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio); + GPIO_SET = set; + GPIO_CLR = clear; + bcm2835_gpio_synchronize(); + + bcm2835_delay(); - command_print(CMD, "BCM2835 GPIO config: tdi = %d", tdi_gpio); return ERROR_OK; } -COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_srst) +/* Generic mode that works for open-drain/open-source drive modes, but slower */ +static int bcm2835gpio_swd_write_generic(int swclk, int swdio) { - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio); + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO], swdio); + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK], swclk); /* Write clock last */ + + bcm2835_delay(); - command_print(CMD, "BCM2835 GPIO config: srst = %d", srst_gpio); return ERROR_OK; } -COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionum_trst) +/* (1) assert or (0) deassert reset lines */ +static int bcm2835gpio_reset(int trst, int srst) { - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio); - - command_print(CMD, "BCM2835 GPIO config: trst = %d", trst_gpio); + /* As the "adapter reset_config" command keeps the srst and trst gpio drive + * mode settings in sync we can use our standard set_gpio_value() function + * that honours drive mode and active low. + */ + if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SRST)) + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SRST], srst); + + if (is_gpio_config_valid(ADAPTER_GPIO_IDX_TRST)) + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_TRST], trst); + + LOG_DEBUG("trst %d gpio: %d %d, srst %d gpio: %d %d", + trst, + (int)adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].chip_num, + (int)adapter_gpio_config[ADAPTER_GPIO_IDX_TRST].gpio_num, + srst, + (int)adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].chip_num, + (int)adapter_gpio_config[ADAPTER_GPIO_IDX_SRST].gpio_num); return ERROR_OK; } -COMMAND_HANDLER(bcm2835gpio_handle_swd_gpionums) +static void bcm2835_swdio_drive(bool is_output) { - if (CMD_ARGC == 2) { - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio); - COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], swdio_gpio); - } else if (CMD_ARGC != 0) { - return ERROR_COMMAND_SYNTAX_ERROR; + if (is_output) { + if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR)) + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 1); + OUT_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num); + } else { + INP_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num); + if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR)) + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 0); } - - command_print(CMD, - "BCM2835 GPIO nums: swclk = %d, swdio = %d", - swclk_gpio, swdio_gpio); - - return ERROR_OK; + bcm2835_gpio_synchronize(); } -COMMAND_HANDLER(bcm2835gpio_handle_swd_gpionum_swclk) +static int bcm2835_swdio_read(void) { - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio); + unsigned int shift = adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num; + uint32_t value = (GPIO_LEV >> shift) & 1; + return value ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low ? 1 : 0); +} - command_print(CMD, "BCM2835 num: swclk = %d", swclk_gpio); +static int bcm2835gpio_khz(int khz, int *jtag_speed) +{ + if (!khz) { + LOG_DEBUG("BCM2835 GPIO: RCLK not supported"); + return ERROR_FAIL; + } + *jtag_speed = DIV_ROUND_UP(speed_coeff, khz) - speed_offset; + LOG_DEBUG("jtag_delay %d", *jtag_speed); + if (*jtag_speed < 0) + *jtag_speed = 0; return ERROR_OK; } -COMMAND_HANDLER(bcm2835gpio_handle_swd_gpionum_swdio) +static int bcm2835gpio_speed_div(int speed, int *khz) { - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio); - - command_print(CMD, "BCM2835 num: swdio = %d", swdio_gpio); + int divisor = speed + speed_offset; + /* divide with roundig to the closest */ + *khz = (speed_coeff + divisor / 2) / divisor; return ERROR_OK; } -COMMAND_HANDLER(bcm2835gpio_handle_swd_dir_gpionum_swdio) +static int bcm2835gpio_speed(int speed) { - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_dir_gpio); - - command_print(CMD, "BCM2835 num: swdio_dir = %d", swdio_dir_gpio); + jtag_delay = speed; return ERROR_OK; } @@ -328,94 +310,33 @@ COMMAND_HANDLER(bcm2835gpio_handle_speed_coeffs) return ERROR_OK; } +COMMAND_HANDLER(bcm2835gpio_handle_peripheral_mem_dev) +{ + if (CMD_ARGC == 1) { + free(bcm2835_peri_mem_dev); + bcm2835_peri_mem_dev = strdup(CMD_ARGV[0]); + } + + command_print(CMD, "BCM2835 GPIO: peripheral_mem_dev = %s", + bcm2835_get_mem_dev()); + return ERROR_OK; +} + COMMAND_HANDLER(bcm2835gpio_handle_peripheral_base) { - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], bcm2835_peri_base); + uint64_t tmp_base; + if (CMD_ARGC == 1) { + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], tmp_base); + bcm2835_peri_base = (off_t)tmp_base; + } - command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08x", - bcm2835_peri_base); + tmp_base = bcm2835_peri_base; + command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08" PRIx64, + tmp_base); return ERROR_OK; } static const struct command_registration bcm2835gpio_subcommand_handlers[] = { - { - .name = "jtag_nums", - .handler = &bcm2835gpio_handle_jtag_gpionums, - .mode = COMMAND_CONFIG, - .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)", - .usage = "[tck tms tdi tdo]", - }, - { - .name = "tck_num", - .handler = &bcm2835gpio_handle_jtag_gpionum_tck, - .mode = COMMAND_CONFIG, - .help = "gpio number for tck.", - .usage = "[tck]", - }, - { - .name = "tms_num", - .handler = &bcm2835gpio_handle_jtag_gpionum_tms, - .mode = COMMAND_CONFIG, - .help = "gpio number for tms.", - .usage = "[tms]", - }, - { - .name = "tdo_num", - .handler = &bcm2835gpio_handle_jtag_gpionum_tdo, - .mode = COMMAND_CONFIG, - .help = "gpio number for tdo.", - .usage = "[tdo]", - }, - { - .name = "tdi_num", - .handler = &bcm2835gpio_handle_jtag_gpionum_tdi, - .mode = COMMAND_CONFIG, - .help = "gpio number for tdi.", - .usage = "[tdi]", - }, - { - .name = "swd_nums", - .handler = &bcm2835gpio_handle_swd_gpionums, - .mode = COMMAND_CONFIG, - .help = "gpio numbers for swclk, swdio. (in that order)", - .usage = "[swclk swdio]", - }, - { - .name = "swclk_num", - .handler = &bcm2835gpio_handle_swd_gpionum_swclk, - .mode = COMMAND_CONFIG, - .help = "gpio number for swclk.", - .usage = "[swclk]", - }, - { - .name = "swdio_num", - .handler = &bcm2835gpio_handle_swd_gpionum_swdio, - .mode = COMMAND_CONFIG, - .help = "gpio number for swdio.", - .usage = "[swdio]", - }, - { - .name = "swdio_dir_num", - .handler = &bcm2835gpio_handle_swd_dir_gpionum_swdio, - .mode = COMMAND_CONFIG, - .help = "gpio number for swdio direction control pin (set=output mode, clear=input mode)", - .usage = "[swdio_dir]", - }, - { - .name = "srst_num", - .handler = &bcm2835gpio_handle_jtag_gpionum_srst, - .mode = COMMAND_CONFIG, - .help = "gpio number for srst.", - .usage = "[srst]", - }, - { - .name = "trst_num", - .handler = &bcm2835gpio_handle_jtag_gpionum_trst, - .mode = COMMAND_CONFIG, - .help = "gpio number for trst.", - .usage = "[trst]", - }, { .name = "speed_coeffs", .handler = &bcm2835gpio_handle_speed_coeffs, @@ -423,11 +344,18 @@ static const struct command_registration bcm2835gpio_subcommand_handlers[] = { .help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.", .usage = "[SPEED_COEFF SPEED_OFFSET]", }, + { + .name = "peripheral_mem_dev", + .handler = &bcm2835gpio_handle_peripheral_mem_dev, + .mode = COMMAND_CONFIG, + .help = "device to map memory mapped GPIOs from.", + .usage = "[device]", + }, { .name = "peripheral_base", .handler = &bcm2835gpio_handle_peripheral_base, .mode = COMMAND_CONFIG, - .help = "peripheral base to access GPIOs (RPi1 0x20000000, RPi2 0x3F000000).", + .help = "peripheral base to access GPIOs, not needed with /dev/gpiomem.", .usage = "[base]", }, @@ -445,57 +373,65 @@ static const struct command_registration bcm2835gpio_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static const char * const bcm2835_transports[] = { "jtag", "swd", NULL }; - -static struct jtag_interface bcm2835gpio_interface = { - .supported = DEBUG_CAP_TMS_SEQ, - .execute_queue = bitbang_execute_queue, -}; - -struct adapter_driver bcm2835gpio_adapter_driver = { - .name = "bcm2835gpio", - .transports = bcm2835_transports, - .commands = bcm2835gpio_command_handlers, - - .init = bcm2835gpio_init, - .quit = bcm2835gpio_quit, - .reset = bcm2835gpio_reset, - .speed = bcm2835gpio_speed, - .khz = bcm2835gpio_khz, - .speed_div = bcm2835gpio_speed_div, - - .jtag_ops = &bcm2835gpio_interface, - .swd_ops = &bitbang_swd, -}; - static bool bcm2835gpio_jtag_mode_possible(void) { - if (!is_gpio_valid(tck_gpio)) - return 0; - if (!is_gpio_valid(tms_gpio)) - return 0; - if (!is_gpio_valid(tdi_gpio)) - return 0; - if (!is_gpio_valid(tdo_gpio)) - return 0; - return 1; + if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TCK)) + return false; + if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TMS)) + return false; + if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TDI)) + return false; + if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TDO)) + return false; + return true; } static bool bcm2835gpio_swd_mode_possible(void) { - if (!is_gpio_valid(swclk_gpio)) - return 0; - if (!is_gpio_valid(swdio_gpio)) - return 0; - return 1; + if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_SWCLK)) + return false; + if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO)) + return false; + return true; } -static int bcm2835gpio_init(void) +static void bcm2835gpio_munmap(void) { - bitbang_interface = &bcm2835gpio_bitbang; + if (pio_base != MAP_FAILED) { + munmap((void *)pio_base, sysconf(_SC_PAGE_SIZE)); + pio_base = MAP_FAILED; + } + + if (pads_base != MAP_FAILED) { + munmap((void *)pads_base, sysconf(_SC_PAGE_SIZE)); + pads_base = MAP_FAILED; + } +} + +static int bcm2835gpio_blink(int on) +{ + if (is_gpio_config_valid(ADAPTER_GPIO_IDX_LED)) + set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_LED], on); + + return ERROR_OK; +} + +static struct bitbang_interface bcm2835gpio_bitbang = { + .read = bcm2835gpio_read, + .write = bcm2835gpio_write, + .swdio_read = bcm2835_swdio_read, + .swdio_drive = bcm2835_swdio_drive, + .swd_write = bcm2835gpio_swd_write_generic, + .blink = bcm2835gpio_blink, +}; +static int bcm2835gpio_init(void) +{ LOG_INFO("BCM2835 GPIO JTAG/SWD bitbang driver"); + bitbang_interface = &bcm2835gpio_bitbang; + adapter_gpio_config = adapter_gpio_get_config(); + if (transport_is_jtag() && !bcm2835gpio_jtag_mode_possible()) { LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode"); return ERROR_JTAG_INIT_FAILED; @@ -506,13 +442,16 @@ static int bcm2835gpio_init(void) return ERROR_JTAG_INIT_FAILED; } - dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC); - if (dev_mem_fd < 0) { - LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem"); - dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC); - } + bool is_gpiomem = strcmp(bcm2835_get_mem_dev(), "/dev/gpiomem") == 0; + bool pad_mapping_possible = !is_gpiomem; + + dev_mem_fd = open(bcm2835_get_mem_dev(), O_RDWR | O_SYNC); if (dev_mem_fd < 0) { - LOG_ERROR("open: %s", strerror(errno)); + LOG_ERROR("open %s: %s", bcm2835_get_mem_dev(), strerror(errno)); + /* TODO: add /dev/mem specific doc and refer to it + * if (!is_gpiomem && (errno == EACCES || errno == EPERM)) + * LOG_INFO("Consult the user's guide chapter 4.? how to set permissions and capabilities"); + */ return ERROR_JTAG_INIT_FAILED; } @@ -525,71 +464,69 @@ static int bcm2835gpio_init(void) return ERROR_JTAG_INIT_FAILED; } - static volatile uint32_t *pads_base; - pads_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE, + /* TODO: move pads config to a separate utility */ + if (pad_mapping_possible) { + pads_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem_fd, BCM2835_PADS_GPIO_0_27); - if (pads_base == MAP_FAILED) { - LOG_ERROR("mmap: %s", strerror(errno)); - close(dev_mem_fd); - return ERROR_JTAG_INIT_FAILED; + if (pads_base == MAP_FAILED) { + LOG_ERROR("mmap pads: %s", strerror(errno)); + LOG_WARNING("Continuing with unchanged GPIO pad settings (drive strength and slew rate)"); + } + } else { + pads_base = MAP_FAILED; } - /* set 4mA drive strength, slew rate limited, hysteresis on */ - pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1; + close(dev_mem_fd); + + if (pads_base != MAP_FAILED) { + /* set 4mA drive strength, slew rate limited, hysteresis on */ + initial_drive_strength_etc = pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] & 0x1f; +LOG_INFO("initial pads conf %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]); + pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1; +LOG_INFO("pads conf set to %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]); + } - /* - * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST - * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. + /* Configure JTAG/SWD signals. Default directions and initial states are handled + * by adapter.c and "adapter gpio" command. */ if (transport_is_jtag()) { - tdo_gpio_mode = MODE_GPIO(tdo_gpio); - tdi_gpio_mode = MODE_GPIO(tdi_gpio); - tck_gpio_mode = MODE_GPIO(tck_gpio); - tms_gpio_mode = MODE_GPIO(tms_gpio); - - INP_GPIO(tdo_gpio); - - GPIO_CLR = 1<<tdi_gpio | 1<<tck_gpio; - GPIO_SET = 1<<tms_gpio; - - OUT_GPIO(tdi_gpio); - OUT_GPIO(tck_gpio); - OUT_GPIO(tms_gpio); - - if (trst_gpio != -1) { - trst_gpio_mode = MODE_GPIO(trst_gpio); - GPIO_SET = 1 << trst_gpio; - OUT_GPIO(trst_gpio); - } + initialize_gpio(ADAPTER_GPIO_IDX_TDO); + initialize_gpio(ADAPTER_GPIO_IDX_TDI); + initialize_gpio(ADAPTER_GPIO_IDX_TMS); + initialize_gpio(ADAPTER_GPIO_IDX_TCK); + initialize_gpio(ADAPTER_GPIO_IDX_TRST); } if (transport_is_swd()) { - /* Make buffer an output before the GPIO connected to it */ - if (swdio_dir_gpio != -1) { - swdio_dir_gpio_mode = MODE_GPIO(swdio_dir_gpio); - GPIO_SET = 1 << swdio_dir_gpio; - OUT_GPIO(swdio_dir_gpio); + /* swdio and its buffer should be initialized in the order that prevents + * two outputs from being connected together. This will occur if the + * swdio GPIO of the AM335x is configured as an output while its + * external buffer is configured to send the swdio signal from the + * target to the AM335x. + */ + if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].init_state == ADAPTER_GPIO_INIT_STATE_INPUT) { + initialize_gpio(ADAPTER_GPIO_IDX_SWDIO); + initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR); + } else { + initialize_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR); + initialize_gpio(ADAPTER_GPIO_IDX_SWDIO); } - swclk_gpio_mode = MODE_GPIO(swclk_gpio); - swdio_gpio_mode = MODE_GPIO(swdio_gpio); - - GPIO_CLR = 1<<swdio_gpio | 1<<swclk_gpio; - - OUT_GPIO(swclk_gpio); - OUT_GPIO(swdio_gpio); - } + initialize_gpio(ADAPTER_GPIO_IDX_SWCLK); - if (srst_gpio != -1) { - srst_gpio_mode = MODE_GPIO(srst_gpio); - GPIO_SET = 1 << srst_gpio; - OUT_GPIO(srst_gpio); + if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL && + adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL) { + LOG_DEBUG("BCM2835 GPIO using fast mode for SWD write"); + bcm2835gpio_bitbang.swd_write = bcm2835gpio_swd_write_fast; + } else { + LOG_DEBUG("BCM2835 GPIO using generic mode for SWD write"); + bcm2835gpio_bitbang.swd_write = bcm2835gpio_swd_write_generic; + } } - LOG_DEBUG("saved pinmux settings: tck %d tms %d tdi %d " - "tdo %d trst %d srst %d", tck_gpio_mode, tms_gpio_mode, - tdi_gpio_mode, tdo_gpio_mode, trst_gpio_mode, srst_gpio_mode); + initialize_gpio(ADAPTER_GPIO_IDX_SRST); + initialize_gpio(ADAPTER_GPIO_IDX_LED); return ERROR_OK; } @@ -597,24 +534,57 @@ static int bcm2835gpio_init(void) static int bcm2835gpio_quit(void) { if (transport_is_jtag()) { - SET_MODE_GPIO(tdo_gpio, tdo_gpio_mode); - SET_MODE_GPIO(tdi_gpio, tdi_gpio_mode); - SET_MODE_GPIO(tck_gpio, tck_gpio_mode); - SET_MODE_GPIO(tms_gpio, tms_gpio_mode); - if (trst_gpio != -1) - SET_MODE_GPIO(trst_gpio, trst_gpio_mode); + restore_gpio(ADAPTER_GPIO_IDX_TDO); + restore_gpio(ADAPTER_GPIO_IDX_TDI); + restore_gpio(ADAPTER_GPIO_IDX_TCK); + restore_gpio(ADAPTER_GPIO_IDX_TMS); + restore_gpio(ADAPTER_GPIO_IDX_TRST); } if (transport_is_swd()) { - SET_MODE_GPIO(swclk_gpio, swclk_gpio_mode); - SET_MODE_GPIO(swdio_gpio, swdio_gpio_mode); + /* Restore swdio/swdio_dir to their initial modes, even if that means + * connecting two outputs. Begin by making swdio an input so that the + * current and final states of swdio and swdio_dir do not have to be + * considered to calculate the safe restoration order. + */ + INP_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num); + restore_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR); + restore_gpio(ADAPTER_GPIO_IDX_SWDIO); + restore_gpio(ADAPTER_GPIO_IDX_SWCLK); } - if (srst_gpio != -1) - SET_MODE_GPIO(srst_gpio, srst_gpio_mode); + restore_gpio(ADAPTER_GPIO_IDX_SRST); + restore_gpio(ADAPTER_GPIO_IDX_LED); - if (swdio_dir_gpio != -1) - SET_MODE_GPIO(swdio_dir_gpio, swdio_dir_gpio_mode); + if (pads_base != MAP_FAILED) { + /* Restore drive strength. MSB is password ("5A") */ + pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5A000000 | initial_drive_strength_etc; + } + bcm2835gpio_munmap(); + free(bcm2835_peri_mem_dev); return ERROR_OK; } + + +static const char * const bcm2835_transports[] = { "jtag", "swd", NULL }; + +static struct jtag_interface bcm2835gpio_interface = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = bitbang_execute_queue, +}; +struct adapter_driver bcm2835gpio_adapter_driver = { + .name = "bcm2835gpio", + .transports = bcm2835_transports, + .commands = bcm2835gpio_command_handlers, + + .init = bcm2835gpio_init, + .quit = bcm2835gpio_quit, + .reset = bcm2835gpio_reset, + .speed = bcm2835gpio_speed, + .khz = bcm2835gpio_khz, + .speed_div = bcm2835gpio_speed_div, + + .jtag_ops = &bcm2835gpio_interface, + .swd_ops = &bitbang_swd, +}; diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c index 898d6d3df9..8df51764b7 100644 --- a/src/jtag/drivers/bitbang.c +++ b/src/jtag/drivers/bitbang.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ /* 2014-12: Addition of the SWD protocol support is based on the initial work @@ -26,6 +15,7 @@ #include "config.h" #endif +#include <jtag/jtag.h> /* Added to avoid include loop in commands.h */ #include "bitbang.h" #include <jtag/interface.h> #include <jtag/commands.h> @@ -289,9 +279,18 @@ static int bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, return ERROR_OK; } -int bitbang_execute_queue(void) +static void bitbang_sleep(unsigned int microseconds) { - struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ + if (bitbang_interface->sleep) { + bitbang_interface->sleep(microseconds); + } else { + jtag_sleep(microseconds); + } +} + +int bitbang_execute_queue(struct jtag_command *cmd_queue) +{ + struct jtag_command *cmd = cmd_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; @@ -362,7 +361,9 @@ int bitbang_execute_queue(void) break; case JTAG_SLEEP: LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); - jtag_sleep(cmd->cmd.sleep->us); + if (bitbang_interface->flush && (bitbang_interface->flush() != ERROR_OK)) + return ERROR_FAIL; + bitbang_sleep(cmd->cmd.sleep->us); break; case JTAG_TMS: retval = bitbang_execute_tms(cmd); @@ -391,8 +392,6 @@ static int bitbang_swd_init(void) static void bitbang_swd_exchange(bool rnw, uint8_t buf[], unsigned int offset, unsigned int bit_cnt) { - LOG_DEBUG("bitbang_swd_exchange"); - if (bitbang_interface->blink) { /* FIXME: we should manage errors */ bitbang_interface->blink(1); @@ -423,11 +422,9 @@ static void bitbang_swd_exchange(bool rnw, uint8_t buf[], unsigned int offset, u static int bitbang_swd_switch_seq(enum swd_special_seq seq) { - LOG_DEBUG("bitbang_swd_switch_seq"); - switch (seq) { case LINE_RESET: - LOG_DEBUG("SWD line reset"); + LOG_DEBUG_IO("SWD line reset"); bitbang_swd_exchange(false, (uint8_t *)swd_seq_line_reset, 0, swd_seq_line_reset_len); break; case JTAG_TO_SWD: @@ -470,7 +467,6 @@ static void swd_clear_sticky_errors(void) static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { - LOG_DEBUG("bitbang_swd_read_reg"); assert(cmd & SWD_CMD_RNW); if (queued_retval != ERROR_OK) { @@ -492,7 +488,7 @@ static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay uint32_t data = buf_get_u32(trn_ack_data_parity_trn, 1 + 3, 32); int parity = buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 32, 1); - LOG_DEBUG("%s %s read reg %X = %08"PRIx32, + LOG_DEBUG_IO("%s %s read reg %X = %08" PRIx32, ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", cmd & SWD_CMD_APNDP ? "AP" : "DP", (cmd & SWD_CMD_A32) >> 1, @@ -521,7 +517,6 @@ static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { - LOG_DEBUG("bitbang_swd_write_reg"); assert(!(cmd & SWD_CMD_RNW)); if (queued_retval != ERROR_OK) { @@ -532,8 +527,9 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay /* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */ bool check_ack = swd_cmd_returns_ack(cmd); + /* init the array to silence scan-build */ + uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)] = {0}; for (;;) { - uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)]; buf_set_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32, value); buf_set_u32(trn_ack_data_parity_trn, 1 + 3 + 1 + 32, 1, parity_u32(value)); @@ -541,13 +537,25 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay bitbang_swd_exchange(false, &cmd, 0, 8); bitbang_interface->swdio_drive(false); - bitbang_swd_exchange(true, trn_ack_data_parity_trn, 0, 1 + 3 + 1); + bitbang_swd_exchange(true, trn_ack_data_parity_trn, 0, 1 + 3); + + /* Avoid a glitch on SWDIO when changing the direction to output. + * To keep performance penalty minimal, pre-write the first data + * bit to SWDIO GPIO output buffer while clocking the turnaround bit. + * Following swdio_drive(true) outputs the pre-written value + * and the same value is rewritten by the next swd_write() + * instead of glitching SWDIO + * HiZ/pull-up --------------> 0 -------------> 1 + * swdio_drive(true) swd_write(0,1) + * in case of data bit 0 = 1 + */ + bitbang_swd_exchange(false, trn_ack_data_parity_trn, 1 + 3 + 1, 1); bitbang_interface->swdio_drive(true); bitbang_swd_exchange(false, trn_ack_data_parity_trn, 1 + 3 + 1, 32 + 1); int ack = buf_get_u32(trn_ack_data_parity_trn, 1, 3); - LOG_DEBUG("%s%s %s write reg %X = %08"PRIx32, + LOG_DEBUG_IO("%s%s %s write reg %X = %08" PRIx32, check_ack ? "" : "ack ignored ", ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", cmd & SWD_CMD_APNDP ? "AP" : "DP", @@ -572,14 +580,13 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay static int bitbang_swd_run_queue(void) { - LOG_DEBUG("bitbang_swd_run_queue"); /* A transaction must be followed by another transaction or at least 8 idle cycles to * ensure that data is clocked through the AP. */ bitbang_swd_exchange(true, NULL, 0, 8); int retval = queued_retval; queued_retval = ERROR_OK; - LOG_DEBUG("SWD queue return value: %02x", retval); + LOG_DEBUG_IO("SWD queue return value: %02x", retval); return retval; } diff --git a/src/jtag/drivers/bitbang.h b/src/jtag/drivers/bitbang.h index bc2c506bc7..dc941796e2 100644 --- a/src/jtag/drivers/bitbang.h +++ b/src/jtag/drivers/bitbang.h @@ -1,28 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_BITBANG_H #define OPENOCD_JTAG_DRIVERS_BITBANG_H #include <jtag/swd.h> +#include <jtag/commands.h> typedef enum { BB_LOW, @@ -65,11 +55,17 @@ struct bitbang_interface { /** Set SWCLK and SWDIO to the given value. */ int (*swd_write)(int swclk, int swdio); + + /** Sleep for some number of microseconds. **/ + int (*sleep)(unsigned int microseconds); + + /** Force a flush. */ + int (*flush)(void); }; extern const struct swd_driver bitbang_swd; -int bitbang_execute_queue(void); +int bitbang_execute_queue(struct jtag_command *cmd_queue); extern struct bitbang_interface *bitbang_interface; diff --git a/src/jtag/drivers/bitq.c b/src/jtag/drivers/bitq.c index 04fc78b586..2e5cca2a49 100644 --- a/src/jtag/drivers/bitq.c +++ b/src/jtag/drivers/bitq.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * -* * -* 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -214,11 +203,11 @@ static void bitq_scan(struct scan_command *cmd) bitq_scan_field(&cmd->fields[i], 1); } -int bitq_execute_queue(void) +int bitq_execute_queue(struct jtag_command *cmd_queue) { - struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ + struct jtag_command *cmd = cmd_queue; /* currently processed command */ - bitq_in_state.cmd = jtag_command_queue; + bitq_in_state.cmd = cmd_queue; bitq_in_state.field_idx = 0; bitq_in_state.bit_pos = 0; bitq_in_state.status = ERROR_OK; diff --git a/src/jtag/drivers/bitq.h b/src/jtag/drivers/bitq.h index df6a08d445..3ed182da4c 100644 --- a/src/jtag/drivers/bitq.h +++ b/src/jtag/drivers/bitq.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_BITQ_H @@ -38,7 +27,7 @@ struct bitq_interface { extern struct bitq_interface *bitq_interface; -int bitq_execute_queue(void); +int bitq_execute_queue(struct jtag_command *cmd_queue); void bitq_cleanup(void); diff --git a/src/jtag/drivers/buspirate.c b/src/jtag/drivers/buspirate.c index 51ace615fe..3b03337c94 100644 --- a/src/jtag/drivers/buspirate.c +++ b/src/jtag/drivers/buspirate.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2010 by Michal Demin * * based on usbprog.c and arm-jtag-ew.c * * Several fixes by R. Diez in 2013. * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -31,7 +20,7 @@ #undef DEBUG_SERIAL /*#define DEBUG_SERIAL */ -static int buspirate_execute_queue(void); +static int buspirate_execute_queue(struct jtag_command *cmd_queue); static int buspirate_init(void); static int buspirate_quit(void); static int buspirate_reset(int trst, int srst); @@ -162,10 +151,10 @@ static int buspirate_serial_read(int fd, uint8_t *buf, int size); static void buspirate_serial_close(int fd); static void buspirate_print_buffer(uint8_t *buf, int size); -static int buspirate_execute_queue(void) +static int buspirate_execute_queue(struct jtag_command *cmd_queue) { /* currently processed command */ - struct jtag_command *cmd = jtag_command_queue; + struct jtag_command *cmd = cmd_queue; int scan_size; enum scan_type type; uint8_t *buffer; diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index eaa65abc6c..341d35cdfa 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2021 by Adrian Negreanu * * groleo@gmail.com * @@ -19,19 +21,6 @@ * * * Copyright (C) 2013 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -171,6 +160,11 @@ static bool swd_mode; #define CMD_DAP_TFER_BLOCK 0x06 #define CMD_DAP_TFER_ABORT 0x07 +/* DAP_TransferBlock increases the sum of command/response sizes + * (due to 16-bit Transfer Count) if used in a small packet. + * Prevent using it until we have at least r/w operations. */ +#define CMD_DAP_TFER_BLOCK_MIN_OPS 4 + /* DAP Status Code */ #define DAP_OK 0 #define DAP_ERROR 0xFF @@ -220,38 +214,27 @@ static const char * const info_caps_str[INFO_CAPS__NUM_CAPS] = { "UART via USB COM port supported", }; -struct pending_transfer_result { - uint8_t cmd; - uint32_t data; - void *buffer; -}; - -struct pending_request_block { - struct pending_transfer_result *transfers; - int transfer_count; -}; - struct pending_scan_result { /** Offset in bytes in the CMD_DAP_JTAG_SEQ response buffer. */ - unsigned first; + unsigned int first; /** Number of bits to read. */ - unsigned length; + unsigned int length; /** Location to store the result */ uint8_t *buffer; /** Offset in the destination buffer */ - unsigned buffer_offset; + unsigned int buffer_offset; }; -/* Up to MIN(packet_count, MAX_PENDING_REQUESTS) requests may be issued - * until the first response arrives */ -#define MAX_PENDING_REQUESTS 3 +/* Read mode */ +enum cmsis_dap_blocking { + CMSIS_DAP_NON_BLOCKING, + CMSIS_DAP_BLOCKING +}; -/* Pending requests are organized as a FIFO - circular buffer */ /* Each block in FIFO can contain up to pending_queue_len transfers */ -static int pending_queue_len; -static struct pending_request_block pending_fifo[MAX_PENDING_REQUESTS]; -static int pending_fifo_put_idx, pending_fifo_get_idx; -static int pending_fifo_block_count; +static unsigned int pending_queue_len; +static unsigned int tfer_max_command_size; +static unsigned int tfer_max_response_size; /* pointers to buffers that will receive jtag scan results on the next flush */ #define MAX_PENDING_SCAN_RESULTS 256 @@ -259,7 +242,7 @@ static int pending_scan_result_count; static struct pending_scan_result pending_scan_results[MAX_PENDING_SCAN_RESULTS]; /* queued JTAG sequences that will be executed on the next flush */ -#define QUEUED_SEQ_BUF_LEN (cmsis_dap_handle->packet_size - 3) +#define QUEUED_SEQ_BUF_LEN (cmsis_dap_handle->packet_usable_size - 3) static int queued_seq_count; static int queued_seq_buf_end; static int queued_seq_tdo_ptr; @@ -320,14 +303,15 @@ static void cmsis_dap_close(struct cmsis_dap *dap) dap->backend = NULL; } - free(cmsis_dap_handle->packet_buffer); - free(cmsis_dap_handle); - cmsis_dap_handle = NULL; + free(dap->packet_buffer); - for (int i = 0; i < MAX_PENDING_REQUESTS; i++) { - free(pending_fifo[i].transfers); - pending_fifo[i].transfers = NULL; + for (unsigned int i = 0; i < MAX_PENDING_REQUESTS; i++) { + free(dap->pending_fifo[i].transfers); + dap->pending_fifo[i].transfers = NULL; } + + free(cmsis_dap_handle); + cmsis_dap_handle = NULL; } static void cmsis_dap_flush_read(struct cmsis_dap *dap) @@ -337,7 +321,7 @@ static void cmsis_dap_flush_read(struct cmsis_dap *dap) * USB close/open so we need to flush up to 64 old packets * to be sure all buffers are empty */ for (i = 0; i < 64; i++) { - int retval = dap->backend->read(dap, 10); + int retval = dap->backend->read(dap, 10, NULL); if (retval == ERROR_TIMEOUT_REACHED) break; } @@ -348,27 +332,30 @@ static void cmsis_dap_flush_read(struct cmsis_dap *dap) /* Send a message and receive the reply */ static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen) { - if (pending_fifo_block_count) { - LOG_ERROR("pending %d blocks, flushing", pending_fifo_block_count); - while (pending_fifo_block_count) { - dap->backend->read(dap, 10); - pending_fifo_block_count--; + if (dap->write_count + dap->read_count) { + LOG_ERROR("internal: queue not empty before xfer"); + } + if (dap->pending_fifo_block_count) { + LOG_ERROR("pending %u blocks, flushing", dap->pending_fifo_block_count); + while (dap->pending_fifo_block_count) { + dap->backend->read(dap, 10, NULL); + dap->pending_fifo_block_count--; } - pending_fifo_put_idx = 0; - pending_fifo_get_idx = 0; + dap->pending_fifo_put_idx = 0; + dap->pending_fifo_get_idx = 0; } - uint8_t current_cmd = cmsis_dap_handle->command[0]; + uint8_t current_cmd = dap->command[0]; int retval = dap->backend->write(dap, txlen, LIBUSB_TIMEOUT_MS); if (retval < 0) return retval; /* get reply */ - retval = dap->backend->read(dap, LIBUSB_TIMEOUT_MS); + retval = dap->backend->read(dap, LIBUSB_TIMEOUT_MS, NULL); if (retval < 0) return retval; - uint8_t *resp = cmsis_dap_handle->response; + uint8_t *resp = dap->response; if (resp[0] == DAP_ERROR) { LOG_ERROR("CMSIS-DAP command 0x%" PRIx8 " not implemented", current_cmd); return ERROR_NOT_IMPLEMENTED; @@ -378,6 +365,7 @@ static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen) LOG_ERROR("CMSIS-DAP command mismatch. Sent 0x%" PRIx8 " received 0x%" PRIx8, current_cmd, resp[0]); + dap->backend->cancel_all(dap); cmsis_dap_flush_read(dap); return ERROR_FAIL; } @@ -432,7 +420,7 @@ static int cmsis_dap_cmd_dap_swj_sequence(uint8_t s_len, const uint8_t *sequence #ifdef CMSIS_DAP_JTAG_DEBUG LOG_DEBUG("cmsis-dap TMS sequence: len=%d", s_len); - for (int i = 0; i < DIV_ROUND_UP(s_len, 8); ++i) + for (unsigned int i = 0; i < DIV_ROUND_UP(s_len, 8); ++i) printf("%02X ", sequence[i]); printf("\n"); @@ -584,6 +572,8 @@ static int cmsis_dap_metacmd_targetsel(uint32_t instance_id) The purpose of this operation is to select the target corresponding to the instance_id that is written */ + LOG_DEBUG_IO("DP write reg TARGETSEL %" PRIx32, instance_id); + size_t idx = 0; command[idx++] = CMD_DAP_SWD_SEQUENCE; command[idx++] = 3; /* sequence count */ @@ -669,7 +659,7 @@ static int cmsis_dap_cmd_dap_swo_baudrate( command[0] = CMD_DAP_SWO_BAUDRATE; h_u32_to_le(&command[1], in_baudrate); - int retval = cmsis_dap_xfer(cmsis_dap_handle, 4); + int retval = cmsis_dap_xfer(cmsis_dap_handle, 5); uint32_t rvbr = le_to_h_u32(&cmsis_dap_handle->response[1]); if (retval != ERROR_OK || rvbr == 0) { LOG_ERROR("CMSIS-DAP: command CMD_SWO_Baudrate(%u) -> %u failed.", in_baudrate, rvbr); @@ -769,32 +759,70 @@ static int cmsis_dap_cmd_dap_swo_data( return ERROR_OK; } +static void cmsis_dap_swd_discard_all_pending(struct cmsis_dap *dap) +{ + for (unsigned int i = 0; i < MAX_PENDING_REQUESTS; i++) + dap->pending_fifo[i].transfer_count = 0; + + dap->pending_fifo_put_idx = 0; + dap->pending_fifo_get_idx = 0; + dap->pending_fifo_block_count = 0; +} + +static void cmsis_dap_swd_cancel_transfers(struct cmsis_dap *dap) +{ + dap->backend->cancel_all(dap); + cmsis_dap_flush_read(dap); + cmsis_dap_swd_discard_all_pending(dap); +} + static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) { - uint8_t *command = cmsis_dap_handle->command; - struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx]; + uint8_t *command = dap->command; + struct pending_request_block *block = &dap->pending_fifo[dap->pending_fifo_put_idx]; + + assert(dap->write_count + dap->read_count == block->transfer_count); + + /* Reset packet size check counters for the next packet */ + dap->write_count = 0; + dap->read_count = 0; - LOG_DEBUG_IO("Executing %d queued transactions from FIFO index %d", block->transfer_count, pending_fifo_put_idx); + LOG_DEBUG_IO("Executing %d queued transactions from FIFO index %u%s", + block->transfer_count, dap->pending_fifo_put_idx, + cmsis_dap_handle->swd_cmds_differ ? "" : ", same swd ops"); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); goto skip; } - if (block->transfer_count == 0) + if (block->transfer_count == 0) { + LOG_ERROR("internal: write an empty queue?!"); goto skip; + } + + bool block_cmd = !cmsis_dap_handle->swd_cmds_differ + && block->transfer_count >= CMD_DAP_TFER_BLOCK_MIN_OPS; + block->command = block_cmd ? CMD_DAP_TFER_BLOCK : CMD_DAP_TFER; - command[0] = CMD_DAP_TFER; + command[0] = block->command; command[1] = 0x00; /* DAP Index */ - command[2] = block->transfer_count; - size_t idx = 3; - for (int i = 0; i < block->transfer_count; i++) { + unsigned int idx; + if (block_cmd) { + h_u16_to_le(&command[2], block->transfer_count); + idx = 4; /* The first transfer will store the common DAP register */ + } else { + command[2] = block->transfer_count; + idx = 3; + } + + for (unsigned int i = 0; i < block->transfer_count; i++) { struct pending_transfer_result *transfer = &(block->transfers[i]); uint8_t cmd = transfer->cmd; uint32_t data = transfer->data; - LOG_DEBUG_IO("%s %s reg %x %"PRIx32, + LOG_DEBUG_IO("%s %s reg %x %" PRIx32, cmd & SWD_CMD_APNDP ? "AP" : "DP", cmd & SWD_CMD_RNW ? "read" : "write", (cmd & SWD_CMD_A32) >> 1, data); @@ -818,7 +846,9 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) data &= ~CORUNDETECT; } - command[idx++] = (cmd >> 1) & 0x0f; + if (!block_cmd || i == 0) + command[idx++] = (cmd >> 1) & 0x0f; + if (!(cmd & SWD_CMD_RNW)) { h_u32_to_le(&command[idx], data); idx += 4; @@ -829,14 +859,13 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) if (retval < 0) { queued_retval = retval; goto skip; - } else { - queued_retval = ERROR_OK; } - pending_fifo_put_idx = (pending_fifo_put_idx + 1) % dap->packet_count; - pending_fifo_block_count++; - if (pending_fifo_block_count > dap->packet_count) - LOG_ERROR("too much pending writes %d", pending_fifo_block_count); + unsigned int packet_count = dap->quirk_mode ? 1 : dap->packet_count; + dap->pending_fifo_put_idx = (dap->pending_fifo_put_idx + 1) % packet_count; + dap->pending_fifo_block_count++; + if (dap->pending_fifo_block_count > packet_count) + LOG_ERROR("internal: too much pending writes %u", dap->pending_fifo_block_count); return; @@ -844,39 +873,74 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) block->transfer_count = 0; } -static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms) +static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, enum cmsis_dap_blocking blocking) { - struct pending_request_block *block = &pending_fifo[pending_fifo_get_idx]; + int retval; + struct pending_request_block *block = &dap->pending_fifo[dap->pending_fifo_get_idx]; - if (pending_fifo_block_count == 0) - LOG_ERROR("no pending write"); + if (dap->pending_fifo_block_count == 0) { + LOG_ERROR("internal: no pending write when reading?!"); + return; + } + + if (queued_retval != ERROR_OK) { + /* keep reading blocks until the pipeline is empty */ + retval = dap->backend->read(dap, 10, NULL); + if (retval == ERROR_TIMEOUT_REACHED || retval == 0) { + /* timeout means that we flushed the pipeline, + * we can safely discard remaining pending requests */ + cmsis_dap_swd_discard_all_pending(dap); + return; + } + goto skip; + } /* get reply */ - int retval = dap->backend->read(dap, timeout_ms); - if (retval == ERROR_TIMEOUT_REACHED && timeout_ms < LIBUSB_TIMEOUT_MS) + struct timeval tv = { + .tv_sec = 0, + .tv_usec = 0 + }; + retval = dap->backend->read(dap, LIBUSB_TIMEOUT_MS, blocking ? NULL : &tv); + bool timeout = (retval == ERROR_TIMEOUT_REACHED || retval == 0); + if (timeout && blocking == CMSIS_DAP_NON_BLOCKING) return; if (retval <= 0) { - LOG_DEBUG("error reading data"); + LOG_DEBUG("error reading adapter response"); queued_retval = ERROR_FAIL; + if (timeout) { + /* timeout means that we flushed the pipeline, + * we can safely discard remaining pending requests */ + cmsis_dap_swd_discard_all_pending(dap); + return; + } goto skip; } uint8_t *resp = dap->response; - if (resp[0] != CMD_DAP_TFER) { + if (resp[0] != block->command) { LOG_ERROR("CMSIS-DAP command mismatch. Expected 0x%x received 0x%" PRIx8, - CMD_DAP_TFER, resp[0]); + block->command, resp[0]); + cmsis_dap_swd_cancel_transfers(dap); queued_retval = ERROR_FAIL; - goto skip; + return; } - uint8_t transfer_count = resp[1]; - uint8_t ack = resp[2] & 0x07; - if (resp[2] & 0x08) { + unsigned int transfer_count; + unsigned int idx; + if (block->command == CMD_DAP_TFER_BLOCK) { + transfer_count = le_to_h_u16(&resp[1]); + idx = 3; + } else { + transfer_count = resp[1]; + idx = 2; + } + if (resp[idx] & 0x08) { LOG_DEBUG("CMSIS-DAP Protocol Error @ %d (wrong parity)", transfer_count); queued_retval = ERROR_FAIL; goto skip; } + uint8_t ack = resp[idx++] & 0x07; if (ack != SWD_ACK_OK) { LOG_DEBUG("SWD ack not OK @ %d %s", transfer_count, ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK"); @@ -885,14 +949,19 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms) goto skip; } - if (block->transfer_count != transfer_count) + if (block->transfer_count != transfer_count) { LOG_ERROR("CMSIS-DAP transfer count mismatch: expected %d, got %d", block->transfer_count, transfer_count); + cmsis_dap_swd_cancel_transfers(dap); + queued_retval = ERROR_FAIL; + return; + } - LOG_DEBUG_IO("Received results of %d queued transactions FIFO index %d", - transfer_count, pending_fifo_get_idx); - size_t idx = 3; - for (int i = 0; i < transfer_count; i++) { + LOG_DEBUG_IO("Received results of %d queued transactions FIFO index %u, %s mode", + transfer_count, dap->pending_fifo_get_idx, + blocking ? "blocking" : "nonblocking"); + + for (unsigned int i = 0; i < transfer_count; i++) { struct pending_transfer_result *transfer = &(block->transfers[i]); if (transfer->cmd & SWD_CMD_RNW) { static uint32_t last_read; @@ -900,7 +969,7 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms) uint32_t tmp = data; idx += 4; - LOG_DEBUG_IO("Read result: %"PRIx32, data); + LOG_DEBUG_IO("Read result: %" PRIx32, data); /* Imitate posted AP reads */ if ((transfer->cmd & SWD_CMD_APNDP) || @@ -916,22 +985,25 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms) skip: block->transfer_count = 0; - pending_fifo_get_idx = (pending_fifo_get_idx + 1) % dap->packet_count; - pending_fifo_block_count--; + if (!dap->quirk_mode && dap->packet_count > 1) + dap->pending_fifo_get_idx = (dap->pending_fifo_get_idx + 1) % dap->packet_count; + dap->pending_fifo_block_count--; } static int cmsis_dap_swd_run_queue(void) { - if (pending_fifo_block_count) - cmsis_dap_swd_read_process(cmsis_dap_handle, 0); + if (cmsis_dap_handle->write_count + cmsis_dap_handle->read_count) { + if (cmsis_dap_handle->pending_fifo_block_count) + cmsis_dap_swd_read_process(cmsis_dap_handle, CMSIS_DAP_NON_BLOCKING); - cmsis_dap_swd_write_from_queue(cmsis_dap_handle); + cmsis_dap_swd_write_from_queue(cmsis_dap_handle); + } - while (pending_fifo_block_count) - cmsis_dap_swd_read_process(cmsis_dap_handle, LIBUSB_TIMEOUT_MS); + while (cmsis_dap_handle->pending_fifo_block_count) + cmsis_dap_swd_read_process(cmsis_dap_handle, CMSIS_DAP_BLOCKING); - pending_fifo_put_idx = 0; - pending_fifo_get_idx = 0; + cmsis_dap_handle->pending_fifo_put_idx = 0; + cmsis_dap_handle->pending_fifo_get_idx = 0; int retval = queued_retval; queued_retval = ERROR_OK; @@ -939,37 +1011,103 @@ static int cmsis_dap_swd_run_queue(void) return retval; } +static unsigned int cmsis_dap_tfer_cmd_size(unsigned int write_count, + unsigned int read_count, bool block_tfer) +{ + unsigned int size; + if (block_tfer) { + size = 5; /* DAP_TransferBlock header */ + size += write_count * 4; /* data */ + } else { + size = 3; /* DAP_Transfer header */ + size += write_count * (1 + 4); /* DAP register + data */ + size += read_count; /* DAP register */ + } + return size; +} + +static unsigned int cmsis_dap_tfer_resp_size(unsigned int write_count, + unsigned int read_count, bool block_tfer) +{ + unsigned int size; + if (block_tfer) + size = 4; /* DAP_TransferBlock response header */ + else + size = 3; /* DAP_Transfer response header */ + + size += read_count * 4; /* data */ + return size; +} + static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data) { - bool targetsel_cmd = swd_cmd(false, false, DP_TARGETSEL) == cmd; + /* TARGETSEL register write cannot be queued */ + if (swd_cmd(false, false, DP_TARGETSEL) == cmd) { + queued_retval = cmsis_dap_swd_run_queue(); + + cmsis_dap_metacmd_targetsel(data); + return; + } + + /* Compute sizes of the DAP Transfer command and the expected response + * for all queued and this operation */ + unsigned int write_count = cmsis_dap_handle->write_count; + unsigned int read_count = cmsis_dap_handle->read_count; + bool block_cmd; + if (write_count + read_count < CMD_DAP_TFER_BLOCK_MIN_OPS) + block_cmd = false; + else + block_cmd = !cmsis_dap_handle->swd_cmds_differ + && cmd == cmsis_dap_handle->common_swd_cmd; + + if (cmd & SWD_CMD_RNW) + read_count++; + else + write_count++; + + unsigned int cmd_size = cmsis_dap_tfer_cmd_size(write_count, read_count, + block_cmd); + unsigned int resp_size = cmsis_dap_tfer_resp_size(write_count, read_count, + block_cmd); + unsigned int max_transfer_count = block_cmd ? 65535 : 255; - if (pending_fifo[pending_fifo_put_idx].transfer_count == pending_queue_len - || targetsel_cmd) { - if (pending_fifo_block_count) - cmsis_dap_swd_read_process(cmsis_dap_handle, 0); + /* Does the DAP Transfer command and also its expected response fit into one packet? */ + if (cmd_size > tfer_max_command_size + || resp_size > tfer_max_response_size + || write_count + read_count > max_transfer_count) { + if (cmsis_dap_handle->pending_fifo_block_count) + cmsis_dap_swd_read_process(cmsis_dap_handle, CMSIS_DAP_NON_BLOCKING); /* Not enough room in the queue. Run the queue. */ cmsis_dap_swd_write_from_queue(cmsis_dap_handle); - if (pending_fifo_block_count >= cmsis_dap_handle->packet_count) - cmsis_dap_swd_read_process(cmsis_dap_handle, LIBUSB_TIMEOUT_MS); + unsigned int packet_count = cmsis_dap_handle->quirk_mode ? 1 : cmsis_dap_handle->packet_count; + if (cmsis_dap_handle->pending_fifo_block_count >= packet_count) + cmsis_dap_swd_read_process(cmsis_dap_handle, CMSIS_DAP_BLOCKING); } - if (queued_retval != ERROR_OK) - return; + assert(cmsis_dap_handle->pending_fifo[cmsis_dap_handle->pending_fifo_put_idx].transfer_count < pending_queue_len); - if (targetsel_cmd) { - cmsis_dap_metacmd_targetsel(data); + if (queued_retval != ERROR_OK) return; - } - struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx]; + struct pending_request_block *block = &cmsis_dap_handle->pending_fifo[cmsis_dap_handle->pending_fifo_put_idx]; struct pending_transfer_result *transfer = &(block->transfers[block->transfer_count]); transfer->data = data; transfer->cmd = cmd; + if (block->transfer_count == 0) { + cmsis_dap_handle->swd_cmds_differ = false; + cmsis_dap_handle->common_swd_cmd = cmd; + } else if (cmd != cmsis_dap_handle->common_swd_cmd) { + cmsis_dap_handle->swd_cmds_differ = true; + } + if (cmd & SWD_CMD_RNW) { /* Queue a read transaction */ transfer->buffer = dst; + cmsis_dap_handle->read_count++; + } else { + cmsis_dap_handle->write_count++; } block->transfer_count++; } @@ -1031,7 +1169,7 @@ static int cmsis_dap_get_caps_info(void) cmsis_dap_handle->caps = caps; - for (int i = 0; i < INFO_CAPS__NUM_CAPS; ++i) { + for (unsigned int i = 0; i < INFO_CAPS__NUM_CAPS; ++i) { if (caps & BIT(i)) LOG_INFO("CMSIS-DAP: %s", info_caps_str[i]); } @@ -1084,7 +1222,12 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq) unsigned int s_len; int retval; - if ((output_pins & (SWJ_PIN_SRST | SWJ_PIN_TRST)) == (SWJ_PIN_SRST | SWJ_PIN_TRST)) { + if (swd_mode) + queued_retval = cmsis_dap_swd_run_queue(); + + if (cmsis_dap_handle->quirk_mode && seq != LINE_RESET && + (output_pins & (SWJ_PIN_SRST | SWJ_PIN_TRST)) + == (SWJ_PIN_SRST | SWJ_PIN_TRST)) { /* Following workaround deasserts reset on most adapters. * Do not reconnect if a reset line is active! * Reconnecting would break connecting under reset. */ @@ -1209,7 +1352,6 @@ static int cmsis_dap_init(void) /* Be conservative and suppress submitting multiple HID requests * until we get packet count info from the adaptor */ cmsis_dap_handle->packet_count = 1; - pending_queue_len = 12; /* INFO_ID_PKT_SZ - short */ retval = cmsis_dap_cmd_dap_info(INFO_ID_PKT_SZ, &data); @@ -1219,13 +1361,7 @@ static int cmsis_dap_init(void) if (data[0] == 2) { /* short */ uint16_t pkt_sz = data[1] + (data[2] << 8); if (pkt_sz != cmsis_dap_handle->packet_size) { - - /* 4 bytes of command header + 5 bytes per register - * write. For bulk read sequences just 4 bytes are - * needed per transfer, so this is suboptimal. */ - pending_queue_len = (pkt_sz - 4) / 5; - - free(cmsis_dap_handle->packet_buffer); + cmsis_dap_handle->backend->packet_buffer_free(cmsis_dap_handle); retval = cmsis_dap_handle->backend->packet_buffer_alloc(cmsis_dap_handle, pkt_sz); if (retval != ERROR_OK) goto init_err; @@ -1234,23 +1370,34 @@ static int cmsis_dap_init(void) } } + /* Maximal number of transfers which fit to one packet: + * Limited by response size: 3 bytes of response header + 4 per read + * Plus writes to full command size: 3 bytes cmd header + 1 per read + 5 per write */ + tfer_max_command_size = cmsis_dap_handle->packet_usable_size; + tfer_max_response_size = cmsis_dap_handle->packet_usable_size; + unsigned int max_reads = tfer_max_response_size / 4; + pending_queue_len = max_reads + (tfer_max_command_size - max_reads) / 5; + cmsis_dap_handle->write_count = 0; + cmsis_dap_handle->read_count = 0; + /* INFO_ID_PKT_CNT - byte */ retval = cmsis_dap_cmd_dap_info(INFO_ID_PKT_CNT, &data); if (retval != ERROR_OK) goto init_err; if (data[0] == 1) { /* byte */ - int pkt_cnt = data[1]; + unsigned int pkt_cnt = data[1]; if (pkt_cnt > 1) cmsis_dap_handle->packet_count = MIN(MAX_PENDING_REQUESTS, pkt_cnt); - LOG_DEBUG("CMSIS-DAP: Packet Count = %d", pkt_cnt); + LOG_DEBUG("CMSIS-DAP: Packet Count = %u", pkt_cnt); } - LOG_DEBUG("Allocating FIFO for %d pending packets", cmsis_dap_handle->packet_count); - for (int i = 0; i < cmsis_dap_handle->packet_count; i++) { - pending_fifo[i].transfers = malloc(pending_queue_len * sizeof(struct pending_transfer_result)); - if (!pending_fifo[i].transfers) { + LOG_DEBUG("Allocating FIFO for %u pending packets", cmsis_dap_handle->packet_count); + for (unsigned int i = 0; i < cmsis_dap_handle->packet_count; i++) { + cmsis_dap_handle->pending_fifo[i].transfers = malloc(pending_queue_len + * sizeof(struct pending_transfer_result)); + if (!cmsis_dap_handle->pending_fifo[i].transfers) { LOG_ERROR("Unable to allocate memory for CMSIS-DAP queue"); retval = ERROR_FAIL; goto init_err; @@ -1376,7 +1523,7 @@ static void cmsis_dap_end_state(tap_state_t state) } #ifdef SPRINT_BINARY -static void sprint_binary(char *s, const uint8_t *buf, int offset, int len) +static void sprint_binary(char *s, const uint8_t *buf, unsigned int offset, unsigned int len) { if (!len) return; @@ -1387,7 +1534,7 @@ static void sprint_binary(char *s, const uint8_t *buf, int offset, int len) buf = { 0xc0 0x18 } offset=3 len=10 should result in: 11000 11000 i=3 there means i/8 = 0 so c = 0xFF, and */ - for (int i = offset; i < offset + len; ++i) { + for (unsigned int i = offset; i < offset + len; ++i) { uint8_t c = buf[i / 8], mask = 1 << (i % 8); if ((i != offset) && !(i % 8)) putchar(' '); @@ -1501,10 +1648,11 @@ static void cmsis_dap_flush(void) * sequence=NULL means clock out zeros on TDI * tdo_buffer=NULL means don't capture TDO */ -static void cmsis_dap_add_jtag_sequence(int s_len, const uint8_t *sequence, int s_offset, - bool tms, uint8_t *tdo_buffer, int tdo_buffer_offset) +static void cmsis_dap_add_jtag_sequence(unsigned int s_len, const uint8_t *sequence, + unsigned int s_offset, bool tms, + uint8_t *tdo_buffer, unsigned int tdo_buffer_offset) { - LOG_DEBUG_IO("[at %d] %d bits, tms %s, seq offset %d, tdo buf %p, tdo offset %d", + LOG_DEBUG_IO("[at %d] %u bits, tms %s, seq offset %u, tdo buf %p, tdo offset %u", queued_seq_buf_end, s_len, tms ? "HIGH" : "LOW", s_offset, tdo_buffer, tdo_buffer_offset); @@ -1513,11 +1661,11 @@ static void cmsis_dap_add_jtag_sequence(int s_len, const uint8_t *sequence, int if (s_len > 64) { LOG_DEBUG_IO("START JTAG SEQ SPLIT"); - for (int offset = 0; offset < s_len; offset += 64) { - int len = s_len - offset; + for (unsigned int offset = 0; offset < s_len; offset += 64) { + unsigned int len = s_len - offset; if (len > 64) len = 64; - LOG_DEBUG_IO("Splitting long jtag sequence: %d-bit chunk starting at offset %d", len, offset); + LOG_DEBUG_IO("Splitting long jtag sequence: %u-bit chunk starting at offset %u", len, offset); cmsis_dap_add_jtag_sequence( len, sequence, @@ -1531,7 +1679,7 @@ static void cmsis_dap_add_jtag_sequence(int s_len, const uint8_t *sequence, int return; } - int cmd_len = 1 + DIV_ROUND_UP(s_len, 8); + unsigned int cmd_len = 1 + DIV_ROUND_UP(s_len, 8); if (queued_seq_count >= 255 || queued_seq_buf_end + cmd_len > QUEUED_SEQ_BUF_LEN) /* empty out the buffer */ cmsis_dap_flush(); @@ -1806,9 +1954,9 @@ static void cmsis_dap_execute_command(struct jtag_command *cmd) } } -static int cmsis_dap_execute_queue(void) +static int cmsis_dap_execute_queue(struct jtag_command *cmd_queue) { - struct jtag_command *cmd = jtag_command_queue; + struct jtag_command *cmd = cmd_queue; while (cmd) { cmsis_dap_execute_command(cmd); @@ -2025,12 +2173,12 @@ COMMAND_HANDLER(cmsis_dap_handle_cmd_command) COMMAND_HANDLER(cmsis_dap_handle_vid_pid_command) { if (CMD_ARGC > MAX_USB_IDS * 2) { - LOG_WARNING("ignoring extra IDs in cmsis_dap_vid_pid " + LOG_WARNING("ignoring extra IDs in cmsis-dap vid_pid " "(maximum is %d pairs)", MAX_USB_IDS); CMD_ARGC = MAX_USB_IDS * 2; } if (CMD_ARGC < 2 || (CMD_ARGC & 1)) { - LOG_WARNING("incomplete cmsis_dap_vid_pid configuration directive"); + LOG_WARNING("incomplete cmsis-dap vid_pid configuration directive"); if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; /* remove the incomplete trailing id */ @@ -2065,15 +2213,29 @@ COMMAND_HANDLER(cmsis_dap_handle_backend_command) } } - LOG_ERROR("invalid backend argument to cmsis_dap_backend <backend>"); + command_print(CMD, "invalid backend argument to cmsis-dap backend <backend>"); + return ERROR_COMMAND_ARGUMENT_INVALID; } } else { - LOG_ERROR("expected exactly one argument to cmsis_dap_backend <backend>"); + return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } +COMMAND_HANDLER(cmsis_dap_handle_quirk_command) +{ + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (CMD_ARGC == 1) + COMMAND_PARSE_ENABLE(CMD_ARGV[0], cmsis_dap_handle->quirk_mode); + + command_print(CMD, "CMSIS-DAP quirk workarounds %s", + cmsis_dap_handle->quirk_mode ? "enabled" : "disabled"); + return ERROR_OK; +} + static const struct command_registration cmsis_dap_subcommand_handlers[] = { { .name = "info", @@ -2089,35 +2251,30 @@ static const struct command_registration cmsis_dap_subcommand_handlers[] = { .usage = "", .help = "issue cmsis-dap command", }, - COMMAND_REGISTRATION_DONE -}; - - -static const struct command_registration cmsis_dap_command_handlers[] = { - { - .name = "cmsis-dap", - .mode = COMMAND_ANY, - .help = "perform CMSIS-DAP management", - .usage = "<cmd>", - .chain = cmsis_dap_subcommand_handlers, - }, { - .name = "cmsis_dap_vid_pid", + .name = "vid_pid", .handler = &cmsis_dap_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "the vendor ID and product ID of the CMSIS-DAP device", .usage = "(vid pid)*", }, { - .name = "cmsis_dap_backend", + .name = "backend", .handler = &cmsis_dap_handle_backend_command, .mode = COMMAND_CONFIG, .help = "set the communication backend to use (USB bulk or HID).", .usage = "(auto | usb_bulk | hid)", }, + { + .name = "quirk", + .handler = &cmsis_dap_handle_quirk_command, + .mode = COMMAND_ANY, + .help = "allow expensive workarounds of known adapter quirks.", + .usage = "[enable | disable]", + }, #if BUILD_CMSIS_DAP_USB { - .name = "cmsis_dap_usb", + .name = "usb", .chain = cmsis_dap_usb_subcommand_handlers, .mode = COMMAND_ANY, .help = "USB bulk backend-specific commands", @@ -2127,6 +2284,18 @@ static const struct command_registration cmsis_dap_command_handlers[] = { COMMAND_REGISTRATION_DONE }; + +static const struct command_registration cmsis_dap_command_handlers[] = { + { + .name = "cmsis-dap", + .mode = COMMAND_ANY, + .help = "perform CMSIS-DAP management", + .usage = "<cmd>", + .chain = cmsis_dap_subcommand_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + static const struct swd_driver cmsis_dap_swd_driver = { .init = cmsis_dap_swd_init, .switch_seq = cmsis_dap_swd_switch_seq, diff --git a/src/jtag/drivers/cmsis_dap.h b/src/jtag/drivers/cmsis_dap.h index 7c64d492c8..e47697d1f9 100644 --- a/src/jtag/drivers/cmsis_dap.h +++ b/src/jtag/drivers/cmsis_dap.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + #ifndef OPENOCD_JTAG_DRIVERS_CMSIS_DAP_H #define OPENOCD_JTAG_DRIVERS_CMSIS_DAP_H @@ -5,19 +7,53 @@ struct cmsis_dap_backend; struct cmsis_dap_backend_data; -struct command_registration; + +struct pending_transfer_result { + uint8_t cmd; + uint32_t data; + void *buffer; +}; + +/* Up to MIN(packet_count, MAX_PENDING_REQUESTS) requests may be issued + * until the first response arrives */ +#define MAX_PENDING_REQUESTS 4 + +struct pending_request_block { + struct pending_transfer_result *transfers; + unsigned int transfer_count; + uint8_t command; +}; struct cmsis_dap { struct cmsis_dap_backend_data *bdata; const struct cmsis_dap_backend *backend; - uint16_t packet_size; - int packet_count; + unsigned int packet_size; + unsigned int packet_usable_size; + unsigned int packet_buffer_size; uint8_t *packet_buffer; - uint16_t packet_buffer_size; uint8_t *command; uint8_t *response; + + /* DP/AP register r/w operation counters used for checking the packet size + * that would result from the queue run */ + unsigned int write_count; + unsigned int read_count; + + /* We can use DAP_TransferBlock only if all SWD operations in the packet + * are either all writes or all reads and use the same DP/AP register. + * The following variables keep track of it */ + uint8_t common_swd_cmd; + bool swd_cmds_differ; + + /* Pending requests are organized as a FIFO - circular buffer */ + struct pending_request_block pending_fifo[MAX_PENDING_REQUESTS]; + unsigned int packet_count; + unsigned int pending_fifo_put_idx, pending_fifo_get_idx; + unsigned int pending_fifo_block_count; + uint16_t caps; - uint8_t mode; + bool quirk_mode; /* enable expensive workarounds */ + uint32_t swo_buf_sz; bool trace_enabled; }; @@ -26,9 +62,12 @@ struct cmsis_dap_backend { const char *name; int (*open)(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], const char *serial); void (*close)(struct cmsis_dap *dap); - int (*read)(struct cmsis_dap *dap, int timeout_ms); + int (*read)(struct cmsis_dap *dap, int transfer_timeout_ms, + struct timeval *wait_timeout); int (*write)(struct cmsis_dap *dap, int len, int timeout_ms); int (*packet_buffer_alloc)(struct cmsis_dap *dap, unsigned int pkt_sz); + void (*packet_buffer_free)(struct cmsis_dap *dap); + void (*cancel_all)(struct cmsis_dap *dap); }; extern const struct cmsis_dap_backend cmsis_dap_hid_backend; diff --git a/src/jtag/drivers/cmsis_dap_usb_bulk.c b/src/jtag/drivers/cmsis_dap_usb_bulk.c index 819596b215..8d0cb544d7 100644 --- a/src/jtag/drivers/cmsis_dap_usb_bulk.c +++ b/src/jtag/drivers/cmsis_dap_usb_bulk.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2018 by Mickaël Thomas * * mickael9@gmail.com * @@ -16,19 +18,6 @@ * * * Copyright (C) 2013 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -39,8 +28,23 @@ #include <libusb.h> #include <helper/log.h> #include <helper/replacements.h> +#include <jtag/jtag.h> /* ERROR_JTAG_DEVICE_ERROR only */ #include "cmsis_dap.h" +#include "libusb_helper.h" + +enum { + CMSIS_DAP_TRANSFER_PENDING = 0, /* must be 0, used in libusb_handle_events_completed */ + CMSIS_DAP_TRANSFER_IDLE, + CMSIS_DAP_TRANSFER_COMPLETED +}; + +struct cmsis_dap_bulk_transfer { + struct libusb_transfer *transfer; + uint8_t *buffer; + int status; /* either CMSIS_DAP_TRANSFER_ enum or error code */ + int transferred; +}; struct cmsis_dap_backend_data { struct libusb_context *usb_ctx; @@ -48,12 +52,16 @@ struct cmsis_dap_backend_data { unsigned int ep_out; unsigned int ep_in; int interface; + + struct cmsis_dap_bulk_transfer command_transfers[MAX_PENDING_REQUESTS]; + struct cmsis_dap_bulk_transfer response_transfers[MAX_PENDING_REQUESTS]; }; static int cmsis_dap_usb_interface = -1; static void cmsis_dap_usb_close(struct cmsis_dap *dap); static int cmsis_dap_usb_alloc(struct cmsis_dap *dap, unsigned int pkt_sz); +static void cmsis_dap_usb_free(struct cmsis_dap *dap); static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], const char *serial) { @@ -273,8 +281,10 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p /* If the interface is reliably identified * then we need not insist on setting USB class, subclass and protocol * exactly as the specification requires. + * Just filter out the well known classes, mainly CDC and MSC. * At least KitProg3 uses class 0 contrary to the specification */ - if (intf_identified_reliably) { + if (intf_identified_reliably && + (intf_desc->bInterfaceClass == 0 || intf_desc->bInterfaceClass > 0x12)) { LOG_WARNING("Using CMSIS-DAPv2 interface %d with wrong class %" PRId8 " subclass %" PRId8 " or protocol %" PRId8, interface_num, @@ -352,7 +362,7 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p if (err) LOG_WARNING("could not claim interface: %s", libusb_strerror(err)); - dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data)); + dap->bdata = calloc(1, sizeof(struct cmsis_dap_backend_data)); if (!dap->bdata) { LOG_ERROR("unable to allocate memory"); libusb_release_interface(dev_handle, interface_num); @@ -361,25 +371,35 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p return ERROR_FAIL; } - dap->packet_size = packet_size; - dap->packet_buffer_size = packet_size; dap->bdata->usb_ctx = ctx; dap->bdata->dev_handle = dev_handle; dap->bdata->ep_out = ep_out; dap->bdata->ep_in = ep_in; dap->bdata->interface = interface_num; - dap->packet_buffer = malloc(dap->packet_buffer_size); - if (!dap->packet_buffer) { - LOG_ERROR("unable to allocate memory"); - cmsis_dap_usb_close(dap); - return ERROR_FAIL; + for (unsigned int idx = 0; idx < MAX_PENDING_REQUESTS; idx++) { + dap->bdata->command_transfers[idx].status = CMSIS_DAP_TRANSFER_IDLE; + dap->bdata->command_transfers[idx].transfer = libusb_alloc_transfer(0); + if (!dap->bdata->command_transfers[idx].transfer) { + LOG_ERROR("unable to allocate USB transfer"); + cmsis_dap_usb_close(dap); + return ERROR_FAIL; + } + + dap->bdata->response_transfers[idx].status = CMSIS_DAP_TRANSFER_IDLE; + dap->bdata->response_transfers[idx].transfer = libusb_alloc_transfer(0); + if (!dap->bdata->response_transfers[idx].transfer) { + LOG_ERROR("unable to allocate USB transfer"); + cmsis_dap_usb_close(dap); + return ERROR_FAIL; + } } - dap->command = dap->packet_buffer; - dap->response = dap->packet_buffer; + err = cmsis_dap_usb_alloc(dap, packet_size); + if (err != ERROR_OK) + cmsis_dap_usb_close(dap); - return ERROR_OK; + return err; } libusb_close(dev_handle); @@ -393,74 +413,235 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p static void cmsis_dap_usb_close(struct cmsis_dap *dap) { + for (unsigned int i = 0; i < MAX_PENDING_REQUESTS; i++) { + libusb_free_transfer(dap->bdata->command_transfers[i].transfer); + libusb_free_transfer(dap->bdata->response_transfers[i].transfer); + } + cmsis_dap_usb_free(dap); libusb_release_interface(dap->bdata->dev_handle, dap->bdata->interface); libusb_close(dap->bdata->dev_handle); libusb_exit(dap->bdata->usb_ctx); free(dap->bdata); dap->bdata = NULL; - free(dap->packet_buffer); - dap->packet_buffer = NULL; } -static int cmsis_dap_usb_read(struct cmsis_dap *dap, int timeout_ms) +static void LIBUSB_CALL cmsis_dap_usb_callback(struct libusb_transfer *transfer) +{ + struct cmsis_dap_bulk_transfer *tr; + + tr = (struct cmsis_dap_bulk_transfer *)transfer->user_data; + if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { + tr->status = CMSIS_DAP_TRANSFER_COMPLETED; + tr->transferred = transfer->actual_length; + } else if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) { + tr->status = ERROR_TIMEOUT_REACHED; + } else { + tr->status = ERROR_JTAG_DEVICE_ERROR; + } +} + +static int cmsis_dap_usb_read(struct cmsis_dap *dap, int transfer_timeout_ms, + struct timeval *wait_timeout) { int transferred = 0; int err; + struct cmsis_dap_bulk_transfer *tr; + tr = &dap->bdata->response_transfers[dap->pending_fifo_get_idx]; + + if (tr->status == CMSIS_DAP_TRANSFER_IDLE) { + libusb_fill_bulk_transfer(tr->transfer, + dap->bdata->dev_handle, dap->bdata->ep_in, + tr->buffer, dap->packet_size, + &cmsis_dap_usb_callback, tr, + transfer_timeout_ms); + LOG_DEBUG_IO("submit read @ %u", dap->pending_fifo_get_idx); + tr->status = CMSIS_DAP_TRANSFER_PENDING; + err = libusb_submit_transfer(tr->transfer); + if (err) { + tr->status = CMSIS_DAP_TRANSFER_IDLE; + LOG_ERROR("error submitting USB read: %s", libusb_strerror(err)); + return ERROR_FAIL; + } + } - err = libusb_bulk_transfer(dap->bdata->dev_handle, dap->bdata->ep_in, - dap->packet_buffer, dap->packet_size, &transferred, timeout_ms); - if (err) { - if (err == LIBUSB_ERROR_TIMEOUT) { - return ERROR_TIMEOUT_REACHED; - } else { - LOG_ERROR("error reading data: %s", libusb_strerror(err)); + struct timeval tv = { + .tv_sec = transfer_timeout_ms / 1000, + .tv_usec = transfer_timeout_ms % 1000 * 1000 + }; + + while (tr->status == CMSIS_DAP_TRANSFER_PENDING) { + err = libusb_handle_events_timeout_completed(dap->bdata->usb_ctx, + wait_timeout ? wait_timeout : &tv, + &tr->status); + if (err) { + LOG_ERROR("error handling USB events: %s", libusb_strerror(err)); return ERROR_FAIL; } + if (wait_timeout) + break; + } + + if (tr->status < 0 || tr->status == CMSIS_DAP_TRANSFER_COMPLETED) { + /* Check related command request for an error */ + struct cmsis_dap_bulk_transfer *tr_cmd; + tr_cmd = &dap->bdata->command_transfers[dap->pending_fifo_get_idx]; + if (tr_cmd->status < 0) { + err = tr_cmd->status; + tr_cmd->status = CMSIS_DAP_TRANSFER_IDLE; + if (err != ERROR_TIMEOUT_REACHED) + LOG_ERROR("error writing USB data"); + else + LOG_DEBUG("command write USB timeout @ %u", dap->pending_fifo_get_idx); + + return err; + } + if (tr_cmd->status == CMSIS_DAP_TRANSFER_COMPLETED) + tr_cmd->status = CMSIS_DAP_TRANSFER_IDLE; } - memset(&dap->packet_buffer[transferred], 0, dap->packet_buffer_size - transferred); + if (tr->status < 0) { + err = tr->status; + tr->status = CMSIS_DAP_TRANSFER_IDLE; + if (err != ERROR_TIMEOUT_REACHED) + LOG_ERROR("error reading USB data"); + else + LOG_DEBUG("USB timeout @ %u", dap->pending_fifo_get_idx); + + return err; + } + + if (tr->status == CMSIS_DAP_TRANSFER_COMPLETED) { + transferred = tr->transferred; + LOG_DEBUG_IO("completed read @ %u, transferred %i", + dap->pending_fifo_get_idx, transferred); + memcpy(dap->packet_buffer, tr->buffer, transferred); + memset(&dap->packet_buffer[transferred], 0, dap->packet_buffer_size - transferred); + tr->status = CMSIS_DAP_TRANSFER_IDLE; + } return transferred; } static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen, int timeout_ms) { - int transferred = 0; int err; + struct cmsis_dap_bulk_transfer *tr; + tr = &dap->bdata->command_transfers[dap->pending_fifo_put_idx]; + + if (tr->status == CMSIS_DAP_TRANSFER_PENDING) { + LOG_ERROR("busy command USB transfer at %u", dap->pending_fifo_put_idx); + struct timeval tv = { + .tv_sec = timeout_ms / 1000, + .tv_usec = timeout_ms % 1000 * 1000 + }; + libusb_handle_events_timeout_completed(dap->bdata->usb_ctx, &tv, &tr->status); + } + if (tr->status < 0) { + if (tr->status != ERROR_TIMEOUT_REACHED) + LOG_ERROR("error writing USB data, late detect"); + else + LOG_DEBUG("USB write timeout @ %u, late detect", dap->pending_fifo_get_idx); + tr->status = CMSIS_DAP_TRANSFER_IDLE; + } + if (tr->status == CMSIS_DAP_TRANSFER_COMPLETED) { + LOG_ERROR("USB write: late transfer competed"); + tr->status = CMSIS_DAP_TRANSFER_IDLE; + } + if (tr->status != CMSIS_DAP_TRANSFER_IDLE) { + libusb_cancel_transfer(tr->transfer); + /* TODO: switch to less verbose errors and wait for USB working again */ + return ERROR_JTAG_DEVICE_ERROR; + } + + memcpy(tr->buffer, dap->packet_buffer, txlen); - /* skip the first byte that is only used by the HID backend */ - err = libusb_bulk_transfer(dap->bdata->dev_handle, dap->bdata->ep_out, - dap->packet_buffer, txlen, &transferred, timeout_ms); + libusb_fill_bulk_transfer(tr->transfer, + dap->bdata->dev_handle, dap->bdata->ep_out, + tr->buffer, txlen, + &cmsis_dap_usb_callback, tr, + timeout_ms); + + LOG_DEBUG_IO("submit write @ %u", dap->pending_fifo_put_idx); + tr->status = CMSIS_DAP_TRANSFER_PENDING; + err = libusb_submit_transfer(tr->transfer); if (err) { - if (err == LIBUSB_ERROR_TIMEOUT) { - return ERROR_TIMEOUT_REACHED; - } else { - LOG_ERROR("error writing data: %s", libusb_strerror(err)); - return ERROR_FAIL; - } + if (err == LIBUSB_ERROR_BUSY) + libusb_cancel_transfer(tr->transfer); + else + tr->status = CMSIS_DAP_TRANSFER_IDLE; + + LOG_ERROR("error submitting USB write: %s", libusb_strerror(err)); + return ERROR_FAIL; } - return transferred; + return ERROR_OK; } static int cmsis_dap_usb_alloc(struct cmsis_dap *dap, unsigned int pkt_sz) { - uint8_t *buf = malloc(pkt_sz); - if (!buf) { + dap->packet_buffer = malloc(pkt_sz); + if (!dap->packet_buffer) { LOG_ERROR("unable to allocate CMSIS-DAP packet buffer"); return ERROR_FAIL; } - dap->packet_buffer = buf; dap->packet_size = pkt_sz; dap->packet_buffer_size = pkt_sz; + /* Prevent sending zero size USB packets */ + dap->packet_usable_size = pkt_sz - 1; dap->command = dap->packet_buffer; dap->response = dap->packet_buffer; + struct cmsis_dap_backend_data *bdata = dap->bdata; + for (unsigned int i = 0; i < MAX_PENDING_REQUESTS; i++) { + bdata->command_transfers[i].buffer = + oocd_libusb_dev_mem_alloc(bdata->dev_handle, pkt_sz); + + bdata->response_transfers[i].buffer = + oocd_libusb_dev_mem_alloc(bdata->dev_handle, pkt_sz); + + if (!bdata->command_transfers[i].buffer + || !bdata->response_transfers[i].buffer) { + LOG_ERROR("unable to allocate CMSIS-DAP pending packet buffer"); + return ERROR_FAIL; + } + } return ERROR_OK; } +static void cmsis_dap_usb_free(struct cmsis_dap *dap) +{ + struct cmsis_dap_backend_data *bdata = dap->bdata; + + for (unsigned int i = 0; i < MAX_PENDING_REQUESTS; i++) { + oocd_libusb_dev_mem_free(bdata->dev_handle, + bdata->command_transfers[i].buffer, dap->packet_size); + oocd_libusb_dev_mem_free(bdata->dev_handle, + bdata->response_transfers[i].buffer, dap->packet_size); + bdata->command_transfers[i].buffer = NULL; + bdata->response_transfers[i].buffer = NULL; + } + + free(dap->packet_buffer); + dap->packet_buffer = NULL; + dap->command = NULL; + dap->response = NULL; +} + +static void cmsis_dap_usb_cancel_all(struct cmsis_dap *dap) +{ + for (unsigned int i = 0; i < MAX_PENDING_REQUESTS; i++) { + if (dap->bdata->command_transfers[i].status == CMSIS_DAP_TRANSFER_PENDING) + libusb_cancel_transfer(dap->bdata->command_transfers[i].transfer); + if (dap->bdata->response_transfers[i].status == CMSIS_DAP_TRANSFER_PENDING) + libusb_cancel_transfer(dap->bdata->response_transfers[i].transfer); + + dap->bdata->command_transfers[i].status = CMSIS_DAP_TRANSFER_IDLE; + dap->bdata->response_transfers[i].status = CMSIS_DAP_TRANSFER_IDLE; + } +} + COMMAND_HANDLER(cmsis_dap_handle_usb_interface_command) { if (CMD_ARGC == 1) @@ -489,4 +670,6 @@ const struct cmsis_dap_backend cmsis_dap_usb_backend = { .read = cmsis_dap_usb_read, .write = cmsis_dap_usb_write, .packet_buffer_alloc = cmsis_dap_usb_alloc, + .packet_buffer_free = cmsis_dap_usb_free, + .cancel_all = cmsis_dap_usb_cancel_all, }; diff --git a/src/jtag/drivers/cmsis_dap_usb_hid.c b/src/jtag/drivers/cmsis_dap_usb_hid.c index 912ba3972f..98ccc3e381 100644 --- a/src/jtag/drivers/cmsis_dap_usb_hid.c +++ b/src/jtag/drivers/cmsis_dap_usb_hid.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2018 by Mickaël Thomas * * mickael9@gmail.com * @@ -16,19 +18,6 @@ * * * Copyright (C) 2013 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -45,8 +34,39 @@ struct cmsis_dap_backend_data { hid_device *dev_handle; }; +struct cmsis_dap_report_size { + unsigned short vid; + unsigned short pid; + unsigned int report_size; +}; + +static const struct cmsis_dap_report_size report_size_quirks[] = { + /* Third gen Atmel tools use a report size of 512 */ + /* This list of PIDs comes from toolinfo.py in Microchip's pyedbglib. */ + // Atmel JTAG-ICE 3 + { .vid = 0x03eb, .pid = 0x2140, .report_size = 512 }, + // Atmel-ICE + { .vid = 0x03eb, .pid = 0x2141, .report_size = 512 }, + // Atmel Power Debugger + { .vid = 0x03eb, .pid = 0x2144, .report_size = 512 }, + // EDBG (found on Xplained Pro boards) + { .vid = 0x03eb, .pid = 0x2111, .report_size = 512 }, + // Zero (???) + { .vid = 0x03eb, .pid = 0x2157, .report_size = 512 }, + // EDBG with Mass Storage (found on Xplained Pro boards) + { .vid = 0x03eb, .pid = 0x2169, .report_size = 512 }, + // Commercially available EDBG (for third-party use) + { .vid = 0x03eb, .pid = 0x216a, .report_size = 512 }, + // Kraken (???) + { .vid = 0x03eb, .pid = 0x2170, .report_size = 512 }, + + { .vid = 0, .pid = 0, .report_size = 0 } +}; + + static void cmsis_dap_hid_close(struct cmsis_dap *dap); static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz); +static void cmsis_dap_hid_free(struct cmsis_dap *dap); static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], const char *serial) { @@ -149,13 +169,15 @@ static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p unsigned int packet_size = 64; - /* atmel cmsis-dap uses 512 byte reports */ - /* except when it doesn't e.g. with mEDBG on SAMD10 Xplained - * board */ + /* Check for adapters that are known to have unusual report lengths. */ + for (i = 0; report_size_quirks[i].vid != 0; i++) { + if (report_size_quirks[i].vid == target_vid && + report_size_quirks[i].pid == target_pid) { + packet_size = report_size_quirks[i].report_size; + } + } /* TODO: HID report descriptor should be parsed instead of - * hardcoding a match by VID */ - if (target_vid == 0x03eb && target_pid != 0x2145 && target_pid != 0x2175) - packet_size = 512; + * hardcoding a match by VID/PID */ dap->bdata->dev_handle = dev; @@ -176,14 +198,21 @@ static void cmsis_dap_hid_close(struct cmsis_dap *dap) hid_exit(); free(dap->bdata); dap->bdata = NULL; - free(dap->packet_buffer); - dap->packet_buffer = NULL; + cmsis_dap_hid_free(dap); } -static int cmsis_dap_hid_read(struct cmsis_dap *dap, int timeout_ms) +static int cmsis_dap_hid_read(struct cmsis_dap *dap, int transfer_timeout_ms, + struct timeval *wait_timeout) { - int retval = hid_read_timeout(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_buffer_size, timeout_ms); - + int timeout_ms; + if (wait_timeout) + timeout_ms = wait_timeout->tv_usec / 1000 + wait_timeout->tv_sec * 1000; + else + timeout_ms = transfer_timeout_ms; + + int retval = hid_read_timeout(dap->bdata->dev_handle, + dap->packet_buffer, dap->packet_buffer_size, + timeout_ms); if (retval == 0) { return ERROR_TIMEOUT_REACHED; } else if (retval == -1) { @@ -224,6 +253,7 @@ static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz) dap->packet_buffer = buf; dap->packet_size = pkt_sz; + dap->packet_usable_size = pkt_sz; dap->packet_buffer_size = packet_buffer_size; dap->command = dap->packet_buffer + REPORT_ID_SIZE; @@ -232,6 +262,16 @@ static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz) return ERROR_OK; } +static void cmsis_dap_hid_free(struct cmsis_dap *dap) +{ + free(dap->packet_buffer); + dap->packet_buffer = NULL; +} + +static void cmsis_dap_hid_cancel_all(struct cmsis_dap *dap) +{ +} + const struct cmsis_dap_backend cmsis_dap_hid_backend = { .name = "hid", .open = cmsis_dap_hid_open, @@ -239,4 +279,6 @@ const struct cmsis_dap_backend cmsis_dap_hid_backend = { .read = cmsis_dap_hid_read, .write = cmsis_dap_hid_write, .packet_buffer_alloc = cmsis_dap_hid_alloc, + .packet_buffer_free = cmsis_dap_hid_free, + .cancel_all = cmsis_dap_hid_cancel_all, }; diff --git a/src/jtag/drivers/dmem.c b/src/jtag/drivers/dmem.c new file mode 100644 index 0000000000..4dc582115c --- /dev/null +++ b/src/jtag/drivers/dmem.c @@ -0,0 +1,622 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ */ + +/** + * @file + * This file implements support for the Direct memory access to CoreSight + * Access Ports (APs) or emulate the same to access CoreSight debug registers + * directly. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/mman.h> + +#include <helper/align.h> +#include <helper/types.h> +#include <helper/system.h> +#include <helper/time_support.h> +#include <helper/list.h> +#include <jtag/interface.h> + +#include <target/arm_adi_v5.h> +#include <transport/transport.h> + +struct dmem_emu_ap_info { + uint64_t ap_num; + /* Emulation mode AP state variables */ + uint32_t apbap_tar; + uint32_t apbap_csw; +}; + +/* + * This bit tells if the transaction is coming in from jtag or not + * we just mask this out to emulate direct address access + */ +#define ARM_APB_PADDR31 BIT(31) + +static void *dmem_map_base, *dmem_virt_base_addr; +static size_t dmem_mapped_size; + +/* Default dmem device. */ +#define DMEM_DEV_PATH_DEFAULT "/dev/mem" +static char *dmem_dev_path; +static uint64_t dmem_dap_base_address; +static unsigned int dmem_dap_max_aps = 1; +static uint32_t dmem_dap_ap_offset = 0x100; + +/* DAP error code. */ +static int dmem_dap_retval = ERROR_OK; + +/* AP Emulation Mode */ +static uint64_t dmem_emu_base_address; +static uint64_t dmem_emu_size; +static void *dmem_emu_map_base, *dmem_emu_virt_base_addr; +static size_t dmem_emu_mapped_size; +#define DMEM_MAX_EMULATE_APS 5 +static unsigned int dmem_emu_ap_count; +static struct dmem_emu_ap_info dmem_emu_ap_list[DMEM_MAX_EMULATE_APS]; + +/* + * This helper is used to determine the TAR increment size in bytes. The AP's + * CSW encoding for SIZE supports byte count decode using "1 << SIZE". + */ +static uint32_t dmem_memap_tar_inc(uint32_t csw) +{ + if ((csw & CSW_ADDRINC_MASK) != 0) + return 1 << (csw & CSW_SIZE_MASK); + return 0; +} + +/* + * EMULATION MODE: In Emulation MODE, we assume the following: + * TCL still describes as system is operational from the view of AP (ex. jtag) + * However, the hardware doesn't permit direct memory access to these APs + * (only permitted via JTAG). + * + * So, the access to these APs have to be decoded to a memory map + * access which we can directly access. + * + * A few TI processors have this issue. + */ +static bool dmem_is_emulated_ap(struct adiv5_ap *ap, unsigned int *idx) +{ + for (unsigned int i = 0; i < dmem_emu_ap_count; i++) { + if (ap->ap_num == dmem_emu_ap_list[i].ap_num) { + *idx = i; + return true; + } + } + return false; +} + +static void dmem_emu_set_ap_reg(uint64_t addr, uint32_t val) +{ + addr &= ~ARM_APB_PADDR31; + + *(volatile uint32_t *)((uintptr_t)dmem_emu_virt_base_addr + addr) = val; +} + +static uint32_t dmem_emu_get_ap_reg(uint64_t addr) +{ + uint32_t val; + + addr &= ~ARM_APB_PADDR31; + + val = *(volatile uint32_t *)((uintptr_t)dmem_emu_virt_base_addr + addr); + + return val; +} + +static int dmem_emu_ap_q_read(unsigned int ap_idx, unsigned int reg, uint32_t *data) +{ + uint64_t addr; + int ret = ERROR_OK; + struct dmem_emu_ap_info *ap_info = &dmem_emu_ap_list[ap_idx]; + + switch (reg) { + case ADIV5_MEM_AP_REG_CSW: + *data = ap_info->apbap_csw; + break; + case ADIV5_MEM_AP_REG_TAR: + *data = ap_info->apbap_tar; + break; + case ADIV5_MEM_AP_REG_CFG: + *data = 0; + break; + case ADIV5_MEM_AP_REG_BASE: + *data = 0; + break; + case ADIV5_AP_REG_IDR: + *data = 0; + break; + case ADIV5_MEM_AP_REG_BD0: + case ADIV5_MEM_AP_REG_BD1: + case ADIV5_MEM_AP_REG_BD2: + case ADIV5_MEM_AP_REG_BD3: + addr = (ap_info->apbap_tar & ~0xf) + (reg & 0x0C); + + *data = dmem_emu_get_ap_reg(addr); + + break; + case ADIV5_MEM_AP_REG_DRW: + addr = ap_info->apbap_tar; + + *data = dmem_emu_get_ap_reg(addr); + + ap_info->apbap_tar += dmem_memap_tar_inc(ap_info->apbap_csw); + break; + default: + LOG_INFO("%s: Unknown reg: 0x%02x", __func__, reg); + ret = ERROR_FAIL; + break; + } + + /* Track the last error code. */ + if (ret != ERROR_OK) + dmem_dap_retval = ret; + + return ret; +} + +static int dmem_emu_ap_q_write(unsigned int ap_idx, unsigned int reg, uint32_t data) +{ + uint64_t addr; + int ret = ERROR_OK; + struct dmem_emu_ap_info *ap_info = &dmem_emu_ap_list[ap_idx]; + + switch (reg) { + case ADIV5_MEM_AP_REG_CSW: + /* + * This implementation only supports 32-bit accesses. + * Force this by ensuring CSW_SIZE field indicates 32-BIT. + */ + ap_info->apbap_csw = ((data & ~CSW_SIZE_MASK) | CSW_32BIT); + break; + case ADIV5_MEM_AP_REG_TAR: + /* + * This implementation only supports 32-bit accesses. + * Force LS 2-bits of TAR to 00b + */ + ap_info->apbap_tar = (data & ~0x3); + break; + + case ADIV5_MEM_AP_REG_CFG: + case ADIV5_MEM_AP_REG_BASE: + case ADIV5_AP_REG_IDR: + /* We don't use this, so we don't need to store */ + break; + + case ADIV5_MEM_AP_REG_BD0: + case ADIV5_MEM_AP_REG_BD1: + case ADIV5_MEM_AP_REG_BD2: + case ADIV5_MEM_AP_REG_BD3: + addr = (ap_info->apbap_tar & ~0xf) + (reg & 0x0C); + + dmem_emu_set_ap_reg(addr, data); + + break; + case ADIV5_MEM_AP_REG_DRW: + addr = ap_info->apbap_tar; + dmem_emu_set_ap_reg(addr, data); + + ap_info->apbap_tar += dmem_memap_tar_inc(ap_info->apbap_csw); + break; + default: + LOG_INFO("%s: Unknown reg: 0x%02x", __func__, reg); + ret = EINVAL; + break; + } + + /* Track the last error code. */ + if (ret != ERROR_OK) + dmem_dap_retval = ret; + + return ret; +} + +/* AP MODE */ +static uint32_t dmem_get_ap_reg_offset(struct adiv5_ap *ap, unsigned int reg) +{ + return (dmem_dap_ap_offset * ap->ap_num) + reg; +} + +static void dmem_set_ap_reg(struct adiv5_ap *ap, unsigned int reg, uint32_t val) +{ + *(volatile uint32_t *)((uintptr_t)dmem_virt_base_addr + + dmem_get_ap_reg_offset(ap, reg)) = val; +} + +static uint32_t dmem_get_ap_reg(struct adiv5_ap *ap, unsigned int reg) +{ + return *(volatile uint32_t *)((uintptr_t)dmem_virt_base_addr + + dmem_get_ap_reg_offset(ap, reg)); +} + +static int dmem_dp_q_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *data) +{ + if (!data) + return ERROR_OK; + + switch (reg) { + case DP_CTRL_STAT: + *data = CDBGPWRUPACK | CSYSPWRUPACK; + break; + + default: + *data = 0; + break; + } + + return ERROR_OK; +} + +static int dmem_dp_q_write(struct adiv5_dap *dap, unsigned int reg, uint32_t data) +{ + return ERROR_OK; +} + +static int dmem_ap_q_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data) +{ + unsigned int idx; + + if (is_adiv6(ap->dap)) { + static bool error_flagged; + + if (!error_flagged) + LOG_ERROR("ADIv6 dap not supported by dmem dap-direct mode"); + + error_flagged = true; + + return ERROR_FAIL; + } + + if (dmem_is_emulated_ap(ap, &idx)) + return dmem_emu_ap_q_read(idx, reg, data); + + *data = dmem_get_ap_reg(ap, reg); + + return ERROR_OK; +} + +static int dmem_ap_q_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data) +{ + unsigned int idx; + + if (is_adiv6(ap->dap)) { + static bool error_flagged; + + if (!error_flagged) + LOG_ERROR("ADIv6 dap not supported by dmem dap-direct mode"); + + error_flagged = true; + + return ERROR_FAIL; + } + + if (dmem_is_emulated_ap(ap, &idx)) + return dmem_emu_ap_q_write(idx, reg, data); + + dmem_set_ap_reg(ap, reg, data); + + return ERROR_OK; +} + +static int dmem_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack) +{ + return ERROR_OK; +} + +static int dmem_dp_run(struct adiv5_dap *dap) +{ + int retval = dmem_dap_retval; + + /* Clear the error code. */ + dmem_dap_retval = ERROR_OK; + + return retval; +} + +static int dmem_connect(struct adiv5_dap *dap) +{ + return ERROR_OK; +} + +COMMAND_HANDLER(dmem_dap_device_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + free(dmem_dev_path); + dmem_dev_path = strdup(CMD_ARGV[0]); + + return ERROR_OK; +} + +COMMAND_HANDLER(dmem_dap_base_address_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], dmem_dap_base_address); + + return ERROR_OK; +} + +COMMAND_HANDLER(dmem_dap_max_aps_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], dmem_dap_max_aps); + + return ERROR_OK; +} + +COMMAND_HANDLER(dmem_dap_ap_offset_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], dmem_dap_ap_offset); + + return ERROR_OK; +} + +COMMAND_HANDLER(dmem_emu_base_address_command) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], dmem_emu_base_address); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], dmem_emu_size); + + return ERROR_OK; +} + +COMMAND_HANDLER(dmem_emu_ap_list_command) +{ + uint64_t em_ap; + + if (CMD_ARGC < 1 || CMD_ARGC > DMEM_MAX_EMULATE_APS) + return ERROR_COMMAND_SYNTAX_ERROR; + + for (unsigned int i = 0; i < CMD_ARGC; i++) { + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[i], em_ap); + dmem_emu_ap_list[i].ap_num = em_ap; + } + + dmem_emu_ap_count = CMD_ARGC; + + return ERROR_OK; +} + +COMMAND_HANDLER(dmem_dap_config_info_command) +{ + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + command_print(CMD, "dmem (Direct Memory) AP Adapter Configuration:"); + command_print(CMD, " Device : %s", + dmem_dev_path ? dmem_dev_path : DMEM_DEV_PATH_DEFAULT); + command_print(CMD, " Base Address : 0x%" PRIx64, dmem_dap_base_address); + command_print(CMD, " Max APs : %u", dmem_dap_max_aps); + command_print(CMD, " AP offset : 0x%08" PRIx32, dmem_dap_ap_offset); + command_print(CMD, " Emulated AP Count : %u", dmem_emu_ap_count); + + if (dmem_emu_ap_count) { + command_print(CMD, " Emulated AP details:"); + command_print(CMD, " Emulated address : 0x%" PRIx64, dmem_emu_base_address); + command_print(CMD, " Emulated size : 0x%" PRIx64, dmem_emu_size); + for (unsigned int i = 0; i < dmem_emu_ap_count; i++) + command_print(CMD, " Emulated AP [%u] : %" PRIx64, i, + dmem_emu_ap_list[i].ap_num); + } + return ERROR_OK; +} + +static const struct command_registration dmem_dap_subcommand_handlers[] = { + { + .name = "info", + .handler = dmem_dap_config_info_command, + .mode = COMMAND_ANY, + .help = "print the config info", + .usage = "", + }, + { + .name = "device", + .handler = dmem_dap_device_command, + .mode = COMMAND_CONFIG, + .help = "set the dmem memory access device (default: /dev/mem)", + .usage = "device_path", + }, + { + .name = "base_address", + .handler = dmem_dap_base_address_command, + .mode = COMMAND_CONFIG, + .help = "set the dmem dap AP memory map base address", + .usage = "base_address", + }, + { + .name = "ap_address_offset", + .handler = dmem_dap_ap_offset_command, + .mode = COMMAND_CONFIG, + .help = "set the offsets of each ap index", + .usage = "offset_address", + }, + { + .name = "max_aps", + .handler = dmem_dap_max_aps_command, + .mode = COMMAND_CONFIG, + .help = "set the maximum number of APs this will support", + .usage = "n", + }, + { + .name = "emu_ap_list", + .handler = dmem_emu_ap_list_command, + .mode = COMMAND_CONFIG, + .help = "set the list of AP indices to be emulated (upto max)", + .usage = "n", + }, + { + .name = "emu_base_address_range", + .handler = dmem_emu_base_address_command, + .mode = COMMAND_CONFIG, + .help = "set the base address and size of emulated AP range (all emulated APs access this range)", + .usage = "base_address address_window_size", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration dmem_dap_command_handlers[] = { + { + .name = "dmem", + .mode = COMMAND_ANY, + .help = "Perform dmem (Direct Memory) DAP management and configuration", + .chain = dmem_dap_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static int dmem_dap_init(void) +{ + char *path = dmem_dev_path ? dmem_dev_path : DMEM_DEV_PATH_DEFAULT; + uint32_t dmem_total_memory_window_size; + long page_size = sysconf(_SC_PAGESIZE); + size_t dmem_mapped_start, dmem_mapped_end; + long start_delta; + int dmem_fd; + + if (!dmem_dap_base_address) { + LOG_ERROR("dmem DAP Base address NOT set? value is 0"); + return ERROR_FAIL; + } + + dmem_fd = open(path, O_RDWR | O_SYNC); + if (dmem_fd == -1) { + LOG_ERROR("Unable to open %s", path); + return ERROR_FAIL; + } + + dmem_total_memory_window_size = (dmem_dap_max_aps + 1) * dmem_dap_ap_offset; + + dmem_mapped_start = dmem_dap_base_address; + dmem_mapped_end = dmem_dap_base_address + dmem_total_memory_window_size; + /* mmap() requires page aligned offsets */ + dmem_mapped_start = ALIGN_DOWN(dmem_mapped_start, page_size); + dmem_mapped_end = ALIGN_UP(dmem_mapped_end, page_size); + + dmem_mapped_size = dmem_mapped_end - dmem_mapped_start; + start_delta = dmem_mapped_start - dmem_dap_base_address; + + dmem_map_base = mmap(NULL, + dmem_mapped_size, + (PROT_READ | PROT_WRITE), + MAP_SHARED, dmem_fd, + dmem_mapped_start); + if (dmem_map_base == MAP_FAILED) { + LOG_ERROR("Mapping address 0x%lx for 0x%lx bytes failed!", + dmem_mapped_start, dmem_mapped_size); + goto error_fail; + } + + dmem_virt_base_addr = (void *)((uintptr_t)dmem_map_base + start_delta); + + /* Lets Map the emulated address if necessary */ + if (dmem_emu_ap_count) { + dmem_mapped_start = dmem_emu_base_address; + dmem_mapped_end = dmem_emu_base_address + dmem_emu_size; + /* mmap() requires page aligned offsets */ + dmem_mapped_start = ALIGN_DOWN(dmem_mapped_start, page_size); + dmem_mapped_end = ALIGN_UP(dmem_mapped_end, page_size); + + dmem_emu_mapped_size = dmem_mapped_end - dmem_mapped_start; + start_delta = dmem_mapped_start - dmem_emu_base_address; + + dmem_emu_map_base = mmap(NULL, + dmem_emu_mapped_size, + (PROT_READ | PROT_WRITE), + MAP_SHARED, dmem_fd, + dmem_mapped_start); + if (dmem_emu_map_base == MAP_FAILED) { + LOG_ERROR("Mapping EMU address 0x%lx for 0x%lx bytes failed!", + dmem_emu_base_address, dmem_emu_size); + goto error_fail; + } + dmem_emu_virt_base_addr = (void *)((uintptr_t)dmem_emu_map_base + + start_delta); + } + + close(dmem_fd); + return ERROR_OK; + +error_fail: + close(dmem_fd); + return ERROR_FAIL; +} + +static int dmem_dap_quit(void) +{ + if (munmap(dmem_map_base, dmem_mapped_size) == -1) + LOG_ERROR("%s: Failed to unmap mapped memory!", __func__); + + if (dmem_emu_ap_count + && munmap(dmem_emu_map_base, dmem_emu_mapped_size) == -1) + LOG_ERROR("%s: Failed to unmap emu mapped memory!", __func__); + + return ERROR_OK; +} + +static int dmem_dap_reset(int req_trst, int req_srst) +{ + return ERROR_OK; +} + +static int dmem_dap_speed(int speed) +{ + return ERROR_OK; +} + +static int dmem_dap_khz(int khz, int *jtag_speed) +{ + *jtag_speed = khz; + return ERROR_OK; +} + +static int dmem_dap_speed_div(int speed, int *khz) +{ + *khz = speed; + return ERROR_OK; +} + +/* DAP operations. */ +static const struct dap_ops dmem_dap_ops = { + .connect = dmem_connect, + .queue_dp_read = dmem_dp_q_read, + .queue_dp_write = dmem_dp_q_write, + .queue_ap_read = dmem_ap_q_read, + .queue_ap_write = dmem_ap_q_write, + .queue_ap_abort = dmem_ap_q_abort, + .run = dmem_dp_run, +}; + +static const char *const dmem_dap_transport[] = { "dapdirect_swd", NULL }; + +struct adapter_driver dmem_dap_adapter_driver = { + .name = "dmem", + .transports = dmem_dap_transport, + .commands = dmem_dap_command_handlers, + + .init = dmem_dap_init, + .quit = dmem_dap_quit, + .reset = dmem_dap_reset, + .speed = dmem_dap_speed, + .khz = dmem_dap_khz, + .speed_div = dmem_dap_speed_div, + + .dap_swd_ops = &dmem_dap_ops, +}; diff --git a/src/jtag/drivers/driver.c b/src/jtag/drivers/driver.c index dbe3b0819b..fae2aad229 100644 --- a/src/jtag/drivers/driver.c +++ b/src/jtag/drivers/driver.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -11,19 +13,6 @@ * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -87,16 +76,22 @@ int interface_jtag_add_ir_scan(struct jtag_tap *active, if (tap == active) { /* if TAP is listed in input fields, copy the value */ - tap->bypass = 0; + tap->bypass = false; jtag_scan_field_clone(field, in_fields); } else { /* if a TAP isn't listed in input fields, set it to BYPASS */ - tap->bypass = 1; + tap->bypass = true; field->num_bits = tap->ir_length; - field->out_value = buf_set_ones(cmd_queue_alloc(DIV_ROUND_UP(tap->ir_length, 8)), tap->ir_length); + if (tap->ir_bypass_value) { + uint8_t *v = cmd_queue_alloc(DIV_ROUND_UP(tap->ir_length, 8)); + buf_set_u64(v, 0, tap->ir_length, tap->ir_bypass_value); + field->out_value = v; + } else { + field->out_value = buf_set_ones(cmd_queue_alloc(DIV_ROUND_UP(tap->ir_length, 8)), tap->ir_length); + } field->in_value = NULL; /* do not collect input for tap's in bypass */ } diff --git a/src/jtag/drivers/dummy.c b/src/jtag/drivers/dummy.c index 7ba44803f2..02da39bc33 100644 --- a/src/jtag/drivers/dummy.c +++ b/src/jtag/drivers/dummy.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2008 by Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/jtag/drivers/ep93xx.c b/src/jtag/drivers/ep93xx.c index 94d65505f9..c3e841d37a 100644 --- a/src/jtag/drivers/ep93xx.c +++ b/src/jtag/drivers/ep93xx.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -35,7 +24,7 @@ static uint8_t output_value; static int dev_mem_fd; -static void *gpio_controller; +static uint8_t *gpio_controller; static volatile uint8_t *gpio_data_register; static volatile uint8_t *gpio_data_direction_register; @@ -48,7 +37,7 @@ static int ep93xx_reset(int trst, int srst); static int ep93xx_init(void); static int ep93xx_quit(void); -struct timespec ep93xx_zzzz; +static struct timespec ep93xx_zzzz; static struct jtag_interface ep93xx_interface = { .supported = DEBUG_CAP_TMS_SEQ, @@ -69,7 +58,7 @@ struct adapter_driver ep93xx_adapter_driver = { static struct bitbang_interface ep93xx_bitbang = { .read = ep93xx_read, .write = ep93xx_write, - .blink = 0, + .blink = NULL, }; static bb_value_t ep93xx_read(void) @@ -121,19 +110,16 @@ static int ep93xx_reset(int trst, int srst) static int set_gonk_mode(void) { - void *syscon; - uint32_t devicecfg; - - syscon = mmap(NULL, 4096, PROT_READ | PROT_WRITE, + void *syscon = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem_fd, 0x80930000); if (syscon == MAP_FAILED) { LOG_ERROR("mmap: %s", strerror(errno)); return ERROR_JTAG_INIT_FAILED; } - devicecfg = *((volatile int *)(syscon + 0x80)); - *((volatile int *)(syscon + 0xc0)) = 0xaa; - *((volatile int *)(syscon + 0x80)) = devicecfg | 0x08000000; + uint32_t devicecfg = *((volatile uint32_t *)((uintptr_t)syscon + 0x80)); + *((volatile uint32_t *)((uintptr_t)syscon + 0xc0)) = 0xaa; + *((volatile uint32_t *)((uintptr_t)syscon + 0x80)) = devicecfg | 0x08000000; munmap(syscon, 4096); diff --git a/src/jtag/drivers/esp_usb_jtag.c b/src/jtag/drivers/esp_usb_jtag.c new file mode 100644 index 0000000000..9504059543 --- /dev/null +++ b/src/jtag/drivers/esp_usb_jtag.c @@ -0,0 +1,797 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Espressif USB to Jtag adapter * + * Copyright (C) 2020 Espressif Systems (Shanghai) Co. Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <jtag/adapter.h> +#include <jtag/interface.h> +#include <helper/time_support.h> +#include <helper/bits.h> +#include "bitq.h" +#include "libusb_helper.h" + +/* +Holy Crap, it's protocol documentation, and it's even vendor-provided! + +A device that speaks this protocol has two endpoints intended for JTAG debugging: one +OUT for the host to send encoded commands to, one IN from which the host can read any read +TDO bits. The device will also respond to vendor-defined interface requests on ep0. + +The main communication method is over the IN/OUT endpoints. The commands that are expected +on the OUT endpoint are one nibble wide and are processed high-nibble-first, low-nibble-second, +and in the order the bytes come in. Commands are defined as follows: + + bit 3 2 1 0 +CMD_CLK [ 0 cap tdi tms ] +CMD_RST [ 1 0 0 srst ] +CMD_FLUSH [ 1 0 1 0 ] +CMD_RSV [ 1 0 1 1 ] +CMD_REP [ 1 1 R1 R0 ] + +CMD_CLK sets the TDI and TMS lines to the value of `tdi` and `tms` and lowers, then raises, TCK. If +`cap` is 1, the value of TDO is captured and can be retrieved over the IN endpoint. The bytes read from +the IN endpoint specifically are these bits, with the lowest it in every byte captured first and the +bytes returned in the order the data in them was captured. The durations of TCK being high / low can +be set using the VEND_JTAG_SETDIV vendor-specific interface request. + +CMD_RST controls the SRST line; as soon as the command is processed, the SRST line will be set +to the value of `srst`. + +CMD_FLUSH flushes the IN endpoint; zeroes will be added to the amount of bits in the endpoint until +the payload is a multiple of bytes, and the data is offered to the host. If the IN endpoint has +no data, this effectively becomes a no-op; the endpoint won't send any 0-byte payloads. + +CMD_RSV is reserved for future use. + +CMD_REP repeats the last command that is not CMD_REP. The amount of times a CMD_REP command will +re-execute this command is (r1*2+r0)<<(2*n), where n is the amount of previous repeat commands executed +since the command to be repeated. + +An example for CMD_REP: Say the host queues: +1. CMD_CLK - This will execute one CMD_CLK. +2. CMD_REP with r1=0 and r0=1 - This will execute 1. another (0*2+1)<<(2*0)=1 time. +3. CMD_REP with r1=1 and r0=0 - This will execute 1. another (1*2+0)<<(2*1)=4 times. +4. CMD_REP with r1=0 and r0=1 - This will execute 1. another (0*2+1)<<(2*2)=8 time. +5. CMD_FLUSH - This will flush the IN pipeline. +6. CMD_CLK - This will execute one CMD_CLK +7. CMD_REP with r1=1 and r0=0 - This will execute 6. another (1*2+0)<<(2*0)=2 times. +8. CMD_FLUSH - This will flush the IN pipeline. + +Note that the net effect of the repetitions is that command 1 is executed (1+1+4+8=) 14 times and +command 6 is executed (1+2=) 3 times. + +Note that the device only has a fairly limited amount of endpoint RAM. It's probably best to keep +an eye on the amount of bytes that are supposed to be in the IN endpoint and grab those before stuffing +more commands into the OUT endpoint: the OUT endpoint will not accept any more commands (writes will +time out) when the IN endpoint buffers are all filled up. + +The device also supports some vendor-specific interface requests. These requests are sent as control +transfers on endpoint 0 to the JTAG endpoint. Note that these commands bypass the data in the OUT +endpoint; if timing is important, it's important that this endpoint is empty. This can be done by +e.g sending one CMD_CLK capturing TDI, then one CMD_FLUSH, then waiting until the bit appears on the +IN endpoint. + +bmRequestType bRequest wValue wIndex wLength Data +01000000b VEND_JTAG_SETDIV [divide] interface 0 None +01000000b VEND_JTAG_SETIO [iobits] interface 0 None +11000000b VEND_JTAG_GETTDO 0 interface 1 [iostate] +10000000b GET_DESCRIPTOR(6) 0x2000 0 256 [jtag cap desc] + +VEND_JTAG_SETDIV indirectly controls the speed of the TCK clock. The value written here is the length +of a TCK cycle, in ticks of the adapters base clock. Both the base clock value as well as the +minimum and maximum divider can be read from the jtag capabilities descriptor, as explained +below. Note that this should not be set to a value outside of the range described there, +otherwise results are undefined. + +VEND_JTAG_SETIO can be controlled to directly set the IO pins. The format of [iobits] normally is +{11'b0, srst, trst, tck, tms, tdi} +Note that the first 11 0 bits are reserved for future use, current hardware ignores them. + +VEND_JTAG_GETTDO returns one byte, of which bit 0 indicates the current state of the TDO input. +Note that other bits are reserved for future use and should be ignored. + +To describe the capabilities of the JTAG adapter, a specific descriptor (0x20) can be retrieved. +The format of the descriptor documented below. The descriptor works in the same fashion as USB +descriptors: a header indicating the version and total length followed by descriptors with a +specific type and size. Forward compatibility is guaranteed as software can skip over an unknown +descriptor. + +*/ + +#define JTAG_PROTO_CAPS_VER 1 /* Version field. At the moment, only version 1 is defined. */ +struct jtag_proto_caps_hdr { + uint8_t proto_ver; /* Protocol version. Expects JTAG_PROTO_CAPS_VER for now. */ + uint8_t length; /* of this plus any following descriptors */ +} __attribute__((packed)); + +/* start of the descriptor headers */ +#define JTAG_BUILTIN_DESCR_START_OFF 0 /* Devices with builtin usb jtag */ +/* +* ESP USB Bridge https://github.com/espressif/esp-usb-bridge uses string descriptor. +* Skip 1 byte length and 1 byte descriptor type +*/ +#define JTAG_EUB_DESCR_START_OFF 2 /* ESP USB Bridge */ + +/* +Note: At the moment, there is only a speed_caps version indicating the base speed of the JTAG +hardware is derived from the APB bus speed of the SoC. If later on, there are standalone +converters using the protocol, we should define e.g. JTAG_PROTO_CAPS_SPEED_FIXED_TYPE to distinguish +between the two. + +Note: If the JTAG device has larger buffers than endpoint-size-plus-a-bit, we should have some kind +of caps header to assume this. If no such caps exist, assume a minimum (in) buffer of endpoint size + 4. +*/ + +struct jtag_gen_hdr { + uint8_t type; + uint8_t length; +} __attribute__((packed)); + +struct jtag_proto_caps_speed_apb { + uint8_t type; /* Type, always JTAG_PROTO_CAPS_SPEED_APB_TYPE */ + uint8_t length; /* Length of this */ + uint8_t apb_speed_10khz[2]; /* ABP bus speed, in 10KHz increments. Base speed is half this. */ + uint8_t div_min[2]; /* minimum divisor (to base speed), inclusive */ + uint8_t div_max[2]; /* maximum divisor (to base speed), inclusive */ +} __attribute__((packed)); + +#define JTAG_PROTO_CAPS_DATA_LEN 255 +#define JTAG_PROTO_CAPS_SPEED_APB_TYPE 1 + +#define VEND_DESCR_BUILTIN_JTAG_CAPS 0x2000 + +#define VEND_JTAG_SETDIV 0 +#define VEND_JTAG_SETIO 1 +#define VEND_JTAG_GETTDO 2 +#define VEND_JTAG_SET_CHIPID 3 + +#define VEND_JTAG_SETIO_TDI BIT(0) +#define VEND_JTAG_SETIO_TMS BIT(1) +#define VEND_JTAG_SETIO_TCK BIT(2) +#define VEND_JTAG_SETIO_TRST BIT(3) +#define VEND_JTAG_SETIO_SRST BIT(4) + +#define CMD_CLK(cap, tdi, tms) ((cap ? BIT(2) : 0) | (tms ? BIT(1) : 0) | (tdi ? BIT(0) : 0)) +#define CMD_RST(srst) (0x8 | (srst ? BIT(0) : 0)) +#define CMD_FLUSH 0xA +#define CMD_RSVD 0xB +#define CMD_REP(r) (0xC + ((r) & 3)) + +/* The internal repeats register is 10 bits, which means we can have 5 repeat commands in a + *row at max. This translates to ('b1111111111+1=)1024 reps max. */ +#define CMD_REP_MAX_REPS 1024 + +/* Currently we only support one USB device. */ +#define USB_CONFIGURATION 0 + +/* Buffer size; is equal to the endpoint size. In bytes + * TODO for future adapters: read from device configuration? */ +#define OUT_EP_SZ 64 +/* Out data can be buffered for longer without issues (as long as the in buffer does not overflow), + * so we'll use an out buffer that is much larger than the out ep size. */ +#define OUT_BUF_SZ (OUT_EP_SZ * 32) +/* The in buffer cannot be larger than the device can offer, though. */ +#define IN_BUF_SZ 64 + +/* Because a series of out commands can lead to a multitude of IN_BUF_SZ-sized in packets + *to be read, we have multiple buffers to store those before the bitq interface reads them out. */ +#define IN_BUF_CT 8 + +#define ESP_USB_INTERFACE 1 + +/* Private data */ +struct esp_usb_jtag { + struct libusb_device_handle *usb_device; + uint32_t base_speed_khz; + uint16_t div_min; + uint16_t div_max; + uint8_t out_buf[OUT_BUF_SZ]; + unsigned int out_buf_pos_nibbles; /* write position in out_buf */ + + uint8_t in_buf[IN_BUF_CT][IN_BUF_SZ]; + unsigned int in_buf_size_bits[IN_BUF_CT]; /* size in bits of the data stored in an in_buf */ + unsigned int cur_in_buf_rd, cur_in_buf_wr; /* read/write index */ + unsigned int in_buf_pos_bits; /* which bit in the in buf needs to be returned to bitq next */ + + unsigned int read_ep; + unsigned int write_ep; + + unsigned int prev_cmd; /* previous command, stored here for RLEing. */ + int prev_cmd_repct; /* Amount of repetitions of that command we have seen until now */ + + /* This is the total number of in bits we need to read, including in unsent commands */ + unsigned int pending_in_bits; + + unsigned int hw_in_fifo_len; + + struct bitq_interface bitq_interface; +}; + +/* For now, we only use one static private struct. Technically, we can re-work this, but I don't think + * OpenOCD supports multiple JTAG adapters anyway. */ +static struct esp_usb_jtag esp_usb_jtag_priv; +static struct esp_usb_jtag *priv = &esp_usb_jtag_priv; + +static int esp_usb_vid; +static int esp_usb_pid; +static int esp_usb_jtag_caps; +static int esp_usb_target_chip_id; + +static int esp_usb_jtag_init(void); +static int esp_usb_jtag_quit(void); + +/* Try to receive from USB endpoint into the current priv->in_buf */ +static int esp_usb_jtag_recv_buf(void) +{ + if (priv->in_buf_size_bits[priv->cur_in_buf_wr] != 0) + LOG_ERROR("esp_usb_jtag: IN buffer overflow! (%d, size %d)", + priv->cur_in_buf_wr, + priv->in_buf_size_bits[priv->cur_in_buf_wr]); + + unsigned int recvd = 0, ct = (priv->pending_in_bits + 7) / 8; + if (ct > IN_BUF_SZ) + ct = IN_BUF_SZ; + if (ct == 0) { + /* Note that the adapters IN EP specifically does *not* usually generate 0-byte in + * packets if there has been no data since the last flush. + * As such, we don't need (and shouldn't) try to read it. */ + return ERROR_OK; + } + + priv->in_buf_size_bits[priv->cur_in_buf_wr] = 0; + while (recvd < ct) { + unsigned int tr; + int ret = jtag_libusb_bulk_read(priv->usb_device, + priv->read_ep, + (char *)priv->in_buf[priv->cur_in_buf_wr] + recvd, + ct, + LIBUSB_TIMEOUT_MS, /*ms*/ + (int *)&tr); + if (ret != ERROR_OK || tr == 0) { + /* Sometimes the hardware returns 0 bytes instead of NAKking the transaction. Ignore this. */ + return ERROR_FAIL; + } + + if (tr != ct) { + /* Huh, short read? */ + LOG_DEBUG("esp_usb_jtag: usb received only %d out of %d bytes.", tr, ct); + } + /* Adjust the amount of bits we still expect to read from the USB device after this. */ + unsigned int bits_in_buf = priv->pending_in_bits; /* initially assume we read + * everything that was pending */ + if (bits_in_buf > tr * 8) + bits_in_buf = tr * 8; /* ...but correct that if that was not the case. */ + priv->pending_in_bits -= bits_in_buf; + priv->in_buf_size_bits[priv->cur_in_buf_wr] += bits_in_buf; + recvd += tr; + } + /* next in buffer for the next time. */ + priv->cur_in_buf_wr++; + if (priv->cur_in_buf_wr == IN_BUF_CT) + priv->cur_in_buf_wr = 0; + LOG_DEBUG_IO("esp_usb_jtag: In ep: received %d bytes; %d bytes (%d bits) left.", recvd, + (priv->pending_in_bits + 7) / 8, priv->pending_in_bits); + return ERROR_OK; +} + +/* Sends priv->out_buf to the USB device. */ +static int esp_usb_jtag_send_buf(void) +{ + unsigned int ct = priv->out_buf_pos_nibbles / 2; + unsigned int written = 0; + + while (written < ct) { + int tr = 0, ret = jtag_libusb_bulk_write(priv->usb_device, + priv->write_ep, + (char *)priv->out_buf + written, + ct - written, + LIBUSB_TIMEOUT_MS, /*ms*/ + &tr); + LOG_DEBUG_IO("esp_usb_jtag: sent %d bytes.", tr); + if (written + tr != ct) { + LOG_DEBUG("esp_usb_jtag: usb sent only %d out of %d bytes.", + written + tr, + ct); + } + if (ret != ERROR_OK) + return ret; + written += tr; + } + priv->out_buf_pos_nibbles = 0; + + /* If there's more than a bufferful of data queuing up in the jtag adapters IN endpoint, empty + * all but one buffer. */ + while (priv->pending_in_bits > (IN_BUF_SZ + priv->hw_in_fifo_len - 1) * 8) + esp_usb_jtag_recv_buf(); + + return ERROR_OK; +} + +/* Simply adds a command to the buffer. Is called by the RLE encoding mechanism. + *Also sends the intermediate buffer if there's enough to go into one USB packet. */ +static int esp_usb_jtag_command_add_raw(unsigned int cmd) +{ + int ret = ERROR_OK; + + if ((priv->out_buf_pos_nibbles & 1) == 0) + priv->out_buf[priv->out_buf_pos_nibbles / 2] = (cmd << 4); + else + priv->out_buf[priv->out_buf_pos_nibbles / 2] |= cmd; + priv->out_buf_pos_nibbles++; + + if (priv->out_buf_pos_nibbles == OUT_BUF_SZ * 2) + ret = esp_usb_jtag_send_buf(); + if (ret == ERROR_OK && priv->out_buf_pos_nibbles % (OUT_EP_SZ * 2) == 0) { + if (priv->pending_in_bits > (IN_BUF_SZ + priv->hw_in_fifo_len - 1) * 8) + ret = esp_usb_jtag_send_buf(); + } + return ret; +} + +/* Writes a command stream equivalent to writing `cmd` `ct` times. */ +static int esp_usb_jtag_write_rlestream(unsigned int cmd, int ct) +{ + /* Special case: stacking flush commands does not make sense (and may not make the hardware very happy) */ + if (cmd == CMD_FLUSH) + ct = 1; + /* Output previous command and repeat commands */ + int ret = esp_usb_jtag_command_add_raw(cmd); + if (ret != ERROR_OK) + return ret; + ct--; /* as the previous line already executes the command one time */ + while (ct > 0) { + ret = esp_usb_jtag_command_add_raw(CMD_REP(ct & 3)); + if (ret != ERROR_OK) + return ret; + ct >>= 2; + } + return ERROR_OK; +} + +/* Adds a command to the buffer of things to be sent. Transparently handles RLE compression using + * the CMD_REP_x commands */ +static int esp_usb_jtag_command_add(unsigned int cmd) +{ + if (cmd == priv->prev_cmd && priv->prev_cmd_repct < CMD_REP_MAX_REPS) { + priv->prev_cmd_repct++; + } else { + /* We can now write out the previous command plus repeat count. */ + if (priv->prev_cmd_repct) { + int ret = esp_usb_jtag_write_rlestream(priv->prev_cmd, priv->prev_cmd_repct); + if (ret != ERROR_OK) + return ret; + } + /* Ready for new command. */ + priv->prev_cmd = cmd; + priv->prev_cmd_repct = 1; + } + return ERROR_OK; +} + +/* Called by bitq interface to output a bit on tdi and perhaps read a bit from tdo */ +static int esp_usb_jtag_out(int tms, int tdi, int tdo_req) +{ + int ret = esp_usb_jtag_command_add(CMD_CLK(tdo_req, tdi, tms)); + if (ret != ERROR_OK) + return ret; + if (tdo_req) + priv->pending_in_bits++; + return ERROR_OK; +} + +/* Called by bitq interface to flush all output commands and get returned data ready to read */ +static int esp_usb_jtag_flush(void) +{ + int ret; + /*Make sure last command is written */ + if (priv->prev_cmd_repct) { + ret = esp_usb_jtag_write_rlestream(priv->prev_cmd, priv->prev_cmd_repct); + if (ret != ERROR_OK) + return ret; + } + priv->prev_cmd_repct = 0; + /* Flush in buffer */ + ret = esp_usb_jtag_command_add_raw(CMD_FLUSH); + if (ret != ERROR_OK) + return ret; + /* Make sure we have an even amount of commands, as we can't write a nibble by itself. */ + if (priv->out_buf_pos_nibbles & 1) { + /*If not, pad with an extra FLUSH */ + ret = esp_usb_jtag_command_add_raw(CMD_FLUSH); + if (ret != ERROR_OK) + return ret; + } + LOG_DEBUG_IO("esp_usb_jtag: Flush!"); + /* Send off the buffer. */ + ret = esp_usb_jtag_send_buf(); + if (ret != ERROR_OK) + return ret; + + /* Immediately fetch the response bits. */ + while (priv->pending_in_bits > 0) + esp_usb_jtag_recv_buf(); + + return ERROR_OK; +} + +/* Called by bitq interface to sleep for a determined amount of time */ +static int esp_usb_jtag_sleep(unsigned long us) +{ + esp_usb_jtag_flush(); + /* TODO: we can sleep more precisely (for small amounts of sleep at least) by sending dummy + * commands to the adapter. */ + jtag_sleep(us); + return 0; +} + +/* Called by the bitq interface to set the various resets */ +static int esp_usb_jtag_reset(int trst, int srst) +{ + /* TODO: handle trst using setup commands. Kind-of superfluous, however, as we can also do + * a tap reset using tms, and it's also not implemented on other ESP32 chips with external JTAG. */ + return esp_usb_jtag_command_add(CMD_RST(srst)); +} + +/* Called by bitq to see if the IN data already is returned to the host. */ +static int esp_usb_jtag_in_rdy(void) +{ + /* We read all bits in the flush() routine, so if we're here, we have bits or are at EOF. */ + return 1; +} + +/* Read one bit from the IN data */ +static int esp_usb_jtag_in(void) +{ + if (!esp_usb_jtag_in_rdy()) { + LOG_ERROR("esp_usb_jtag: Eeek! bitq asked us for in data while not ready!"); + return -1; + } + if (priv->cur_in_buf_rd == priv->cur_in_buf_wr && + priv->in_buf_size_bits[priv->cur_in_buf_rd] == 0) + return -1; + + /* Extract the bit */ + int r = (priv->in_buf[priv->cur_in_buf_rd][priv->in_buf_pos_bits / 8] & + BIT(priv->in_buf_pos_bits & 7)) ? 1 : 0; + /* Move to next bit. */ + priv->in_buf_pos_bits++; + if (priv->in_buf_pos_bits == priv->in_buf_size_bits[priv->cur_in_buf_rd]) { + /* No more bits in this buffer; mark as re-usable and move to next buffer. */ + priv->in_buf_pos_bits = 0; + priv->in_buf_size_bits[priv->cur_in_buf_rd] = 0;/*indicate it is free again */ + priv->cur_in_buf_rd++; + if (priv->cur_in_buf_rd == IN_BUF_CT) + priv->cur_in_buf_rd = 0; + } + return r; +} + +static int esp_usb_jtag_init(void) +{ + memset(priv, 0, sizeof(struct esp_usb_jtag)); + + const uint16_t vids[] = { esp_usb_vid, 0 }; /* must be null terminated */ + const uint16_t pids[] = { esp_usb_pid, 0 }; /* must be null terminated */ + + bitq_interface = &priv->bitq_interface; + bitq_interface->out = esp_usb_jtag_out; + bitq_interface->flush = esp_usb_jtag_flush; + bitq_interface->sleep = esp_usb_jtag_sleep; + bitq_interface->reset = esp_usb_jtag_reset; + bitq_interface->in_rdy = esp_usb_jtag_in_rdy; + bitq_interface->in = esp_usb_jtag_in; + + int r = jtag_libusb_open(vids, pids, NULL, &priv->usb_device, NULL); + if (r != ERROR_OK) { + LOG_ERROR("esp_usb_jtag: could not find or open device!"); + goto out; + } + + jtag_libusb_set_configuration(priv->usb_device, USB_CONFIGURATION); + + r = jtag_libusb_choose_interface(priv->usb_device, &priv->read_ep, &priv->write_ep, + LIBUSB_CLASS_VENDOR_SPEC, LIBUSB_CLASS_VENDOR_SPEC, ESP_USB_INTERFACE, LIBUSB_TRANSFER_TYPE_BULK); + if (r != ERROR_OK) { + LOG_ERROR("esp_usb_jtag: error finding/claiming JTAG interface on device!"); + goto out; + } + + /* TODO: This is not proper way to get caps data. Two requests can be done. + * 1- With the minimum size required to get to know the total length of that struct, + * 2- Then exactly the length of that struct. */ + uint8_t jtag_caps_desc[JTAG_PROTO_CAPS_DATA_LEN]; + int jtag_caps_read_len; + r = jtag_libusb_control_transfer(priv->usb_device, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, + LIBUSB_REQUEST_GET_DESCRIPTOR, esp_usb_jtag_caps, 0, + (char *)jtag_caps_desc, JTAG_PROTO_CAPS_DATA_LEN, LIBUSB_TIMEOUT_MS, + &jtag_caps_read_len); + if (r != ERROR_OK) { + LOG_ERROR("esp_usb_jtag: could not retrieve jtag_caps descriptor!"); + goto out; + } + + /* defaults for values we normally get from the jtag caps descriptor */ + priv->base_speed_khz = UINT32_MAX; + priv->div_min = 1; + priv->div_max = 1; + + int p = esp_usb_jtag_caps == + VEND_DESCR_BUILTIN_JTAG_CAPS ? JTAG_BUILTIN_DESCR_START_OFF : JTAG_EUB_DESCR_START_OFF; + + if (p + sizeof(struct jtag_proto_caps_hdr) > (unsigned int)jtag_caps_read_len) { + LOG_ERROR("esp_usb_jtag: not enough data to get header"); + goto out; + } + + struct jtag_proto_caps_hdr *hdr = (struct jtag_proto_caps_hdr *)&jtag_caps_desc[p]; + if (hdr->proto_ver != JTAG_PROTO_CAPS_VER) { + LOG_ERROR("esp_usb_jtag: unknown jtag_caps descriptor version 0x%X!", + hdr->proto_ver); + goto out; + } + if (hdr->length > jtag_caps_read_len) { + LOG_ERROR("esp_usb_jtag: header length (%d) bigger then max read bytes (%d)", + hdr->length, jtag_caps_read_len); + goto out; + } + + p += sizeof(struct jtag_proto_caps_hdr); + + while (p + sizeof(struct jtag_gen_hdr) < hdr->length) { + struct jtag_gen_hdr *dhdr = (struct jtag_gen_hdr *)&jtag_caps_desc[p]; + if (dhdr->type == JTAG_PROTO_CAPS_SPEED_APB_TYPE) { + if (p + sizeof(struct jtag_proto_caps_speed_apb) < hdr->length) { + LOG_ERROR("esp_usb_jtag: not enough data to get caps speed"); + goto out; + } + struct jtag_proto_caps_speed_apb *spcap = (struct jtag_proto_caps_speed_apb *)dhdr; + /* base speed always is half APB speed */ + priv->base_speed_khz = le_to_h_u16(spcap->apb_speed_10khz) * 10 / 2; + priv->div_min = le_to_h_u16(spcap->div_min); + priv->div_max = le_to_h_u16(spcap->div_max); + /* TODO: mark in priv that this is apb-derived and as such may change if apb + * ever changes? */ + } else { + LOG_WARNING("esp_usb_jtag: unknown caps type 0x%X", dhdr->type); + } + p += dhdr->length; + } + if (priv->base_speed_khz == UINT32_MAX) { + LOG_WARNING("esp_usb_jtag: No speed caps found... using sane-ish defaults."); + priv->base_speed_khz = 1000; + } + LOG_INFO("esp_usb_jtag: Device found. Base speed %dKHz, div range %d to %d", + priv->base_speed_khz, priv->div_min, priv->div_max); + + /* TODO: grab from (future) descriptor if we ever have a device with larger IN buffers */ + priv->hw_in_fifo_len = 4; + + /* inform bridge board about the connected target chip for the specific operations + * it is also safe to send this info to chips that have builtin usb jtag */ + jtag_libusb_control_transfer(priv->usb_device, + LIBUSB_REQUEST_TYPE_VENDOR, + VEND_JTAG_SET_CHIPID, + esp_usb_target_chip_id, + 0, + NULL, + 0, + LIBUSB_TIMEOUT_MS, + NULL); + + return ERROR_OK; + +out: + if (priv->usb_device) + jtag_libusb_close(priv->usb_device); + bitq_interface = NULL; + priv->usb_device = NULL; + return ERROR_FAIL; +} + +static int esp_usb_jtag_quit(void) +{ + if (!priv->usb_device) + return ERROR_OK; + jtag_libusb_close(priv->usb_device); + bitq_cleanup(); + bitq_interface = NULL; + return ERROR_OK; +} + +static int esp_usb_jtag_speed_div(int divisor, int *khz) +{ + *khz = priv->base_speed_khz / divisor; + return ERROR_OK; +} + +static int esp_usb_jtag_khz(int khz, int *divisor) +{ + if (khz == 0) { + LOG_WARNING("esp_usb_jtag: RCLK not supported"); + return ERROR_FAIL; + } + + *divisor = priv->base_speed_khz / khz; + LOG_DEBUG("Divisor for %d KHz with base clock of %d khz is %d", + khz, + priv->base_speed_khz, + *divisor); + if (*divisor < priv->div_min) + *divisor = priv->div_min; + if (*divisor > priv->div_max) + *divisor = priv->div_max; + + return ERROR_OK; +} + +static int esp_usb_jtag_speed(int divisor) +{ + if (divisor == 0) { + LOG_ERROR("esp_usb_jtag: Adaptive clocking is not supported."); + return ERROR_JTAG_NOT_IMPLEMENTED; + } + + LOG_DEBUG("esp_usb_jtag: setting divisor %d", divisor); + jtag_libusb_control_transfer(priv->usb_device, + LIBUSB_REQUEST_TYPE_VENDOR, VEND_JTAG_SETDIV, divisor, 0, NULL, 0, LIBUSB_TIMEOUT_MS, NULL); + + return ERROR_OK; +} + +COMMAND_HANDLER(esp_usb_jtag_tdo_cmd) +{ + char tdo; + if (!priv->usb_device) + return ERROR_FAIL; + int r = jtag_libusb_control_transfer(priv->usb_device, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR, VEND_JTAG_GETTDO, 0, 0, &tdo, 1, LIBUSB_TIMEOUT_MS, NULL); + if (r != ERROR_OK) + return r; + + command_print(CMD, "%d", tdo); + + return ERROR_OK; +} + +COMMAND_HANDLER(esp_usb_jtag_setio_cmd) +{ + uint32_t tdi, tms, tck, trst, srst; + uint16_t d = 0; + + if (!priv->usb_device) + return ERROR_FAIL; + + if (CMD_ARGC != 5) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], tdi); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], tms); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], tck); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], trst); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], srst); + if (tdi) + d |= VEND_JTAG_SETIO_TDI; + if (tms) + d |= VEND_JTAG_SETIO_TMS; + if (tck) + d |= VEND_JTAG_SETIO_TCK; + if (trst) + d |= VEND_JTAG_SETIO_TRST; + if (srst) + d |= VEND_JTAG_SETIO_SRST; + + jtag_libusb_control_transfer(priv->usb_device, + 0x40, VEND_JTAG_SETIO, d, 0, NULL, 0, LIBUSB_TIMEOUT_MS, NULL); + + return ERROR_OK; +} + +COMMAND_HANDLER(esp_usb_jtag_vid_pid) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], esp_usb_vid); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], esp_usb_pid); + LOG_INFO("esp_usb_jtag: VID set to 0x%x and PID to 0x%x", esp_usb_vid, esp_usb_pid); + + return ERROR_OK; +} + +COMMAND_HANDLER(esp_usb_jtag_caps_descriptor) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], esp_usb_jtag_caps); + LOG_INFO("esp_usb_jtag: capabilities descriptor set to 0x%x", esp_usb_jtag_caps); + + return ERROR_OK; +} + +COMMAND_HANDLER(esp_usb_jtag_chip_id) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], esp_usb_target_chip_id); + LOG_INFO("esp_usb_jtag: target chip id set to %d", esp_usb_target_chip_id); + + return ERROR_OK; +} + +static const struct command_registration esp_usb_jtag_subcommands[] = { + { + .name = "tdo", + .handler = &esp_usb_jtag_tdo_cmd, + .mode = COMMAND_EXEC, + .help = "Returns the current state of the TDO line", + .usage = "", + }, + { + .name = "setio", + .handler = &esp_usb_jtag_setio_cmd, + .mode = COMMAND_EXEC, + .help = "Manually set the status of the output lines", + .usage = "tdi tms tck trst srst" + }, + { + .name = "vid_pid", + .handler = &esp_usb_jtag_vid_pid, + .mode = COMMAND_CONFIG, + .help = "set vendor ID and product ID for ESP usb jtag driver", + .usage = "vid pid", + }, + { + .name = "caps_descriptor", + .handler = &esp_usb_jtag_caps_descriptor, + .mode = COMMAND_CONFIG, + .help = "set jtag descriptor to read capabilities of ESP usb jtag driver", + .usage = "descriptor", + }, + { + .name = "chip_id", + .handler = &esp_usb_jtag_chip_id, + .mode = COMMAND_CONFIG, + .help = "set chip_id to transfer to the bridge", + .usage = "chip_id", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration esp_usb_jtag_commands[] = { + { + .name = "espusbjtag", + .mode = COMMAND_ANY, + .help = "ESP-USB-JTAG commands", + .chain = esp_usb_jtag_subcommands, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static struct jtag_interface esp_usb_jtag_interface = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = bitq_execute_queue, +}; + +struct adapter_driver esp_usb_adapter_driver = { + .name = "esp_usb_jtag", + .transports = jtag_only, + .commands = esp_usb_jtag_commands, + + .init = esp_usb_jtag_init, + .quit = esp_usb_jtag_quit, + .speed_div = esp_usb_jtag_speed_div, + .speed = esp_usb_jtag_speed, + .khz = esp_usb_jtag_khz, + + .jtag_ops = &esp_usb_jtag_interface, +}; diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c index c930d8c4c1..766f6ddb5d 100644 --- a/src/jtag/drivers/ft232r.c +++ b/src/jtag/drivers/ft232r.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2010 Serge Vakulenko * * serge@vak.ru * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -246,7 +235,7 @@ static int ft232r_speed(int divisor) if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, - SIO_SET_BAUD_RATE, divisor, 0, 0, 0, 1000) != 0) { + SIO_SET_BAUD_RATE, divisor, 0, NULL, 0, 1000, NULL) != ERROR_OK) { LOG_ERROR("cannot set baud rate"); return ERROR_JTAG_DEVICE_ERROR; } @@ -257,7 +246,7 @@ static int ft232r_init(void) { uint16_t avids[] = {ft232r_vid, 0}; uint16_t apids[] = {ft232r_pid, 0}; - if (jtag_libusb_open(avids, apids, &adapter, NULL)) { + if (jtag_libusb_open(avids, apids, NULL, &adapter, NULL)) { const char *ft232r_serial_desc = adapter_get_required_serial(); LOG_ERROR("ft232r not found: vid=%04x, pid=%04x, serial=%s\n", ft232r_vid, ft232r_pid, (!ft232r_serial_desc) ? "[any]" : ft232r_serial_desc); @@ -277,7 +266,7 @@ static int ft232r_init(void) /* Reset the device. */ if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, - SIO_RESET, 0, 0, 0, 0, 1000) != 0) { + SIO_RESET, 0, 0, NULL, 0, 1000, NULL) != ERROR_OK) { LOG_ERROR("unable to reset device"); return ERROR_JTAG_INIT_FAILED; } @@ -286,7 +275,7 @@ static int ft232r_init(void) if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, SIO_SET_BITMODE, (1<<tck_gpio) | (1<<tdi_gpio) | (1<<tms_gpio) | (1<<ntrst_gpio) | (1<<nsysrst_gpio) | 0x400, - 0, 0, 0, 1000) != 0) { + 0, NULL, 0, 1000, NULL) != ERROR_OK) { LOG_ERROR("cannot set sync bitbang mode"); return ERROR_JTAG_INIT_FAILED; } @@ -299,13 +288,13 @@ static int ft232r_init(void) if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, SIO_SET_BAUD_RATE, divisor, - 0, 0, 0, 1000) != 0) { + 0, NULL, 0, 1000, NULL) != ERROR_OK) { LOG_ERROR("cannot set baud rate"); return ERROR_JTAG_INIT_FAILED; } if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, - SIO_SET_LATENCY_TIMER, latency_timer, 0, 0, 0, 1000) != 0) { + SIO_SET_LATENCY_TIMER, latency_timer, 0, NULL, 0, 1000, NULL) != ERROR_OK) { LOG_ERROR("unable to set latency timer"); return ERROR_JTAG_INIT_FAILED; } @@ -326,7 +315,7 @@ static int ft232r_quit(void) if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, SIO_SET_BITMODE, ft232r_restore_bitmode, - 0, 0, 0, 1000) != 0) { + 0, NULL, 0, 1000, NULL) != ERROR_OK) { LOG_ERROR("cannot set bitmode to restore serial port"); } } @@ -814,9 +803,9 @@ static void syncbb_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int } } -static int syncbb_execute_queue(void) +static int syncbb_execute_queue(struct jtag_command *cmd_queue) { - struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ + struct jtag_command *cmd = cmd_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 16cb0274b2..49762bcbeb 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /************************************************************************** * Copyright (C) 2012 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * -* * -* 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/>. * ***************************************************************************/ /** @@ -75,6 +64,7 @@ #include <transport/transport.h> #include <helper/time_support.h> #include <helper/log.h> +#include <helper/nvp.h> #if IS_CYGWIN == 1 #include <windows.h> @@ -235,7 +225,7 @@ static int ftdi_set_signal(const struct signal *s, char value) oe = s->invert_oe; break; default: - assert(0 && "invalid signal level specifier"); + LOG_ERROR("invalid signal level specifier \'%c\'(0x%02x)", value, value); return ERROR_FAIL; } @@ -712,14 +702,14 @@ static void ftdi_execute_command(struct jtag_command *cmd) } } -static int ftdi_execute_queue(void) +static int ftdi_execute_queue(struct jtag_command *cmd_queue) { /* blink, if the current layout has that feature */ struct signal *led = find_signal_by_name("LED"); if (led) ftdi_set_signal(led, '1'); - for (struct jtag_command *cmd = jtag_command_queue; cmd; cmd = cmd->next) { + for (struct jtag_command *cmd = cmd_queue; cmd; cmd = cmd->next) { /* fill the write buffer with the desired command */ ftdi_execute_command(cmd); } @@ -746,13 +736,8 @@ static int ftdi_initialize(void) return ERROR_JTAG_INIT_FAILED; } - for (int i = 0; ftdi_vid[i] || ftdi_pid[i]; i++) { - mpsse_ctx = mpsse_open(&ftdi_vid[i], &ftdi_pid[i], ftdi_device_desc, + mpsse_ctx = mpsse_open(ftdi_vid, ftdi_pid, ftdi_device_desc, adapter_get_required_serial(), adapter_usb_get_location(), ftdi_channel); - if (mpsse_ctx) - break; - } - if (!mpsse_ctx) return ERROR_JTAG_INIT_FAILED; @@ -1228,7 +1213,7 @@ COMMAND_HANDLER(ftdi_handle_set_signal_command) /* fallthrough */ default: LOG_ERROR("unknown signal level '%s', use 0, 1 or z", CMD_ARGV[1]); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } return mpsse_flush(mpsse_ctx); @@ -1288,22 +1273,22 @@ COMMAND_HANDLER(ftdi_handle_vid_pid_command) COMMAND_HANDLER(ftdi_handle_tdo_sample_edge_command) { - struct jim_nvp *n; - static const struct jim_nvp nvp_ftdi_jtag_modes[] = { + const struct nvp *n; + static const struct nvp nvp_ftdi_jtag_modes[] = { { .name = "rising", .value = JTAG_MODE }, { .name = "falling", .value = JTAG_MODE_ALT }, { .name = NULL, .value = -1 }, }; if (CMD_ARGC > 0) { - n = jim_nvp_name2value_simple(nvp_ftdi_jtag_modes, CMD_ARGV[0]); + n = nvp_name2value(nvp_ftdi_jtag_modes, CMD_ARGV[0]); if (!n->name) return ERROR_COMMAND_SYNTAX_ERROR; ftdi_jtag_mode = n->value; } - n = jim_nvp_value2name_simple(nvp_ftdi_jtag_modes, ftdi_jtag_mode); + n = nvp_value2name(nvp_ftdi_jtag_modes, ftdi_jtag_mode); command_print(CMD, "ftdi samples TDO on %s edge of TCK", n->name); return ERROR_OK; diff --git a/src/jtag/drivers/gw16012.c b/src/jtag/drivers/gw16012.c index db0a67715b..a4c6fd0f00 100644 --- a/src/jtag/drivers/gw16012.c +++ b/src/jtag/drivers/gw16012.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -281,9 +270,9 @@ static void gw16012_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int } } -static int gw16012_execute_queue(void) +static int gw16012_execute_queue(struct jtag_command *cmd_queue) { - struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ + struct jtag_command *cmd = cmd_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; diff --git a/src/jtag/drivers/imx_gpio.c b/src/jtag/drivers/imx_gpio.c index 39b463d313..d44b1278c0 100644 --- a/src/jtag/drivers/imx_gpio.c +++ b/src/jtag/drivers/imx_gpio.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2017 by Grzegorz Kostka, kostka.grzegorz@gmail.com * * * * Based on bcm2835gpio.c * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 5c218742b4..1874557dcd 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Juergen Stuber <juergen@jstuber.net> * * based on Dominic Rath's and Benedikt Sauter's usbprog.c * @@ -13,19 +15,6 @@ * * * Copyright (C) 2015 by Paul Fertser * * fercerpav@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -287,10 +276,10 @@ static int jlink_execute_command(struct jtag_command *cmd) return ERROR_OK; } -static int jlink_execute_queue(void) +static int jlink_execute_queue(struct jtag_command *cmd_queue) { int ret; - struct jtag_command *cmd = jtag_command_queue; + struct jtag_command *cmd = cmd_queue; while (cmd) { ret = jlink_execute_command(cmd); @@ -977,19 +966,17 @@ COMMAND_HANDLER(jlink_usb_command) { int tmp; - if (CMD_ARGC != 1) { - command_print(CMD, "Need exactly one argument for jlink usb"); + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - } if (sscanf(CMD_ARGV[0], "%i", &tmp) != 1) { command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]); - return ERROR_FAIL; + return ERROR_COMMAND_ARGUMENT_INVALID; } if (tmp < JAYLINK_USB_ADDRESS_0 || tmp > JAYLINK_USB_ADDRESS_3) { command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]); - return ERROR_FAIL; + return ERROR_COMMAND_ARGUMENT_INVALID; } usb_address = tmp; @@ -1070,7 +1057,7 @@ COMMAND_HANDLER(jlink_handle_jlink_jtag_command) } else if (CMD_ARGC == 1) { if (sscanf(CMD_ARGV[0], "%i", &tmp) != 1) { command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } switch (tmp) { @@ -1082,10 +1069,9 @@ COMMAND_HANDLER(jlink_handle_jlink_jtag_command) break; default: command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } } else { - command_print(CMD, "Need exactly one argument for jlink jtag"); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -1097,10 +1083,8 @@ COMMAND_HANDLER(jlink_handle_target_power_command) int ret; int enable; - if (CMD_ARGC != 1) { - command_print(CMD, "Need exactly one argument for jlink targetpower"); + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - } if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER)) { command_print(CMD, "Target power supply is not supported by the " @@ -1439,17 +1423,16 @@ COMMAND_HANDLER(jlink_handle_config_usb_address_command) } else if (CMD_ARGC == 1) { if (sscanf(CMD_ARGV[0], "%" SCNd8, &tmp) != 1) { command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]); - return ERROR_FAIL; + return ERROR_COMMAND_ARGUMENT_INVALID; } if (tmp > JAYLINK_USB_ADDRESS_3) { command_print(CMD, "Invalid USB address: %u", tmp); - return ERROR_FAIL; + return ERROR_COMMAND_ARGUMENT_INVALID; } tmp_config.usb_address = tmp; } else { - command_print(CMD, "Need exactly one argument for jlink config usb"); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -1481,13 +1464,11 @@ COMMAND_HANDLER(jlink_handle_config_target_power_command) enable = false; } else { command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); - return ERROR_FAIL; + return ERROR_COMMAND_ARGUMENT_INVALID; } tmp_config.target_power = enable; } else { - command_print(CMD, "Need exactly one argument for jlink config " - "targetpower"); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -1521,7 +1502,7 @@ COMMAND_HANDLER(jlink_handle_config_mac_address_command) if ((strlen(str) != 17) || (str[2] != ':' || str[5] != ':' || str[8] != ':' || str[11] != ':' || str[14] != ':')) { command_print(CMD, "Invalid MAC address format"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } for (i = 5; i >= 0; i--) { @@ -1531,17 +1512,16 @@ COMMAND_HANDLER(jlink_handle_config_mac_address_command) if (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) { command_print(CMD, "Invalid MAC address: zero address"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } if (!(0x01 & addr[0])) { command_print(CMD, "Invalid MAC address: multicast address"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } memcpy(tmp_config.mac_address, addr, sizeof(addr)); } else { - command_print(CMD, "Need exactly one argument for jlink config mac"); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -1603,20 +1583,26 @@ COMMAND_HANDLER(jlink_handle_config_ip_address_command) if (!CMD_ARGC) { show_config_ip_address(CMD); } else { - if (!string_to_ip(CMD_ARGV[0], ip_address, &i)) - return ERROR_COMMAND_SYNTAX_ERROR; + if (!string_to_ip(CMD_ARGV[0], ip_address, &i)) { + command_print(CMD, "invalid IPv4 address"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } len = strlen(CMD_ARGV[0]); /* Check for format A.B.C.D/E. */ if (i < len) { - if (CMD_ARGV[0][i] != '/') - return ERROR_COMMAND_SYNTAX_ERROR; + if (CMD_ARGV[0][i] != '/') { + command_print(CMD, "missing network mask"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0] + i + 1, subnet_bits); } else if (CMD_ARGC > 1) { - if (!string_to_ip(CMD_ARGV[1], (uint8_t *)&subnet_mask, &i)) - return ERROR_COMMAND_SYNTAX_ERROR; + if (!string_to_ip(CMD_ARGV[1], (uint8_t *)&subnet_mask, &i)) { + command_print(CMD, "invalid subnet mask"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } } if (!subnet_mask) @@ -1987,6 +1973,8 @@ struct pending_scan_result { void *buffer; /** Offset in the destination buffer */ unsigned buffer_offset; + /** SWD command */ + uint8_t swd_cmd; }; #define MAX_PENDING_SCAN_RESULTS 256 @@ -2120,7 +2108,7 @@ static int jlink_swd_switch_seq(enum swd_special_seq seq) switch (seq) { case LINE_RESET: - LOG_DEBUG("SWD line reset"); + LOG_DEBUG_IO("SWD line reset"); s = swd_seq_line_reset; s_len = swd_seq_line_reset_len; break; @@ -2169,7 +2157,7 @@ static int jlink_swd_run_queue(void) int i; int ret; - LOG_DEBUG("Executing %d queued transactions", pending_scan_results_length); + LOG_DEBUG_IO("Executing %d queued transactions", pending_scan_results_length); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); @@ -2190,12 +2178,13 @@ static int jlink_swd_run_queue(void) } for (i = 0; i < pending_scan_results_length; i++) { + /* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */ + bool check_ack = swd_cmd_returns_ack(pending_scan_results_buffer[i].swd_cmd); int ack = buf_get_u32(tdo_buffer, pending_scan_results_buffer[i].first, 3); - - if (ack != SWD_ACK_OK) { + if (check_ack && ack != SWD_ACK_OK) { LOG_DEBUG("SWD ack not OK: %d %s", ack, ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK"); - queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL; + queued_retval = swd_ack_to_error_code(ack); goto skip; } else if (pending_scan_results_buffer[i].length) { uint32_t data = buf_get_u32(tdo_buffer, 3 + pending_scan_results_buffer[i].first, 32); @@ -2232,6 +2221,7 @@ static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint3 if (queued_retval != ERROR_OK) return; + pending_scan_results_buffer[pending_scan_results_length].swd_cmd = cmd; cmd |= SWD_CMD_START | SWD_CMD_PARK; jlink_queue_data_out(&cmd, 8); diff --git a/src/jtag/drivers/jtag_dpi.c b/src/jtag/drivers/jtag_dpi.c index 016ff55366..285f96e4bf 100644 --- a/src/jtag/drivers/jtag_dpi.c +++ b/src/jtag/drivers/jtag_dpi.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * JTAG to DPI driver * @@ -7,19 +9,6 @@ * * See file CREDITS for list of people who contributed to this * project. - * - * 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/>. */ #ifdef HAVE_CONFIG_H @@ -233,12 +222,12 @@ static int jtag_dpi_stableclocks(int cycles) return jtag_dpi_runtest(cycles); } -static int jtag_dpi_execute_queue(void) +static int jtag_dpi_execute_queue(struct jtag_command *cmd_queue) { struct jtag_command *cmd; int ret = ERROR_OK; - for (cmd = jtag_command_queue; ret == ERROR_OK && cmd; + for (cmd = cmd_queue; ret == ERROR_OK && cmd; cmd = cmd->next) { switch (cmd->type) { case JTAG_RUNTEST: diff --git a/src/jtag/drivers/jtag_tcp.c b/src/jtag/drivers/jtag_tcp.c index 2b65d30543..8fe42bfea7 100644 --- a/src/jtag/drivers/jtag_tcp.c +++ b/src/jtag/drivers/jtag_tcp.c @@ -286,7 +286,7 @@ static int jtag_tcp_runtest(int num_cycles) } -int jtag_tcp_execute_queue(void) +int jtag_tcp_execute_queue(struct jtag_command *cmd_queue) { struct jtag_command *cmd; int retval = ERROR_OK; @@ -294,7 +294,7 @@ int jtag_tcp_execute_queue(void) int scan_size; enum scan_type type; - for (cmd = jtag_command_queue; retval == ERROR_OK && cmd != NULL; + for (cmd = cmd_queue; retval == ERROR_OK && cmd != NULL; cmd = cmd->next) { switch (cmd->type) { case JTAG_RESET: @@ -343,7 +343,7 @@ int jtag_tcp_execute_queue(void) return ERROR_FAIL; } - for (cmd = jtag_command_queue; retval == ERROR_OK && cmd != NULL; + for (cmd = cmd_queue; retval == ERROR_OK && cmd != NULL; cmd = cmd->next) { switch (cmd->type) { break; diff --git a/src/jtag/drivers/jtag_vpi.c b/src/jtag/drivers/jtag_vpi.c index eb53a5b06d..9dec0d19df 100644 --- a/src/jtag/drivers/jtag_vpi.c +++ b/src/jtag/drivers/jtag_vpi.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * JTAG to VPI driver * @@ -5,19 +7,6 @@ * * See file CREDITS for list of people who contributed to this * project. - * - * 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/>. */ #ifdef HAVE_CONFIG_H @@ -491,12 +480,12 @@ static int jtag_vpi_stableclocks(int cycles) return ERROR_OK; } -static int jtag_vpi_execute_queue(void) +static int jtag_vpi_execute_queue(struct jtag_command *cmd_queue) { struct jtag_command *cmd; int retval = ERROR_OK; - for (cmd = jtag_command_queue; retval == ERROR_OK && cmd; + for (cmd = cmd_queue; retval == ERROR_OK && cmd; cmd = cmd->next) { switch (cmd->type) { case JTAG_RESET: @@ -604,10 +593,8 @@ static int jtag_vpi_quit(void) COMMAND_HANDLER(jtag_vpi_set_port) { - if (CMD_ARGC == 0) { - LOG_ERROR("Command \"jtag_vpi set_port\" expects 1 argument (TCP port number)"); + if (CMD_ARGC == 0) return ERROR_COMMAND_SYNTAX_ERROR; - } COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], server_port); LOG_INFO("jtag_vpi: server port set to %u", server_port); @@ -618,10 +605,8 @@ COMMAND_HANDLER(jtag_vpi_set_port) COMMAND_HANDLER(jtag_vpi_set_address) { - if (CMD_ARGC == 0) { - LOG_ERROR("Command \"jtag_vpi set_address\" expects 1 argument (IP address)"); + if (CMD_ARGC == 0) return ERROR_COMMAND_SYNTAX_ERROR; - } free(server_address); server_address = strdup(CMD_ARGV[0]); @@ -632,10 +617,8 @@ COMMAND_HANDLER(jtag_vpi_set_address) COMMAND_HANDLER(jtag_vpi_stop_sim_on_exit_handler) { - if (CMD_ARGC != 1) { - LOG_ERROR("Command \"jtag_vpi stop_sim_on_exit\" expects 1 argument (on|off)"); + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - } COMMAND_PARSE_ON_OFF(CMD_ARGV[0], stop_sim_on_exit); return ERROR_OK; diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index 5e2168eea5..c0d2adc100 100644 --- a/src/jtag/drivers/kitprog.c +++ b/src/jtag/drivers/kitprog.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Juergen Stuber <juergen@jstuber.net> * * based on Dominic Rath's and Benedikt Sauter's usbprog.c * @@ -16,19 +18,6 @@ * * * Copyright (C) 2015-2017 by Forest Crossman * * cyrozap@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -90,8 +79,24 @@ #define HID_COMMAND_CONFIGURE 0x8f #define HID_COMMAND_BOOTLOADER 0xa0 -/* 512 bytes seems to work reliably */ -#define SWD_MAX_BUFFER_LENGTH 512 +/* 512 bytes seemed to work reliably. + * It works with both full queue of mostly reads or mostly writes. + * + * Unfortunately the commit 88f429ead019fd6df96ec15f0d897385f3cef0d0 + * 5321: target/cortex_m: faster reading of all CPU registers + * revealed a serious Kitprog firmware problem: + * If the queue contains more than 63 transactions in the repeated pattern + * one write, two reads, the firmware fails badly. + * Sending 64 transactions makes the adapter to loose the connection with the + * device. Sending 65 or more transactions causes the adapter to stop + * receiving USB HID commands, next kitprog_hid_command() stops in hid_write(). + * + * The problem was detected with KitProg v2.12 and v2.16. + * We can guess the problem is something like a buffer or stack overflow. + * + * Use shorter buffer as a workaround. 300 bytes (= 60 transactions) works. + */ +#define SWD_MAX_BUFFER_LENGTH 300 struct kitprog { hid_device *hid_handle; @@ -270,7 +275,7 @@ static int kitprog_usb_open(void) const uint16_t vids[] = { VID, 0 }; const uint16_t pids[] = { PID, 0 }; - if (jtag_libusb_open(vids, pids, &kitprog_handle->usb_handle, NULL) != ERROR_OK) { + if (jtag_libusb_open(vids, pids, NULL, &kitprog_handle->usb_handle, NULL) != ERROR_OK) { LOG_ERROR("Failed to open or find the device"); return ERROR_FAIL; } @@ -332,9 +337,13 @@ static int kitprog_hid_command(uint8_t *command, size_t command_length, return ERROR_FAIL; } - ret = hid_read(kitprog_handle->hid_handle, data, data_length); - if (ret < 0) { - LOG_DEBUG("HID read returned %i", ret); + ret = hid_read_timeout(kitprog_handle->hid_handle, + data, data_length, LIBUSB_TIMEOUT_MS); + if (ret == 0) { + LOG_ERROR("HID read timed out"); + return ERROR_TIMEOUT_REACHED; + } else if (ret < 0) { + LOG_ERROR("HID read error %ls", hid_error(kitprog_handle->hid_handle)); return ERROR_FAIL; } @@ -405,13 +414,13 @@ static int kitprog_set_protocol(uint8_t protocol) int transferred; char status = PROGRAMMER_NOK_NACK; - transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (CONTROL_MODE_SET_PROGRAMMER_PROTOCOL << 8) | CONTROL_COMMAND_PROGRAM, - protocol, &status, 1, 0); + protocol, &status, 1, 0, &transferred); - if (transferred == 0) { + if (retval != ERROR_OK || transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } @@ -431,11 +440,11 @@ static int kitprog_get_status(void) /* Try a maximum of three times */ for (int i = 0; (i < 3) && (transferred == 0); i++) { - transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_READ, (CONTROL_MODE_POLL_PROGRAMMER_STATUS << 8) | CONTROL_COMMAND_PROGRAM, - 0, &status, 1, 0); + 0, &status, 1, 0, &transferred); jtag_sleep(1000); } @@ -457,13 +466,13 @@ static int kitprog_set_unknown(void) int transferred; char status = PROGRAMMER_NOK_NACK; - transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (0x03 << 8) | 0x04, - 0, &status, 1, 0); + 0, &status, 1, 0, &transferred); - if (transferred == 0) { + if (retval != ERROR_OK || transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } @@ -482,13 +491,13 @@ static int kitprog_acquire_psoc(uint8_t psoc_type, uint8_t acquire_mode, int transferred; char status = PROGRAMMER_NOK_NACK; - transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (CONTROL_MODE_ACQUIRE_SWD_TARGET << 8) | CONTROL_COMMAND_PROGRAM, - (max_attempts << 8) | (acquire_mode << 4) | psoc_type, &status, 1, 0); + (max_attempts << 8) | (acquire_mode << 4) | psoc_type, &status, 1, 0, &transferred); - if (transferred == 0) { + if (retval != ERROR_OK || transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } @@ -506,13 +515,13 @@ static int kitprog_reset_target(void) int transferred; char status = PROGRAMMER_NOK_NACK; - transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (CONTROL_MODE_RESET_TARGET << 8) | CONTROL_COMMAND_PROGRAM, - 0, &status, 1, 0); + 0, &status, 1, 0, &transferred); - if (transferred == 0) { + if (retval != ERROR_OK || transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } @@ -530,13 +539,13 @@ static int kitprog_swd_sync(void) int transferred; char status = PROGRAMMER_NOK_NACK; - transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (CONTROL_MODE_SYNCHRONIZE_TRANSFER << 8) | CONTROL_COMMAND_PROGRAM, - 0, &status, 1, 0); + 0, &status, 1, 0, &transferred); - if (transferred == 0) { + if (retval != ERROR_OK || transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } @@ -554,13 +563,13 @@ static int kitprog_swd_seq(uint8_t seq_type) int transferred; char status = PROGRAMMER_NOK_NACK; - transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle, + int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, CONTROL_TYPE_WRITE, (CONTROL_MODE_SEND_SWD_SEQUENCE << 8) | CONTROL_COMMAND_PROGRAM, - seq_type, &status, 1, 0); + seq_type, &status, 1, 0, &transferred); - if (transferred == 0) { + if (retval != ERROR_OK || transferred == 0) { LOG_DEBUG("Zero bytes transferred"); return ERROR_FAIL; } @@ -870,6 +879,13 @@ static const struct command_registration kitprog_subcommand_handlers[] = { .usage = "", .help = "try to acquire a PSoC", }, + { + .name = "init_acquire_psoc", + .handler = &kitprog_handle_init_acquire_psoc_command, + .mode = COMMAND_CONFIG, + .help = "try to acquire a PSoC during init", + .usage = "", + }, COMMAND_REGISTRATION_DONE }; @@ -881,13 +897,6 @@ static const struct command_registration kitprog_command_handlers[] = { .usage = "<cmd>", .chain = kitprog_subcommand_handlers, }, - { - .name = "kitprog_init_acquire_psoc", - .handler = &kitprog_handle_init_acquire_psoc_command, - .mode = COMMAND_CONFIG, - .help = "try to acquire a PSoC during init", - .usage = "", - }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/drivers/libjaylink b/src/jtag/drivers/libjaylink index 9aa7a5957c..0d23921a05 160000 --- a/src/jtag/drivers/libjaylink +++ b/src/jtag/drivers/libjaylink @@ -1 +1 @@ -Subproject commit 9aa7a5957c07bb6e862fc1a6d3153d109c7407e4 +Subproject commit 0d23921a05d5d427332a142d154c213d0c306eb1 diff --git a/src/jtag/drivers/libusb_helper.c b/src/jtag/drivers/libusb_helper.c index fc961cb915..57ea8cd3fa 100644 --- a/src/jtag/drivers/libusb_helper.c +++ b/src/jtag/drivers/libusb_helper.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> * * * * Copyright (C) 2011 by Mauro Gamba <maurillo71@gmail.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -61,7 +50,7 @@ static int jtag_libusb_error(int err) } } -static bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc, +bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc, const uint16_t vids[], const uint16_t pids[]) { for (unsigned i = 0; vids[i]; i++) { @@ -157,12 +146,13 @@ static bool jtag_libusb_match_serial(struct libusb_device_handle *device, } int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], - struct libusb_device_handle **out, + const char *product, struct libusb_device_handle **out, adapter_get_alternate_serial_fn adapter_get_alternate_serial) { int cnt, idx, err_code; int retval = ERROR_FAIL; bool serial_mismatch = false; + bool product_mismatch = false; struct libusb_device_handle *libusb_handle = NULL; const char *serial = adapter_get_required_serial(); @@ -199,10 +189,18 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], continue; } + if (product && + !string_descriptor_equal(libusb_handle, dev_desc.iProduct, product)) { + product_mismatch = true; + libusb_close(libusb_handle); + continue; + } + /* Success. */ *out = libusb_handle; retval = ERROR_OK; serial_mismatch = false; + product_mismatch = false; break; } if (cnt >= 0) @@ -211,6 +209,9 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], if (serial_mismatch) LOG_INFO("No device matches the serial string"); + if (product_mismatch) + LOG_INFO("No device matches the product string"); + if (retval != ERROR_OK) libusb_exit(jtag_libusb_context); @@ -227,17 +228,22 @@ void jtag_libusb_close(struct libusb_device_handle *dev) int jtag_libusb_control_transfer(struct libusb_device_handle *dev, uint8_t request_type, uint8_t request, uint16_t value, uint16_t index, char *bytes, - uint16_t size, unsigned int timeout) + uint16_t size, unsigned int timeout, int *transferred) { - int transferred = 0; - - transferred = libusb_control_transfer(dev, request_type, request, value, index, + int retval = libusb_control_transfer(dev, request_type, request, value, index, (unsigned char *)bytes, size, timeout); - if (transferred < 0) - transferred = 0; + if (retval < 0) { + LOG_ERROR("libusb_control_transfer error: %s", libusb_error_name(retval)); + if (transferred) + *transferred = 0; + return jtag_libusb_error(retval); + } + + if (transferred) + *transferred = retval; - return transferred; + return ERROR_OK; } int jtag_libusb_bulk_write(struct libusb_device_handle *dev, int ep, char *bytes, @@ -371,3 +377,59 @@ int jtag_libusb_handle_events_completed(int *completed) { return libusb_handle_events_completed(jtag_libusb_context, completed); } + +static enum { + DEV_MEM_NOT_YET_DECIDED, + DEV_MEM_AVAILABLE, + DEV_MEM_FALLBACK_MALLOC +} dev_mem_allocation; + +/* Older libusb does not implement following API calls - define stubs instead */ +#if !defined(LIBUSB_API_VERSION) || (LIBUSB_API_VERSION < 0x01000105) +static uint8_t *libusb_dev_mem_alloc(libusb_device_handle *devh, size_t length) +{ + return NULL; +} + +static int libusb_dev_mem_free(libusb_device_handle *devh, + uint8_t *buffer, size_t length) +{ + return LIBUSB_ERROR_NOT_SUPPORTED; +} +#endif + +uint8_t *oocd_libusb_dev_mem_alloc(libusb_device_handle *devh, + size_t length) +{ + uint8_t *buffer = NULL; + if (dev_mem_allocation != DEV_MEM_FALLBACK_MALLOC) + buffer = libusb_dev_mem_alloc(devh, length); + + if (dev_mem_allocation == DEV_MEM_NOT_YET_DECIDED) + dev_mem_allocation = buffer ? DEV_MEM_AVAILABLE : DEV_MEM_FALLBACK_MALLOC; + + if (dev_mem_allocation == DEV_MEM_FALLBACK_MALLOC) + buffer = malloc(length); + + return buffer; +} + +int oocd_libusb_dev_mem_free(libusb_device_handle *devh, + uint8_t *buffer, size_t length) +{ + if (!buffer) + return ERROR_OK; + + switch (dev_mem_allocation) { + case DEV_MEM_AVAILABLE: + return jtag_libusb_error(libusb_dev_mem_free(devh, buffer, length)); + + case DEV_MEM_FALLBACK_MALLOC: + free(buffer); + return ERROR_OK; + + case DEV_MEM_NOT_YET_DECIDED: + return ERROR_FAIL; + } + return ERROR_FAIL; +} diff --git a/src/jtag/drivers/libusb_helper.h b/src/jtag/drivers/libusb_helper.h index 9d51464a7f..3cd83c6b38 100644 --- a/src/jtag/drivers/libusb_helper.h +++ b/src/jtag/drivers/libusb_helper.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> * * * * Copyright (C) 2011 by Mauro Gamba <maurillo71@gmail.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_LIBUSB_HELPER_H @@ -41,13 +30,16 @@ typedef char * (*adapter_get_alternate_serial_fn)(struct libusb_device_handle *device, struct libusb_device_descriptor *dev_desc); +bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc, + const uint16_t vids[], const uint16_t pids[]); int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], - struct libusb_device_handle **out, + const char *product, struct libusb_device_handle **out, adapter_get_alternate_serial_fn adapter_get_alternate_serial); void jtag_libusb_close(struct libusb_device_handle *dev); int jtag_libusb_control_transfer(struct libusb_device_handle *dev, uint8_t request_type, uint8_t request, uint16_t value, - uint16_t index, char *bytes, uint16_t size, unsigned int timeout); + uint16_t index, char *bytes, uint16_t size, unsigned int timeout, + int *transferred); int jtag_libusb_bulk_write(struct libusb_device_handle *dev, int ep, char *bytes, int size, int timeout, int *transferred); int jtag_libusb_bulk_read(struct libusb_device_handle *dev, int ep, @@ -75,4 +67,27 @@ int jtag_libusb_choose_interface(struct libusb_device_handle *devh, int jtag_libusb_get_pid(struct libusb_device *dev, uint16_t *pid); int jtag_libusb_handle_events_completed(int *completed); +/** + * Attempts to allocate a block of persistent DMA memory suitable for transfers + * against the USB device. Fall-back to the ordinary heap malloc() + * if the first libusb_dev_mem_alloc() call fails. + * @param devh _libusb_ device handle. + * @param length size of desired data buffer + * @returns a pointer to the newly allocated memory, or NULL on failure + */ +uint8_t *oocd_libusb_dev_mem_alloc(libusb_device_handle *devh, + size_t length); + +/** + * Free device memory allocated with oocd_libusb_dev_mem_alloc(). + * Uses either libusb_dev_mem_free() or free() consistently with + * the used method of allocation. + * @param devh _libusb_ device handle. + * @param buffer pointer to the previously allocated memory + * @param length size of desired data buffer + * @returns Returns ERROR_OK on success, ERROR_FAIL otherwise. + */ +int oocd_libusb_dev_mem_free(libusb_device_handle *devh, + uint8_t *buffer, size_t length); + #endif /* OPENOCD_JTAG_DRIVERS_LIBUSB_HELPER_H */ diff --git a/src/jtag/drivers/linuxgpiod.c b/src/jtag/drivers/linuxgpiod.c index 288035f2e0..9428837883 100644 --- a/src/jtag/drivers/linuxgpiod.c +++ b/src/jtag/drivers/linuxgpiod.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Bitbang driver for Linux GPIO descriptors through libgpiod * Copyright (C) 2020 Antonio Borneo <borneo.antonio@gmail.com> @@ -14,67 +14,39 @@ #endif #include <gpiod.h> +#include <jtag/adapter.h> #include <jtag/interface.h> #include <transport/transport.h> #include "bitbang.h" -/* gpio numbers for each gpio. Negative values are invalid */ -static int tck_gpio = -1; -static int tms_gpio = -1; -static int tdi_gpio = -1; -static int tdo_gpio = -1; -static int trst_gpio = -1; -static int srst_gpio = -1; -static int swclk_gpio = -1; -static int swdio_gpio = -1; -static int swdio_dir_gpio = -1; -static int led_gpio = -1; -static int gpiochip = -1; -static int tck_gpiochip = -1; -static int tms_gpiochip = -1; -static int tdi_gpiochip = -1; -static int tdo_gpiochip = -1; -static int trst_gpiochip = -1; -static int srst_gpiochip = -1; -static int swclk_gpiochip = -1; -static int swdio_gpiochip = -1; -static int swdio_dir_gpiochip = -1; -static int led_gpiochip = -1; - -static struct gpiod_chip *gpiod_chip_tck; -static struct gpiod_chip *gpiod_chip_tms; -static struct gpiod_chip *gpiod_chip_tdi; -static struct gpiod_chip *gpiod_chip_tdo; -static struct gpiod_chip *gpiod_chip_trst; -static struct gpiod_chip *gpiod_chip_srst; -static struct gpiod_chip *gpiod_chip_swclk; -static struct gpiod_chip *gpiod_chip_swdio; -static struct gpiod_chip *gpiod_chip_swdio_dir; -static struct gpiod_chip *gpiod_chip_led; - -static struct gpiod_line *gpiod_tck; -static struct gpiod_line *gpiod_tms; -static struct gpiod_line *gpiod_tdi; -static struct gpiod_line *gpiod_tdo; -static struct gpiod_line *gpiod_trst; -static struct gpiod_line *gpiod_swclk; -static struct gpiod_line *gpiod_swdio; -static struct gpiod_line *gpiod_swdio_dir; -static struct gpiod_line *gpiod_srst; -static struct gpiod_line *gpiod_led; +static struct gpiod_chip *gpiod_chip[ADAPTER_GPIO_IDX_NUM] = {}; +static struct gpiod_line *gpiod_line[ADAPTER_GPIO_IDX_NUM] = {}; static int last_swclk; static int last_swdio; static bool last_stored; static bool swdio_input; -static bool swdio_dir_is_active_high = true; + +static const struct adapter_gpio_config *adapter_gpio_config; + +/* + * Helper function to determine if gpio config is valid + * + * Assume here that there will be less than 10000 gpios per gpiochip, and less + * than 1000 gpiochips. + */ +static bool is_gpio_config_valid(enum adapter_gpio_config_index idx) +{ + return adapter_gpio_config[idx].chip_num < 1000 + && adapter_gpio_config[idx].gpio_num < 10000; +} /* Bitbang interface read of TDO */ static bb_value_t linuxgpiod_read(void) { int retval; - retval = gpiod_line_get_value(gpiod_tdo); + retval = gpiod_line_get_value(gpiod_line[ADAPTER_GPIO_IDX_TDO]); if (retval < 0) { LOG_WARNING("reading tdo failed"); return 0; @@ -107,20 +79,20 @@ static int linuxgpiod_write(int tck, int tms, int tdi) } if (tdi != last_tdi) { - retval = gpiod_line_set_value(gpiod_tdi, tdi); + retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_TDI], tdi); if (retval < 0) LOG_WARNING("writing tdi failed"); } if (tms != last_tms) { - retval = gpiod_line_set_value(gpiod_tms, tms); + retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_TMS], tms); if (retval < 0) LOG_WARNING("writing tms failed"); } /* write clk last */ if (tck != last_tck) { - retval = gpiod_line_set_value(gpiod_tck, tck); + retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_TCK], tck); if (retval < 0) LOG_WARNING("writing tck failed"); } @@ -136,7 +108,7 @@ static int linuxgpiod_swdio_read(void) { int retval; - retval = gpiod_line_get_value(gpiod_swdio); + retval = gpiod_line_get_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO]); if (retval < 0) { LOG_WARNING("Fail read swdio"); return 0; @@ -154,23 +126,23 @@ static void linuxgpiod_swdio_drive(bool is_output) * https://stackoverflow.com/questions/58735140/ * this would change in future libgpiod */ - gpiod_line_release(gpiod_swdio); + gpiod_line_release(gpiod_line[ADAPTER_GPIO_IDX_SWDIO]); if (is_output) { - if (gpiod_swdio_dir) { - retval = gpiod_line_set_value(gpiod_swdio_dir, swdio_dir_is_active_high ? 1 : 0); + if (gpiod_line[ADAPTER_GPIO_IDX_SWDIO_DIR]) { + retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO_DIR], 1); if (retval < 0) LOG_WARNING("Fail set swdio_dir"); } - retval = gpiod_line_request_output(gpiod_swdio, "OpenOCD", 1); + retval = gpiod_line_request_output(gpiod_line[ADAPTER_GPIO_IDX_SWDIO], "OpenOCD", 1); if (retval < 0) LOG_WARNING("Fail request_output line swdio"); } else { - retval = gpiod_line_request_input(gpiod_swdio, "OpenOCD"); + retval = gpiod_line_request_input(gpiod_line[ADAPTER_GPIO_IDX_SWDIO], "OpenOCD"); if (retval < 0) LOG_WARNING("Fail request_input line swdio"); - if (gpiod_swdio_dir) { - retval = gpiod_line_set_value(gpiod_swdio_dir, swdio_dir_is_active_high ? 0 : 1); + if (gpiod_line[ADAPTER_GPIO_IDX_SWDIO_DIR]) { + retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO_DIR], 0); if (retval < 0) LOG_WARNING("Fail set swdio_dir"); } @@ -186,7 +158,7 @@ static int linuxgpiod_swd_write(int swclk, int swdio) if (!swdio_input) { if (!last_stored || (swdio != last_swdio)) { - retval = gpiod_line_set_value(gpiod_swdio, swdio); + retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO], swdio); if (retval < 0) LOG_WARNING("Fail set swdio"); } @@ -194,7 +166,7 @@ static int linuxgpiod_swd_write(int swclk, int swdio) /* write swclk last */ if (!last_stored || (swclk != last_swclk)) { - retval = gpiod_line_set_value(gpiod_swclk, swclk); + retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWCLK], swclk); if (retval < 0) LOG_WARNING("Fail set swclk"); } @@ -210,10 +182,10 @@ static int linuxgpiod_blink(int on) { int retval; - if (!gpiod_led) + if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_LED)) return ERROR_OK; - retval = gpiod_line_set_value(gpiod_led, on); + retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_LED], on); if (retval < 0) LOG_WARNING("Fail set led"); return retval; @@ -239,16 +211,18 @@ static int linuxgpiod_reset(int trst, int srst) LOG_DEBUG("linuxgpiod_reset"); - /* assume active low */ - if (gpiod_srst) { - retval1 = gpiod_line_set_value(gpiod_srst, srst ? 0 : 1); + /* + * active low behaviour handled by "adaptor gpio" command and + * GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW flag when requesting the line. + */ + if (gpiod_line[ADAPTER_GPIO_IDX_SRST]) { + retval1 = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SRST], srst); if (retval1 < 0) LOG_WARNING("set srst value failed"); } - /* assume active low */ - if (gpiod_trst) { - retval2 = gpiod_line_set_value(gpiod_trst, trst ? 0 : 1); + if (gpiod_line[ADAPTER_GPIO_IDX_TRST]) { + retval2 = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_TRST], trst); if (retval2 < 0) LOG_WARNING("set trst value failed"); } @@ -256,127 +230,134 @@ static int linuxgpiod_reset(int trst, int srst) return ((retval1 < 0) || (retval2 < 0)) ? ERROR_FAIL : ERROR_OK; } -/* - * Helper function to determine if gpio number is valid - * - * Assume here that there will be less than 10000 gpios per gpiochip - */ -static bool is_gpio_valid(int gpio) -{ - return gpio >= 0 && gpio < 10000; -} - static bool linuxgpiod_jtag_mode_possible(void) { - if (!is_gpio_valid(tck_gpio)) + if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TCK)) return false; - if (!is_gpio_valid(tms_gpio)) + if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TMS)) return false; - if (!is_gpio_valid(tdi_gpio)) + if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TDI)) return false; - if (!is_gpio_valid(tdo_gpio)) + if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_TDO)) return false; return true; } static bool linuxgpiod_swd_mode_possible(void) { - if (!is_gpio_valid(swclk_gpio)) + if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_SWCLK)) return false; - if (!is_gpio_valid(swdio_gpio)) + if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO)) return false; return true; } -static inline void helper_release(struct gpiod_line *line) +static inline void helper_release(enum adapter_gpio_config_index idx) { - if (line) - gpiod_line_release(line); + if (gpiod_line[idx]) { + gpiod_line_release(gpiod_line[idx]); + gpiod_line[idx] = NULL; + } + if (gpiod_chip[idx]) { + gpiod_chip_close(gpiod_chip[idx]); + gpiod_chip[idx] = NULL; + } } static int linuxgpiod_quit(void) { - helper_release(gpiod_led); - helper_release(gpiod_srst); - helper_release(gpiod_swdio); - helper_release(gpiod_swclk); - helper_release(gpiod_trst); - helper_release(gpiod_tms); - helper_release(gpiod_tck); - helper_release(gpiod_tdi); - helper_release(gpiod_tdo); - - if (gpiod_chip_led != NULL) - gpiod_chip_close(gpiod_chip_led); - if (gpiod_chip_srst != NULL) - gpiod_chip_close(gpiod_chip_srst); - if (gpiod_chip_swdio != NULL) - gpiod_chip_close(gpiod_chip_swdio); - if (gpiod_chip_swdio_dir != NULL) - gpiod_chip_close(gpiod_chip_swdio_dir); - if (gpiod_chip_swclk != NULL) - gpiod_chip_close(gpiod_chip_swclk); - if (gpiod_chip_trst != NULL) - gpiod_chip_close(gpiod_chip_trst); - if (gpiod_chip_tms != NULL) - gpiod_chip_close(gpiod_chip_tms); - if (gpiod_chip_tck != NULL) - gpiod_chip_close(gpiod_chip_tck); - if (gpiod_chip_tdi != NULL) - gpiod_chip_close(gpiod_chip_tdi); - if (gpiod_chip_tdo != NULL) - gpiod_chip_close(gpiod_chip_tdo); + LOG_DEBUG("linuxgpiod_quit"); + for (int i = 0; i < ADAPTER_GPIO_IDX_NUM; ++i) + helper_release(i); return ERROR_OK; } -static struct gpiod_line *helper_get_line(const char *label, - struct gpiod_chip *gpiod_chip, unsigned int offset, - int val, int dir, int flags) +static int helper_get_line(enum adapter_gpio_config_index idx) { - struct gpiod_line *line; - int retval; + if (!is_gpio_config_valid(idx)) + return ERROR_OK; + + int dir = GPIOD_LINE_REQUEST_DIRECTION_INPUT, flags = 0, val = 0, retval; + + gpiod_chip[idx] = gpiod_chip_open_by_number(adapter_gpio_config[idx].chip_num); + if (!gpiod_chip[idx]) { + LOG_ERROR("Cannot open LinuxGPIOD chip %d for %s", adapter_gpio_config[idx].chip_num, + adapter_gpio_get_name(idx)); + return ERROR_JTAG_INIT_FAILED; + } + + gpiod_line[idx] = gpiod_chip_get_line(gpiod_chip[idx], adapter_gpio_config[idx].gpio_num); + if (!gpiod_line[idx]) { + LOG_ERROR("Error get line %s", adapter_gpio_get_name(idx)); + return ERROR_JTAG_INIT_FAILED; + } + + switch (adapter_gpio_config[idx].init_state) { + case ADAPTER_GPIO_INIT_STATE_INPUT: + dir = GPIOD_LINE_REQUEST_DIRECTION_INPUT; + break; + case ADAPTER_GPIO_INIT_STATE_INACTIVE: + dir = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT; + val = 0; + break; + case ADAPTER_GPIO_INIT_STATE_ACTIVE: + dir = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT; + val = 1; + break; + } + + switch (adapter_gpio_config[idx].drive) { + case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL: + break; + case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN: + flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN; + break; + case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE: + flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE; + break; + } - line = gpiod_chip_get_line(gpiod_chip, offset); - if (!line) { - LOG_ERROR("Error get line %s", label); - return NULL; + switch (adapter_gpio_config[idx].pull) { + case ADAPTER_GPIO_PULL_NONE: +#ifdef GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE + flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE; +#endif + break; + case ADAPTER_GPIO_PULL_UP: +#ifdef GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP + flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP; +#else + LOG_WARNING("linuxgpiod: ignoring request for pull-up on %s: not supported by gpiod v%s", + adapter_gpio_get_name(idx), gpiod_version_string()); +#endif + break; + case ADAPTER_GPIO_PULL_DOWN: +#ifdef GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN + flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN; +#else + LOG_WARNING("linuxgpiod: ignoring request for pull-down on %s: not supported by gpiod v%s", + adapter_gpio_get_name(idx), gpiod_version_string()); +#endif + break; } + if (adapter_gpio_config[idx].active_low) + flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; + struct gpiod_line_request_config config = { .consumer = "OpenOCD", .request_type = dir, .flags = flags, }; - retval = gpiod_line_request(line, &config, val); + retval = gpiod_line_request(gpiod_line[idx], &config, val); if (retval < 0) { - LOG_ERROR("Error requesting gpio line %s", label); - return NULL; + LOG_ERROR("Error requesting gpio line %s", adapter_gpio_get_name(idx)); + return ERROR_JTAG_INIT_FAILED; } - return line; -} - -static struct gpiod_line *helper_get_input_line(const char *label, - struct gpiod_chip *gpiod_chip, unsigned int offset) -{ - return helper_get_line(label, gpiod_chip, offset, 0, - GPIOD_LINE_REQUEST_DIRECTION_INPUT, 0); -} - -static struct gpiod_line *helper_get_output_line(const char *label, - struct gpiod_chip *gpiod_chip, unsigned int offset, int val) -{ - return helper_get_line(label, gpiod_chip, offset, val, - GPIOD_LINE_REQUEST_DIRECTION_OUTPUT, 0); -} - -static struct gpiod_line *helper_get_open_drain_output_line(const char *label, - struct gpiod_chip *gpiod_chip, unsigned int offset, int val) -{ - return helper_get_line(label, gpiod_chip, offset, val, - GPIOD_LINE_REQUEST_DIRECTION_OUTPUT, GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN); + return ERROR_OK; } static int linuxgpiod_init(void) @@ -384,11 +365,11 @@ static int linuxgpiod_init(void) LOG_INFO("Linux GPIOD JTAG/SWD bitbang driver"); bitbang_interface = &linuxgpiod_bitbang; + adapter_gpio_config = adapter_gpio_get_config(); /* - * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST - * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. - * For SWD, SWCLK and SWDIO are configures as output high. + * Configure JTAG/SWD signals. Default directions and initial states are handled + * by adapter.c and "adapter gpio" command. */ if (transport_is_jtag()) { @@ -397,129 +378,44 @@ static int linuxgpiod_init(void) goto out_error; } - gpiod_chip_tdo = gpiod_chip_open_by_number(tdo_gpiochip); - if (!gpiod_chip_tdo) { - LOG_ERROR("Cannot open LinuxGPIOD tdo_gpiochip %d", tdo_gpiochip); - goto out_error; - } - gpiod_chip_tdi = gpiod_chip_open_by_number(tdi_gpiochip); - if (!gpiod_chip_tdi) { - LOG_ERROR("Cannot open LinuxGPIOD tdi_gpiochip %d", tdi_gpiochip); - goto out_error; - } - gpiod_chip_tck = gpiod_chip_open_by_number(tck_gpiochip); - if (!gpiod_chip_tck) { - LOG_ERROR("Cannot open LinuxGPIOD tck_gpiochip %d", tck_gpiochip); - goto out_error; - } - gpiod_chip_tms = gpiod_chip_open_by_number(tms_gpiochip); - if (!gpiod_chip_tms) { - LOG_ERROR("Cannot open LinuxGPIOD tms_gpiochip %d", tms_gpiochip); - goto out_error; - } - - gpiod_tdo = helper_get_input_line("tdo", gpiod_chip_tdo, tdo_gpio); - if (!gpiod_tdo) - goto out_error; - - gpiod_tdi = helper_get_output_line("tdi", gpiod_chip_tdi, tdi_gpio, 0); - if (!gpiod_tdi) - goto out_error; - - gpiod_tck = helper_get_output_line("tck", gpiod_chip_tck, tck_gpio, 0); - if (!gpiod_tck) - goto out_error; - - gpiod_tms = helper_get_output_line("tms", gpiod_chip_tms, tms_gpio, 1); - if (!gpiod_tms) - goto out_error; - - if (is_gpio_valid(trst_gpio)) { - gpiod_chip_trst = gpiod_chip_open_by_number(trst_gpiochip); - if (!gpiod_chip_trst) { - LOG_ERROR("Cannot open LinuxGPIOD trst_gpiochip %d", trst_gpiochip); + if (helper_get_line(ADAPTER_GPIO_IDX_TDO) != ERROR_OK || + helper_get_line(ADAPTER_GPIO_IDX_TDI) != ERROR_OK || + helper_get_line(ADAPTER_GPIO_IDX_TCK) != ERROR_OK || + helper_get_line(ADAPTER_GPIO_IDX_TMS) != ERROR_OK || + helper_get_line(ADAPTER_GPIO_IDX_TRST) != ERROR_OK) goto out_error; - } - - if (jtag_get_reset_config() & RESET_TRST_OPEN_DRAIN) - gpiod_trst = helper_get_open_drain_output_line("trst", gpiod_chip_trst, trst_gpio, 1); - else - gpiod_trst = helper_get_output_line("trst", gpiod_chip_trst, trst_gpio, 1); - - if (!gpiod_trst) - goto out_error; - } } if (transport_is_swd()) { + int retval1, retval2; if (!linuxgpiod_swd_mode_possible()) { LOG_ERROR("Require swclk and swdio gpio for SWD mode"); goto out_error; } - gpiod_chip_swclk = gpiod_chip_open_by_number(swclk_gpiochip); - if (!gpiod_chip_swclk) { - LOG_ERROR("Cannot open LinuxGPIOD swclk_gpiochip %d", swclk_gpiochip); - goto out_error; + /* + * swdio and its buffer should be initialized in the order that prevents + * two outputs from being connected together. This will occur if the + * swdio GPIO is configured as an output while the external buffer is + * configured to send the swdio signal from the target to the GPIO. + */ + if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].init_state == ADAPTER_GPIO_INIT_STATE_INPUT) { + retval1 = helper_get_line(ADAPTER_GPIO_IDX_SWDIO); + retval2 = helper_get_line(ADAPTER_GPIO_IDX_SWDIO_DIR); + } else { + retval1 = helper_get_line(ADAPTER_GPIO_IDX_SWDIO_DIR); + retval2 = helper_get_line(ADAPTER_GPIO_IDX_SWDIO); } - gpiod_chip_swdio = gpiod_chip_open_by_number(swdio_gpiochip); - if (!gpiod_chip_swdio) { - LOG_ERROR("Cannot open LinuxGPIOD swdio_gpiochip %d", swdio_gpiochip); + if (retval1 != ERROR_OK || retval2 != ERROR_OK) goto out_error; - } - - if (is_gpio_valid(swdio_dir_gpio)) { - gpiod_chip_swdio_dir = gpiod_chip_open_by_number(swdio_dir_gpiochip); - if (!gpiod_chip_swdio_dir) { - LOG_ERROR("Cannot open LinuxGPIOD swdio_dir_gpiochip %d", swdio_dir_gpiochip); - goto out_error; - } - } - gpiod_swclk = helper_get_output_line("swclk", gpiod_chip_swclk, swclk_gpio, 1); - if (!gpiod_swclk) - goto out_error; - - /* Set buffer direction before making SWDIO an output */ - if (is_gpio_valid(swdio_dir_gpio)) { - gpiod_swdio_dir = helper_get_output_line("swdio_dir", gpiod_chip_swdio_dir, swdio_dir_gpio, - swdio_dir_is_active_high ? 1 : 0); - if (!gpiod_swdio_dir) - goto out_error; - } - - gpiod_swdio = helper_get_output_line("swdio", gpiod_chip_swdio, swdio_gpio, 1); - if (!gpiod_swdio) + if (helper_get_line(ADAPTER_GPIO_IDX_SWCLK) != ERROR_OK) goto out_error; } - if (is_gpio_valid(srst_gpio)) { - gpiod_chip_srst = gpiod_chip_open_by_number(srst_gpiochip); - if (!gpiod_chip_srst) { - LOG_ERROR("Cannot open LinuxGPIOD srst_gpiochip %d", srst_gpiochip); - goto out_error; - } - - if (jtag_get_reset_config() & RESET_SRST_PUSH_PULL) - gpiod_srst = helper_get_output_line("srst", gpiod_chip_srst, srst_gpio, 1); - else - gpiod_srst = helper_get_open_drain_output_line("srst", gpiod_chip_srst, srst_gpio, 1); - - if (!gpiod_srst) - goto out_error; - } - - if (is_gpio_valid(led_gpio)) { - gpiod_chip_led = gpiod_chip_open_by_number(led_gpiochip); - if (!gpiod_chip_led) { - LOG_ERROR("Cannot open LinuxGPIOD led_gpiochip %d", led_gpiochip); - goto out_error; - } - - gpiod_led = helper_get_output_line("led", gpiod_chip_led, led_gpio, 0); - if (!gpiod_led) + if (helper_get_line(ADAPTER_GPIO_IDX_SRST) != ERROR_OK || + helper_get_line(ADAPTER_GPIO_IDX_LED) != ERROR_OK) goto out_error; - } return ERROR_OK; @@ -529,241 +425,6 @@ static int linuxgpiod_init(void) return ERROR_JTAG_INIT_FAILED; } -COMMAND_HELPER(linuxgpiod_helper_gpionum, const char *name, int *chip, int *line) -{ - int i = 0; - if (CMD_ARGC > 2) - return ERROR_COMMAND_SYNTAX_ERROR; - if (CMD_ARGC == 2) { - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], *chip); - i = 1; - } - if (CMD_ARGC > 0) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[i], *line); - command_print(CMD, "LinuxGPIOD %s: chip = %d, num = %d", name, *chip, *line); - return ERROR_OK; -} - -COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionums) -{ - if (CMD_ARGC == 4) { - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio); - COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio); - COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio); - COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio); - } else if (CMD_ARGC != 0) { - return ERROR_COMMAND_SYNTAX_ERROR; - } - - command_print(CMD, - "LinuxGPIOD nums: tck = %d, tms = %d, tdi = %d, tdo = %d", - tck_gpio, tms_gpio, tdi_gpio, tdo_gpio); - - return ERROR_OK; -} - -COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tck) -{ - return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "tck", &tck_gpiochip, - &tck_gpio); -} - -COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tms) -{ - return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "tms", &tms_gpiochip, - &tms_gpio); -} - -COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tdo) -{ - return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "tdo", &tdo_gpiochip, - &tdo_gpio); -} - -COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_tdi) -{ - return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "tdi", &tdi_gpiochip, - &tdi_gpio); -} - -COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_srst) -{ - return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "srst", &srst_gpiochip, - &srst_gpio); -} - -COMMAND_HANDLER(linuxgpiod_handle_jtag_gpionum_trst) -{ - return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "trst", &trst_gpiochip, - &trst_gpio); -} - -COMMAND_HANDLER(linuxgpiod_handle_swd_gpionums) -{ - if (CMD_ARGC == 2) { - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio); - COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], swdio_gpio); - } else if (CMD_ARGC != 0) { - return ERROR_COMMAND_SYNTAX_ERROR; - } - - command_print(CMD, - "LinuxGPIOD nums: swclk = %d, swdio = %d", - swclk_gpio, swdio_gpio); - - return ERROR_OK; -} - -COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swclk) -{ - return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "swclk", &swclk_gpiochip, - &swclk_gpio); -} - -COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swdio) -{ - return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "swdio", &swdio_gpiochip, - &swdio_gpio); -} - -COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swdio_dir) -{ - return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "swdio_dir", &swdio_dir_gpiochip, - &swdio_dir_gpio); -} - -COMMAND_HANDLER(linuxgpiod_handle_gpionum_led) -{ - return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "led", &led_gpiochip, - &led_gpio); -} - -COMMAND_HANDLER(linuxgpiod_handle_gpiochip) -{ - if (CMD_ARGC == 1) { - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], gpiochip); - tck_gpiochip = gpiochip; - tms_gpiochip = gpiochip; - tdi_gpiochip = gpiochip; - tdo_gpiochip = gpiochip; - trst_gpiochip = gpiochip; - srst_gpiochip = gpiochip; - swclk_gpiochip = gpiochip; - swdio_gpiochip = gpiochip; - swdio_dir_gpiochip = gpiochip; - led_gpiochip = gpiochip; - } - - command_print(CMD, "LinuxGPIOD gpiochip = %d", gpiochip); - return ERROR_OK; -} - -static const struct command_registration linuxgpiod_subcommand_handlers[] = { - { - .name = "jtag_nums", - .handler = linuxgpiod_handle_jtag_gpionums, - .mode = COMMAND_CONFIG, - .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)", - .usage = "tck tms tdi tdo", - }, - { - .name = "tck_num", - .handler = linuxgpiod_handle_jtag_gpionum_tck, - .mode = COMMAND_CONFIG, - .help = "gpio chip number (optional) and gpio number for tck.", - .usage = "[chip] tck", - }, - { - .name = "tms_num", - .handler = linuxgpiod_handle_jtag_gpionum_tms, - .mode = COMMAND_CONFIG, - .help = "gpio chip number (optional) and gpio number for tms.", - .usage = "[chip] tms", - }, - { - .name = "tdo_num", - .handler = linuxgpiod_handle_jtag_gpionum_tdo, - .mode = COMMAND_CONFIG, - .help = "gpio chip number (optional) and gpio number for tdo.", - .usage = "[chip] tdo", - }, - { - .name = "tdi_num", - .handler = linuxgpiod_handle_jtag_gpionum_tdi, - .mode = COMMAND_CONFIG, - .help = "gpio chip number (optional) and gpio number for tdi.", - .usage = "[chip] tdi", - }, - { - .name = "srst_num", - .handler = linuxgpiod_handle_jtag_gpionum_srst, - .mode = COMMAND_CONFIG, - .help = "gpio chip number (optional) and gpio number for srst.", - .usage = "[chip] srst", - }, - { - .name = "trst_num", - .handler = linuxgpiod_handle_jtag_gpionum_trst, - .mode = COMMAND_CONFIG, - .help = "gpio chip number (optional) and gpio number for trst.", - .usage = "[chip] trst", - }, - { - .name = "swd_nums", - .handler = linuxgpiod_handle_swd_gpionums, - .mode = COMMAND_CONFIG, - .help = "gpio numbers for swclk, swdio. (in that order)", - .usage = "swclk swdio", - }, - { - .name = "swclk_num", - .handler = linuxgpiod_handle_swd_gpionum_swclk, - .mode = COMMAND_CONFIG, - .help = "gpio chip number (optional) and gpio number for swclk.", - .usage = "[chip] swclk", - }, - { - .name = "swdio_num", - .handler = linuxgpiod_handle_swd_gpionum_swdio, - .mode = COMMAND_CONFIG, - .help = "gpio chip number (optional) and gpio number for swdio.", - .usage = "[chip] swdio", - }, - { - .name = "swdio_dir_num", - .handler = linuxgpiod_handle_swd_gpionum_swdio_dir, - .mode = COMMAND_CONFIG, - .help = "gpio chip number (optional) and gpio number for swdio_dir.", - .usage = "[chip] swdio_dir", - }, - { - .name = "led_num", - .handler = linuxgpiod_handle_gpionum_led, - .mode = COMMAND_CONFIG, - .help = "gpio chip number (optional) and gpio number for LED.", - .usage = "[chip] led", - }, - { - .name = "gpiochip", - .handler = linuxgpiod_handle_gpiochip, - .mode = COMMAND_CONFIG, - .help = "number of the gpiochip.", - .usage = "gpiochip", - }, - COMMAND_REGISTRATION_DONE -}; - -static const struct command_registration linuxgpiod_command_handlers[] = { - { - .name = "linuxgpiod", - .mode = COMMAND_ANY, - .help = "perform linuxgpiod management", - .chain = linuxgpiod_subcommand_handlers, - .usage = "", - }, - COMMAND_REGISTRATION_DONE -}; - static const char *const linuxgpiod_transport[] = { "swd", "jtag", NULL }; static struct jtag_interface linuxgpiod_interface = { @@ -774,7 +435,6 @@ static struct jtag_interface linuxgpiod_interface = { struct adapter_driver linuxgpiod_adapter_driver = { .name = "linuxgpiod", .transports = linuxgpiod_transport, - .commands = linuxgpiod_command_handlers, .init = linuxgpiod_init, .quit = linuxgpiod_quit, diff --git a/src/jtag/drivers/minidriver_imp.h b/src/jtag/drivers/minidriver_imp.h index cd59a74fb5..7afb46345f 100644 --- a/src/jtag/drivers/minidriver_imp.h +++ b/src/jtag/drivers/minidriver_imp.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2007-2009 Øyvind Harboe <oyvind.harboe@zylin.com> * * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_MINIDRIVER_IMP_H diff --git a/src/jtag/drivers/mpsse.c b/src/jtag/drivers/mpsse.c index 0e3d2be0e0..41a8b6e33f 100644 --- a/src/jtag/drivers/mpsse.c +++ b/src/jtag/drivers/mpsse.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /************************************************************************** * Copyright (C) 2012 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -24,6 +13,7 @@ #include "helper/log.h" #include "helper/replacements.h" #include "helper/time_support.h" +#include "libusb_helper.h" #include <libusb.h> /* Compatibility define for older libusb-1.0 */ @@ -159,7 +149,7 @@ static bool device_location_equal(struct libusb_device *device, const char *loca * Set any field to 0 as a wildcard. If the device is found true is returned, with ctx containing * the already opened handle. ctx->interface must be set to the desired interface (channel) number * prior to calling this function. */ -static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, const uint16_t *pid, +static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t vids[], const uint16_t pids[], const char *product, const char *serial, const char *location) { struct libusb_device **list; @@ -180,9 +170,7 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con continue; } - if (vid && *vid != desc.idVendor) - continue; - if (pid && *pid != desc.idProduct) + if (!jtag_libusb_match_ids(&desc, vids, pids)) continue; err = libusb_open(device, &ctx->usb_dev); @@ -214,7 +202,7 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con libusb_free_device_list(list, 1); if (!found) { - LOG_ERROR("no device found"); + /* The caller reports detailed error desc */ return false; } @@ -318,14 +306,14 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con return false; } -struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const char *description, +struct mpsse_ctx *mpsse_open(const uint16_t vids[], const uint16_t pids[], const char *description, const char *serial, const char *location, int channel) { struct mpsse_ctx *ctx = calloc(1, sizeof(*ctx)); int err; if (!ctx) - return 0; + return NULL; bit_copy_queue_init(&ctx->read_queue); ctx->read_chunk_size = 16384; @@ -354,18 +342,13 @@ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const cha goto error; } - if (!open_matching_device(ctx, vid, pid, description, serial, location)) { - /* Four hex digits plus terminating zero each */ - char vidstr[5]; - char pidstr[5]; - LOG_ERROR("unable to open ftdi device with vid %s, pid %s, description '%s', " + if (!open_matching_device(ctx, vids, pids, description, serial, location)) { + LOG_ERROR("unable to open ftdi device with description '%s', " "serial '%s' at bus location '%s'", - vid ? sprintf(vidstr, "%04x", *vid), vidstr : "*", - pid ? sprintf(pidstr, "%04x", *pid), pidstr : "*", description ? description : "*", serial ? serial : "*", location ? location : "*"); - ctx->usb_dev = 0; + ctx->usb_dev = NULL; goto error; } @@ -395,7 +378,7 @@ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const cha return ctx; error: mpsse_close(ctx); - return 0; + return NULL; } void mpsse_close(struct mpsse_ctx *ctx) @@ -482,13 +465,13 @@ static unsigned buffer_add_read(struct mpsse_ctx *ctx, uint8_t *in, unsigned in_ void mpsse_clock_data_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, unsigned length, uint8_t mode) { - mpsse_clock_data(ctx, out, out_offset, 0, 0, length, mode); + mpsse_clock_data(ctx, out, out_offset, NULL, 0, length, mode); } void mpsse_clock_data_in(struct mpsse_ctx *ctx, uint8_t *in, unsigned in_offset, unsigned length, uint8_t mode) { - mpsse_clock_data(ctx, 0, 0, in, in_offset, length, mode); + mpsse_clock_data(ctx, NULL, 0, in, in_offset, length, mode); } void mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, @@ -565,7 +548,7 @@ void mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_of void mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, unsigned length, bool tdi, uint8_t mode) { - mpsse_clock_tms_cs(ctx, out, out_offset, 0, 0, length, tdi, mode); + mpsse_clock_tms_cs(ctx, out, out_offset, NULL, 0, length, tdi, mode); } void mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, @@ -859,7 +842,7 @@ int mpsse_flush(struct mpsse_ctx *ctx) if (ctx->write_count == 0) return retval; - struct libusb_transfer *read_transfer = 0; + struct libusb_transfer *read_transfer = NULL; struct transfer_result read_result = { .ctx = ctx, .done = true }; if (ctx->read_count) { buffer_write_byte(ctx, 0x87); /* SEND_IMMEDIATE */ @@ -897,20 +880,6 @@ int mpsse_flush(struct mpsse_ctx *ctx) retval = libusb_handle_events_timeout_completed(ctx->usb_ctx, &timeout_usb, NULL); keep_alive(); - if (retval == LIBUSB_ERROR_NO_DEVICE || retval == LIBUSB_ERROR_INTERRUPTED) - break; - - if (retval != LIBUSB_SUCCESS) { - libusb_cancel_transfer(write_transfer); - if (read_transfer) - libusb_cancel_transfer(read_transfer); - while (!write_result.done || !read_result.done) { - retval = libusb_handle_events_timeout_completed(ctx->usb_ctx, - &timeout_usb, NULL); - if (retval != LIBUSB_SUCCESS) - break; - } - } int64_t now = timeval_ms(); if (now - start > warn_after) { @@ -918,6 +887,15 @@ int mpsse_flush(struct mpsse_ctx *ctx) "ms.", now - start); warn_after *= 2; } + + if (retval == LIBUSB_ERROR_INTERRUPTED) + continue; + + if (retval != LIBUSB_SUCCESS) { + libusb_cancel_transfer(write_transfer); + if (read_transfer) + libusb_cancel_transfer(read_transfer); + } } error_check: diff --git a/src/jtag/drivers/mpsse.h b/src/jtag/drivers/mpsse.h index 651eef9406..a017aff002 100644 --- a/src/jtag/drivers/mpsse.h +++ b/src/jtag/drivers/mpsse.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /************************************************************************** * Copyright (C) 2012 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_MPSSE_H diff --git a/src/jtag/drivers/nulink_usb.c b/src/jtag/drivers/nulink_usb.c index 84a4420e82..4fdb857827 100644 --- a/src/jtag/drivers/nulink_usb.c +++ b/src/jtag/drivers/nulink_usb.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2016-2017 by Nuvoton * * Zale Yu <cyyu@nuvoton.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c index ae21cf2b9b..81b74d40ec 100644 --- a/src/jtag/drivers/opendous.c +++ b/src/jtag/drivers/opendous.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * * * Copyright (C) 2009 by Cahya Wirawan <cahya@gmx.at> * @@ -11,19 +13,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -110,7 +99,7 @@ static char *opendous_type; static const struct opendous_probe *opendous_probe; /* External interface functions */ -static int opendous_execute_queue(void); +static int opendous_execute_queue(struct jtag_command *cmd_queue); static int opendous_init(void); static int opendous_quit(void); @@ -249,9 +238,9 @@ struct adapter_driver opendous_adapter_driver = { .jtag_ops = &opendous_interface, }; -static int opendous_execute_queue(void) +static int opendous_execute_queue(struct jtag_command *cmd_queue) { - struct jtag_command *cmd = jtag_command_queue; + struct jtag_command *cmd = cmd_queue; int scan_size; enum scan_type type; uint8_t *buffer; @@ -358,7 +347,7 @@ static int opendous_init(void) opendous_jtag_handle = opendous_usb_open(); - if (opendous_jtag_handle == 0) { + if (!opendous_jtag_handle) { LOG_ERROR("Cannot find opendous Interface! Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; } @@ -706,7 +695,7 @@ struct opendous_jtag *opendous_usb_open(void) struct opendous_jtag *result; struct libusb_device_handle *devh; - if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, &devh, NULL) != ERROR_OK) + if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, NULL, &devh, NULL) != ERROR_OK) return NULL; jtag_libusb_set_configuration(devh, 0); @@ -746,7 +735,7 @@ int opendous_usb_message(struct opendous_jtag *opendous_jtag, int out_length, in /* Write data from out_buffer to USB. */ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length) { - int result; + int result, transferred; if (out_length > OPENDOUS_OUT_BUFFER_SIZE) { LOG_ERROR("opendous_jtag_write illegal out_length=%d (max=%d)", out_length, OPENDOUS_OUT_BUFFER_SIZE); @@ -759,7 +748,11 @@ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length) if (opendous_probe->CONTROL_TRANSFER) { result = jtag_libusb_control_transfer(opendous_jtag->usb_handle, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, - FUNC_WRITE_DATA, 0, 0, (char *) usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT); + FUNC_WRITE_DATA, 0, 0, (char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT, + &transferred); + /* FIXME: propagate error separately from transferred */ + if (result == ERROR_OK) + result = transferred; } else { jtag_libusb_bulk_write(opendous_jtag->usb_handle, OPENDOUS_WRITE_ENDPOINT, (char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT, &result); @@ -779,6 +772,8 @@ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length) /* Read data from USB into in_buffer. */ int opendous_usb_read(struct opendous_jtag *opendous_jtag) { + int transferred; + #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("USB read begin"); #endif @@ -786,7 +781,11 @@ int opendous_usb_read(struct opendous_jtag *opendous_jtag) if (opendous_probe->CONTROL_TRANSFER) { result = jtag_libusb_control_transfer(opendous_jtag->usb_handle, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, - FUNC_READ_DATA, 0, 0, (char *) usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT); + FUNC_READ_DATA, 0, 0, (char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT, + &transferred); + /* FIXME: propagate error separately from transferred */ + if (result == ERROR_OK) + result = transferred; } else { jtag_libusb_bulk_read(opendous_jtag->usb_handle, OPENDOUS_READ_ENDPOINT, (char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT, &result); @@ -807,17 +806,12 @@ int opendous_usb_read(struct opendous_jtag *opendous_jtag) void opendous_debug_buffer(uint8_t *buffer, int length) { - char line[81]; - char s[4]; - int i; - int j; + char line[8 + 3 * BYTES_PER_LINE + 1]; - for (i = 0; i < length; i += BYTES_PER_LINE) { - snprintf(line, 5, "%04x", i); - for (j = i; j < i + BYTES_PER_LINE && j < length; j++) { - snprintf(s, 4, " %02x", buffer[j]); - strcat(line, s); - } + for (int i = 0; i < length; i += BYTES_PER_LINE) { + int n = snprintf(line, 9, "%04x", i); + for (int j = i; j < i + BYTES_PER_LINE && j < length; j++) + n += snprintf(line + n, 4, " %02x", buffer[j]); LOG_DEBUG("%s", line); } } diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index 771b6e6f3e..ea78ca8fd6 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /******************************************************************************* * Driver for OpenJTAG Project (www.openjtag.org) * * Compatible with libftdi drivers. * @@ -18,19 +20,6 @@ * And jlink.c * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ /*************************************************************************** @@ -250,10 +239,10 @@ static int openjtag_buf_write_cy7c65215( ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST, CY7C65215_JTAG_WRITE, size, 0, - NULL, 0, CY7C65215_USB_TIMEOUT); - if (ret < 0) { - LOG_ERROR("vendor command failed, error %d", ret); - return ERROR_JTAG_DEVICE_ERROR; + NULL, 0, CY7C65215_USB_TIMEOUT, NULL); + if (ret != ERROR_OK) { + LOG_ERROR("vendor command failed"); + return ret; } if (jtag_libusb_bulk_write(usbh, ep_out, (char *)buf, size, @@ -317,10 +306,10 @@ static int openjtag_buf_read_cy7c65215( ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST, CY7C65215_JTAG_READ, qty, 0, - NULL, 0, CY7C65215_USB_TIMEOUT); - if (ret < 0) { - LOG_ERROR("vendor command failed, error %d", ret); - return ERROR_JTAG_DEVICE_ERROR; + NULL, 0, CY7C65215_USB_TIMEOUT, NULL); + if (ret != ERROR_OK) { + LOG_ERROR("vendor command failed"); + return ret; } if (jtag_libusb_bulk_read(usbh, ep_in, (char *)buf, qty, @@ -449,7 +438,7 @@ static int openjtag_init_cy7c65215(void) int ret; usbh = NULL; - ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, &usbh, NULL); + ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, NULL, &usbh, NULL); if (ret != ERROR_OK) { LOG_ERROR("unable to open cy7c65215 device"); goto err; @@ -466,8 +455,8 @@ static int openjtag_init_cy7c65215(void) ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST, CY7C65215_JTAG_ENABLE, - 0, 0, NULL, 0, CY7C65215_USB_TIMEOUT); - if (ret < 0) { + 0, 0, NULL, 0, CY7C65215_USB_TIMEOUT, NULL); + if (ret != ERROR_OK) { LOG_ERROR("could not enable JTAG module"); goto err; } @@ -477,7 +466,7 @@ static int openjtag_init_cy7c65215(void) err: if (usbh) jtag_libusb_close(usbh); - return ERROR_JTAG_INIT_FAILED; + return ret; } static int openjtag_init(void) @@ -519,8 +508,8 @@ static int openjtag_quit_cy7c65215(void) ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST, CY7C65215_JTAG_DISABLE, - 0, 0, NULL, 0, CY7C65215_USB_TIMEOUT); - if (ret < 0) + 0, 0, NULL, 0, CY7C65215_USB_TIMEOUT, NULL); + if (ret != ERROR_OK) LOG_WARNING("could not disable JTAG module"); jtag_libusb_close(usbh); @@ -541,9 +530,20 @@ static int openjtag_quit(void) static void openjtag_write_tap_buffer(void) { uint32_t written; + uint32_t rx_expected = 0; + + /* calculate expected number of return bytes */ + for (int tx_offs = 0; tx_offs < usb_tx_buf_offs; tx_offs++) { + if ((usb_tx_buf[tx_offs] & 0x0F) == 6) { + rx_expected++; + tx_offs++; + } else if ((usb_tx_buf[tx_offs] & 0x0F) == 2) { + rx_expected++; + } + } openjtag_buf_write(usb_tx_buf, usb_tx_buf_offs, &written); - openjtag_buf_read(usb_rx_buf, usb_tx_buf_offs, &usb_rx_buf_len); + openjtag_buf_read(usb_rx_buf, rx_expected, &usb_rx_buf_len); usb_tx_buf_offs = 0; } @@ -671,14 +671,12 @@ static void openjtag_execute_reset(struct jtag_command *cmd) uint8_t buf = 0x00; - if (cmd->cmd.reset->trst) { - buf = 0x03; - } else { + /* Pull SRST low for 5 TCLK cycles */ + if (cmd->cmd.reset->srst) { buf |= 0x04; buf |= 0x05 << 4; + openjtag_add_byte(buf); } - - openjtag_add_byte(buf); } static void openjtag_execute_sleep(struct jtag_command *cmd) @@ -691,8 +689,14 @@ static void openjtag_set_state(uint8_t openocd_state) uint8_t state = openjtag_get_tap_state(openocd_state); uint8_t buf = 0; - buf = 0x01; - buf |= state << 4; + + if (state != OPENJTAG_TAP_RESET) { + buf = 0x01; + buf |= state << 4; + } else { + /* Force software TLR */ + buf = 0x03; + } openjtag_add_byte(buf); } @@ -753,16 +757,18 @@ static void openjtag_execute_runtest(struct jtag_command *cmd) tap_set_state(TAP_IDLE); } - if (cmd->cmd.runtest->num_cycles > 16) - LOG_WARNING("num_cycles > 16 on run test"); - if (openjtag_variant != OPENJTAG_VARIANT_CY7C65215 || cmd->cmd.runtest->num_cycles) { uint8_t command; - command = 7; - command |= ((cmd->cmd.runtest->num_cycles - 1) & 0x0F) << 4; + int cycles = cmd->cmd.runtest->num_cycles; - openjtag_add_byte(command); + do { + command = 7; + command |= (((cycles > 16 ? 16 : cycles) - 1) & 0x0F) << 4; + + openjtag_add_byte(command); + cycles -= 16; + } while (cycles > 0); } tap_set_end_state(end_state); @@ -799,9 +805,9 @@ static void openjtag_execute_command(struct jtag_command *cmd) } } -static int openjtag_execute_queue(void) +static int openjtag_execute_queue(struct jtag_command *cmd_queue) { - struct jtag_command *cmd = jtag_command_queue; + struct jtag_command *cmd = cmd_queue; while (cmd) { openjtag_execute_command(cmd); @@ -870,6 +876,17 @@ COMMAND_HANDLER(openjtag_handle_variant_command) return ERROR_OK; } +COMMAND_HANDLER(openjtag_handle_vid_pid_command) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], openjtag_vid); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], openjtag_pid); + + return ERROR_OK; +} + static const struct command_registration openjtag_subcommand_handlers[] = { { .name = "device_desc", @@ -885,6 +902,13 @@ static const struct command_registration openjtag_subcommand_handlers[] = { .help = "set the OpenJTAG variant", .usage = "variant-string", }, + { + .name = "vid_pid", + .handler = openjtag_handle_vid_pid_command, + .mode = COMMAND_CONFIG, + .help = "USB VID and PID of the adapter", + .usage = "vid pid", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/drivers/osbdm.c b/src/jtag/drivers/osbdm.c index f7665eb12b..8d4fc90d88 100644 --- a/src/jtag/drivers/osbdm.c +++ b/src/jtag/drivers/osbdm.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2012 by Jan Dakinevich * * jan.dakinevich@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" @@ -374,7 +363,7 @@ static int osbdm_flush(struct osbdm *osbdm, struct queue *queue) static int osbdm_open(struct osbdm *osbdm) { (void)memset(osbdm, 0, sizeof(*osbdm)); - if (jtag_libusb_open(osbdm_vid, osbdm_pid, &osbdm->devh, NULL) != ERROR_OK) + if (jtag_libusb_open(osbdm_vid, osbdm_pid, NULL, &osbdm->devh, NULL) != ERROR_OK) return ERROR_FAIL; if (libusb_claim_interface(osbdm->devh, 0) != ERROR_OK) @@ -639,7 +628,7 @@ static int osbdm_execute_command( return retval; } -static int osbdm_execute_queue(void) +static int osbdm_execute_queue(struct jtag_command *cmd_queue) { int retval = ERROR_OK; @@ -648,7 +637,7 @@ static int osbdm_execute_queue(void) LOG_ERROR("BUG: can't allocate bit queue"); retval = ERROR_FAIL; } else { - struct jtag_command *cmd = jtag_command_queue; + struct jtag_command *cmd = cmd_queue; while (retval == ERROR_OK && cmd) { retval = osbdm_execute_command(&osbdm_context, queue, cmd); diff --git a/src/jtag/drivers/parport.c b/src/jtag/drivers/parport.c index 9273e3ec27..d26a51048f 100644 --- a/src/jtag/drivers/parport.c +++ b/src/jtag/drivers/parport.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -422,9 +411,13 @@ COMMAND_HANDLER(parport_handle_parport_cable_command) return ERROR_OK; /* only if the cable name wasn't overwritten by cmdline */ - if (parport_cable == 0) { + if (!parport_cable) { /* REVISIT first verify that it's listed in cables[] ... */ parport_cable = malloc(strlen(CMD_ARGV[0]) + sizeof(char)); + if (!parport_cable) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } strcpy(parport_cable, CMD_ARGV[0]); } diff --git a/src/jtag/drivers/presto.c b/src/jtag/drivers/presto.c index e938a3be3a..f6e13f7eb4 100644 --- a/src/jtag/drivers/presto.c +++ b/src/jtag/drivers/presto.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * - * * - * 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/>. * ***************************************************************************/ /** diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index 6ab7cc9c59..c97b6b6abe 100644 --- a/src/jtag/drivers/remote_bitbang.c +++ b/src/jtag/drivers/remote_bitbang.c @@ -1,19 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Richard Uhler * * ruhler@mit.edu * * * - * 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/>. * + * Copyright (C) 2021 by Manuel Wick <manuel@matronix.de> * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -40,6 +31,8 @@ static int remote_bitbang_fd; static uint8_t remote_bitbang_send_buf[512]; static unsigned int remote_bitbang_send_buf_used; +static bool use_remote_sleep; + /* Circular buffer. When start == end, the buffer is empty. */ static char remote_bitbang_recv_buf[256]; static unsigned int remote_bitbang_recv_buf_start; @@ -225,18 +218,70 @@ static int remote_bitbang_reset(int trst, int srst) return remote_bitbang_queue(c, FLUSH_SEND_BUF); } +static int remote_bitbang_sleep(unsigned int microseconds) +{ + if (!use_remote_sleep) { + jtag_sleep(microseconds); + return ERROR_OK; + } + + int tmp; + unsigned int ms = microseconds / 1000; + unsigned int us = microseconds % 1000; + + for (unsigned int i = 0; i < ms; i++) { + tmp = remote_bitbang_queue('D', NO_FLUSH); + if (tmp != ERROR_OK) + return tmp; + } + + for (unsigned int i = 0; i < us; i++) { + tmp = remote_bitbang_queue('d', NO_FLUSH); + if (tmp != ERROR_OK) + return tmp; + } + + return remote_bitbang_flush(); +} + static int remote_bitbang_blink(int on) { char c = on ? 'B' : 'b'; return remote_bitbang_queue(c, FLUSH_SEND_BUF); } +static void remote_bitbang_swdio_drive(bool is_output) +{ + char c = is_output ? 'O' : 'o'; + if (remote_bitbang_queue(c, FLUSH_SEND_BUF) == ERROR_FAIL) + LOG_ERROR("Error setting direction for swdio"); +} + +static int remote_bitbang_swdio_read(void) +{ + if (remote_bitbang_queue('c', FLUSH_SEND_BUF) != ERROR_FAIL) + return remote_bitbang_read_sample(); + else + return BB_ERROR; +} + +static int remote_bitbang_swd_write(int swclk, int swdio) +{ + char c = 'd' + ((swclk ? 0x2 : 0x0) | (swdio ? 0x1 : 0x0)); + return remote_bitbang_queue(c, NO_FLUSH); +} + static struct bitbang_interface remote_bitbang_bitbang = { .buf_size = sizeof(remote_bitbang_recv_buf) - 1, .sample = &remote_bitbang_sample, .read_sample = &remote_bitbang_read_sample, .write = &remote_bitbang_write, + .swdio_read = &remote_bitbang_swdio_read, + .swdio_drive = &remote_bitbang_swdio_drive, + .swd_write = &remote_bitbang_swd_write, .blink = &remote_bitbang_blink, + .sleep = &remote_bitbang_sleep, + .flush = &remote_bitbang_flush, }; static int remote_bitbang_init_tcp(void) @@ -360,6 +405,18 @@ COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_host_command) return ERROR_COMMAND_SYNTAX_ERROR; } +static const char * const remote_bitbang_transports[] = { "jtag", "swd", NULL }; + +COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_use_remote_sleep_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], use_remote_sleep); + + return ERROR_OK; +} + static const struct command_registration remote_bitbang_subcommand_handlers[] = { { .name = "port", @@ -377,7 +434,15 @@ static const struct command_registration remote_bitbang_subcommand_handlers[] = " if port is 0 or unset, this is the name of the unix socket to use.", .usage = "host_name", }, - COMMAND_REGISTRATION_DONE, + { + .name = "use_remote_sleep", + .handler = remote_bitbang_handle_remote_bitbang_use_remote_sleep_command, + .mode = COMMAND_CONFIG, + .help = "Rather than executing sleep locally, include delays in the " + "instruction stream for the remote host.", + .usage = "(on|off)", + }, + COMMAND_REGISTRATION_DONE }; static const struct command_registration remote_bitbang_command_handlers[] = { @@ -391,14 +456,14 @@ static const struct command_registration remote_bitbang_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static int remote_bitbang_execute_queue(void) +static int remote_bitbang_execute_queue(struct jtag_command *cmd_queue) { /* safety: the send buffer must be empty, no leftover characters from * previous transactions */ assert(remote_bitbang_send_buf_used == 0); /* process the JTAG command queue */ - int ret = bitbang_execute_queue(); + int ret = bitbang_execute_queue(cmd_queue); if (ret != ERROR_OK) return ret; @@ -412,7 +477,7 @@ static struct jtag_interface remote_bitbang_interface = { struct adapter_driver remote_bitbang_adapter_driver = { .name = "remote_bitbang", - .transports = jtag_only, + .transports = remote_bitbang_transports, .commands = remote_bitbang_command_handlers, .init = &remote_bitbang_init, @@ -420,4 +485,5 @@ struct adapter_driver remote_bitbang_adapter_driver = { .reset = &remote_bitbang_reset, .jtag_ops = &remote_bitbang_interface, + .swd_ops = &bitbang_swd, }; diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c index 0cf9dbbb23..1b1f2e4de6 100644 --- a/src/jtag/drivers/rlink.c +++ b/src/jtag/drivers/rlink.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 Rob Brown, Lou Deluxe * * rob@cobbleware.com, lou.openocd012@fixit.nospammail.net * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -643,7 +632,7 @@ static int dtc_queue_run(void) uint8_t dtc_mask, tdo_mask; uint8_t reply_buffer[USB_EP2IN_SIZE]; - assert((dtc_queue.rq_head != 0) == (dtc_queue.reply_index > 0)); + assert((!!dtc_queue.rq_head) == (dtc_queue.reply_index > 0)); assert(dtc_queue.cmd_index < USB_EP2BANK_SIZE); assert(dtc_queue.reply_index <= USB_EP2IN_SIZE); @@ -1273,9 +1262,9 @@ static int rlink_scan(struct jtag_command *cmd, enum scan_type type, return 0; } -static int rlink_execute_queue(void) +static int rlink_execute_queue(struct jtag_command *cmd_queue) { - struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ + struct jtag_command *cmd = cmd_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; @@ -1459,7 +1448,7 @@ static int rlink_init(void) const uint16_t vids[] = { USB_IDVENDOR, 0 }; const uint16_t pids[] = { USB_IDPRODUCT, 0 }; - if (jtag_libusb_open(vids, pids, &hdev, NULL) != ERROR_OK) + if (jtag_libusb_open(vids, pids, NULL, &hdev, NULL) != ERROR_OK) return ERROR_FAIL; struct libusb_device_descriptor descriptor; diff --git a/src/jtag/drivers/rlink.h b/src/jtag/drivers/rlink.h index 0c15a3223d..38f8429b06 100644 --- a/src/jtag/drivers/rlink.h +++ b/src/jtag/drivers/rlink.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2008 Lou Deluxe * * lou.openocd012@fixit.nospammail.net * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_RLINK_H diff --git a/src/jtag/drivers/rlink_call.m4 b/src/jtag/drivers/rlink_call.m4 index bf07afa4ed..39ac25c7cb 100644 --- a/src/jtag/drivers/rlink_call.m4 +++ b/src/jtag/drivers/rlink_call.m4 @@ -1,21 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Copyright (C) 2008 Lou Deluxe +# lou.openocd012@fixit.nospammail.net +# + m4_divert(`-1') -/*************************************************************************** - * Copyright (C) 2008 Lou Deluxe * - * lou.openocd012@fixit.nospammail.net * - * * - * 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/>. * - ***************************************************************************/ m4_dnl Setup and hold times depend on SHIFTER_PRESCALER m4_define(`SETUP_DELAY_CYCLES', m4_eval(`('SHIFTER_PRESCALER` + 1) / 2')) diff --git a/src/jtag/drivers/rlink_dtc_cmd.h b/src/jtag/drivers/rlink_dtc_cmd.h index ff9e8b25fc..b40ad1716f 100644 --- a/src/jtag/drivers/rlink_dtc_cmd.h +++ b/src/jtag/drivers/rlink_dtc_cmd.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2008 Lou Deluxe * * lou.openocd012@fixit.nospammail.net * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_RLINK_DTC_CMD_H diff --git a/src/jtag/drivers/rlink_ep1_cmd.h b/src/jtag/drivers/rlink_ep1_cmd.h index 3f9f2b3811..812d7e51cb 100644 --- a/src/jtag/drivers/rlink_ep1_cmd.h +++ b/src/jtag/drivers/rlink_ep1_cmd.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2008 Lou Deluxe * * lou.openocd012@fixit.nospammail.net * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_RLINK_EP1_CMD_H diff --git a/src/jtag/drivers/rlink_init.m4 b/src/jtag/drivers/rlink_init.m4 index 8ad2f51d81..e77e943ed8 100644 --- a/src/jtag/drivers/rlink_init.m4 +++ b/src/jtag/drivers/rlink_init.m4 @@ -1,21 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Copyright (C) 2008 Lou Deluxe +# lou.openocd012@fixit.nospammail.net +# + m4_divert(`-1') -/*************************************************************************** - * Copyright (C) 2008 Lou Deluxe * - * lou.openocd012@fixit.nospammail.net * - * * - * 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/>. * - ***************************************************************************/ m4_undefine(`CTRL_MPEG_L') m4_undefine(`CTRL_CARD_L') diff --git a/src/jtag/drivers/rlink_st7.h b/src/jtag/drivers/rlink_st7.h index 3d573e72ce..b891024041 100644 --- a/src/jtag/drivers/rlink_st7.h +++ b/src/jtag/drivers/rlink_st7.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2008 Lou Deluxe * * lou.openocd012@fixit.nospammail.net * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_RLINK_ST7_H diff --git a/src/jtag/drivers/rshim.c b/src/jtag/drivers/rshim.c index 246e931c22..21fc7fd378 100644 --- a/src/jtag/drivers/rshim.c +++ b/src/jtag/drivers/rshim.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright (c) 2020, Mellanox Technologies Ltd. - All Rights Reserved * Liming Sun <lsun@mellanox.com> - * - * 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/>. */ #ifdef HAVE_CONFIG_H @@ -265,8 +254,8 @@ static int rshim_dp_q_write(struct adiv5_dap *dap, unsigned int reg, dp_ctrl_stat = data; break; case DP_SELECT: - ap_sel = (data & DP_SELECT_APSEL) >> 24; - ap_bank = (data & DP_SELECT_APBANK) >> 4; + ap_sel = (data & ADIV5_DP_SELECT_APSEL) >> 24; + ap_bank = (data & ADIV5_DP_SELECT_APBANK) >> 4; break; default: LOG_INFO("Unknown command"); @@ -282,36 +271,44 @@ static int rshim_ap_q_read(struct adiv5_ap *ap, unsigned int reg, uint32_t addr; int rc = ERROR_OK, tile; + if (is_adiv6(ap->dap)) { + static bool error_flagged; + if (!error_flagged) + LOG_ERROR("ADIv6 dap not supported by rshim dap-direct mode"); + error_flagged = true; + return ERROR_FAIL; + } + switch (reg) { - case MEM_AP_REG_CSW: + case ADIV5_MEM_AP_REG_CSW: *data = ap_csw; break; - case MEM_AP_REG_CFG: + case ADIV5_MEM_AP_REG_CFG: *data = 0; break; - case MEM_AP_REG_BASE: + case ADIV5_MEM_AP_REG_BASE: *data = RSH_CS_ROM_BASE; break; - case AP_REG_IDR: + case ADIV5_AP_REG_IDR: if (ap->ap_num == 0) *data = APB_AP_IDR; else *data = 0; break; - case MEM_AP_REG_BD0: - case MEM_AP_REG_BD1: - case MEM_AP_REG_BD2: - case MEM_AP_REG_BD3: + case ADIV5_MEM_AP_REG_BD0: + case ADIV5_MEM_AP_REG_BD1: + case ADIV5_MEM_AP_REG_BD2: + case ADIV5_MEM_AP_REG_BD3: addr = (ap_tar & ~0xf) + (reg & 0x0C); ap_addr_2_tile(&tile, &addr); rc = coresight_read(tile, addr, data); break; - case MEM_AP_REG_DRW: + case ADIV5_MEM_AP_REG_DRW: addr = (ap_tar & ~0x3) + ap_tar_inc; ap_addr_2_tile(&tile, &addr); rc = coresight_read(tile, addr, data); @@ -338,31 +335,39 @@ static int rshim_ap_q_write(struct adiv5_ap *ap, unsigned int reg, int rc = ERROR_OK, tile; uint32_t addr; + if (is_adiv6(ap->dap)) { + static bool error_flagged; + if (!error_flagged) + LOG_ERROR("ADIv6 dap not supported by rshim dap-direct mode"); + error_flagged = true; + return ERROR_FAIL; + } + if (ap_bank != 0) { rshim_dap_retval = ERROR_FAIL; return ERROR_FAIL; } switch (reg) { - case MEM_AP_REG_CSW: + case ADIV5_MEM_AP_REG_CSW: ap_csw = data; break; - case MEM_AP_REG_TAR: + case ADIV5_MEM_AP_REG_TAR: ap_tar = data; ap_tar_inc = 0; break; - case MEM_AP_REG_BD0: - case MEM_AP_REG_BD1: - case MEM_AP_REG_BD2: - case MEM_AP_REG_BD3: + case ADIV5_MEM_AP_REG_BD0: + case ADIV5_MEM_AP_REG_BD1: + case ADIV5_MEM_AP_REG_BD2: + case ADIV5_MEM_AP_REG_BD3: addr = (ap_tar & ~0xf) + (reg & 0x0C); ap_addr_2_tile(&tile, &addr); rc = coresight_write(tile, addr, data); break; - case MEM_AP_REG_DRW: + case ADIV5_MEM_AP_REG_DRW: ap_drw = data; addr = (ap_tar & ~0x3) + ap_tar_inc; ap_addr_2_tile(&tile, &addr); @@ -429,10 +434,8 @@ static void rshim_disconnect(struct adiv5_dap *dap) COMMAND_HANDLER(rshim_dap_device_command) { - if (CMD_ARGC != 1) { - command_print(CMD, "Too many arguments"); + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - } free(rshim_dev_path); rshim_dev_path = strdup(CMD_ARGV[0]); diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 2785d9b968..b14fbf1f38 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2020 by Tarek Bochkati * * Tarek Bochkati <tarek.bouchkati@gmail.com> * @@ -13,19 +15,6 @@ * spen@spen-soft.co.uk * * * * This code is based on https://github.com/texane/stlink * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -95,6 +84,8 @@ #define STLINK_V3S_PID (0x374F) #define STLINK_V3_2VCP_PID (0x3753) #define STLINK_V3E_NO_MSD_PID (0x3754) +#define STLINK_V3P_USBLOADER_PID (0x3755) +#define STLINK_V3P_PID (0x3757) /* * ST-Link/V1, ST-Link/V2 and ST-Link/V2.1 are full-speed USB devices and @@ -465,7 +456,7 @@ static inline int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, i #define STLINK_DEBUG_PORT_ACCESS 0xffff #define STLINK_TRACE_SIZE 4096 -#define STLINK_TRACE_MAX_HZ 2000000 +#define STLINK_TRACE_MAX_HZ 2250000 #define STLINK_V3_TRACE_MAX_HZ 24000000 #define STLINK_V3_MAX_FREQ_NB 10 @@ -504,6 +495,8 @@ static inline int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, i #define STLINK_TCP_SS_CMD_NOT_AVAILABLE 0x00001053 #define STLINK_TCP_SS_TCP_ERROR 0x00002001 #define STLINK_TCP_SS_TCP_CANT_CONNECT 0x00002002 +#define STLINK_TCP_SS_TCP_CLOSE_ERROR 0x00002003 +#define STLINK_TCP_SS_TCP_BUSY 0x00002004 #define STLINK_TCP_SS_WIN32_ERROR 0x00010000 /* @@ -971,6 +964,11 @@ static int stlink_tcp_send_cmd(void *handle, int send_size, int recv_size, bool if (check_tcp_status) { uint32_t tcp_ss = le_to_h_u32(h->tcp_backend_priv.recv_buf); if (tcp_ss != STLINK_TCP_SS_OK) { + if (tcp_ss == STLINK_TCP_SS_TCP_BUSY) { + LOG_DEBUG("TCP busy"); + return ERROR_WAIT; + } + LOG_ERROR("TCP error status 0x%X", tcp_ss); return ERROR_FAIL; } @@ -1301,8 +1299,8 @@ static int stlink_usb_version(void *handle) break; } - /* STLINK-V3 requires a specific command */ - if (v == 3 && x == 0 && y == 0) { + /* STLINK-V3 & STLINK-V3P require a specific command */ + if (v >= 3 && x == 0 && y == 0) { stlink_usb_init_buffer(handle, h->rx_ep, 16); h->cmdbuf[h->cmdidx++] = STLINK_APIV3_GET_VERSION_EX; @@ -1418,6 +1416,41 @@ static int stlink_usb_version(void *handle) if (h->version.jtag >= 6) flags |= STLINK_F_HAS_RW8_512BYTES; + break; + case 4: + /* STLINK-V3P use api-v3 */ + h->version.jtag_api = STLINK_JTAG_API_V3; + + /* STLINK-V3P is a superset of ST-LINK/V3 */ + + /* API for trace */ + /* API for target voltage */ + flags |= STLINK_F_HAS_TRACE; + + /* preferred API to get last R/W status */ + flags |= STLINK_F_HAS_GETLASTRWSTATUS2; + + /* API to access DAP registers */ + flags |= STLINK_F_HAS_DAP_REG; + + /* API to read/write memory at 16 bit */ + /* API to write memory without address increment */ + flags |= STLINK_F_HAS_MEM_16BIT; + + /* API required to init AP before any AP access */ + flags |= STLINK_F_HAS_AP_INIT; + + /* API required to return proper error code on close AP */ + flags |= STLINK_F_FIX_CLOSE_AP; + + /* Banked regs (DPv1 & DPv2) support */ + /* API to read memory without address increment */ + /* Memory R/W supports CSW */ + flags |= STLINK_F_HAS_DPBANKSEL; + + /* 8bit read/write max packet size 512 bytes */ + flags |= STLINK_F_HAS_RW8_512BYTES; + break; default: break; @@ -3373,7 +3406,7 @@ static int stlink_usb_usb_open(void *handle, struct hl_interface_param_s *param) in order to become operational. */ do { - if (jtag_libusb_open(param->vid, param->pid, + if (jtag_libusb_open(param->vid, param->pid, NULL, &h->usb_backend_priv.fd, stlink_usb_get_alternate_serial) != ERROR_OK) { LOG_ERROR("open failed"); return ERROR_FAIL; @@ -3406,6 +3439,8 @@ static int stlink_usb_usb_open(void *handle, struct hl_interface_param_s *param) case STLINK_V3S_PID: case STLINK_V3_2VCP_PID: case STLINK_V3E_NO_MSD_PID: + case STLINK_V3P_USBLOADER_PID: + case STLINK_V3P_PID: h->version.stlink = 3; h->tx_ep = STLINK_V2_1_TX_EP; h->trace_ep = STLINK_V2_1_TRACE_EP; @@ -3698,7 +3733,7 @@ static int stlink_open(struct hl_interface_param_s *param, enum stlink_mode mode h = calloc(1, sizeof(struct stlink_usb_handle_s)); - if (h == 0) { + if (!h) { LOG_DEBUG("malloc failed"); return ERROR_FAIL; } @@ -3824,7 +3859,7 @@ static int stlink_config_trace(void *handle, bool enabled, return ERROR_FAIL; } - unsigned int max_trace_freq = (h->version.stlink == 3) ? + unsigned int max_trace_freq = (h->version.stlink >= 3) ? STLINK_V3_TRACE_MAX_HZ : STLINK_TRACE_MAX_HZ; /* Only concern ourselves with the frequency if the STlink is processing it. */ @@ -4145,7 +4180,7 @@ static int stlink_dap_reinit_interface(void) stlink_dap_handle->reconnect_pending = false; /* on new FW, calling mode-leave closes all the opened AP; reopen them! */ if (stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT) - for (int apsel = 0; apsel <= DP_APSEL_MAX; apsel++) + for (unsigned int apsel = 0; apsel <= DP_APSEL_MAX; apsel++) if (test_bit(apsel, opened_ap)) { clear_bit(apsel, opened_ap); stlink_dap_open_ap(apsel); @@ -4279,7 +4314,15 @@ static int stlink_dap_ap_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *d uint32_t dummy; int retval; - if (reg != AP_REG_IDR) { + if (is_adiv6(dap)) { + static bool error_flagged; + if (!error_flagged) + LOG_ERROR("ADIv6 dap not supported by stlink dap-direct mode"); + error_flagged = true; + return ERROR_FAIL; + } + + if (reg != ADIV5_AP_REG_IDR) { retval = stlink_dap_open_ap(ap->ap_num); if (retval != ERROR_OK) return retval; @@ -4297,6 +4340,14 @@ static int stlink_dap_ap_write(struct adiv5_ap *ap, unsigned int reg, uint32_t d struct adiv5_dap *dap = ap->dap; int retval; + if (is_adiv6(dap)) { + static bool error_flagged; + if (!error_flagged) + LOG_ERROR("ADIv6 dap not supported by stlink dap-direct mode"); + error_flagged = true; + return ERROR_FAIL; + } + retval = stlink_dap_open_ap(ap->ap_num); if (retval != ERROR_OK) return retval; @@ -4325,7 +4376,7 @@ static int stlink_usb_misc_rw_segment(void *handle, const struct dap_queue *q, u LOG_DEBUG("Queue: %u commands in %u items", len, items); - int ap_num = DP_APSEL_INVALID; + uint32_t ap_num = DP_APSEL_INVALID; unsigned int cmd_index = 0; unsigned int val_index = ALIGN_UP(items, 4); for (unsigned int i = 0; i < len; i++) { @@ -4474,7 +4525,7 @@ static int stlink_usb_count_misc_rw_queue(void *handle, const struct dap_queue * { struct stlink_usb_handle_s *h = handle; unsigned int i, items = 0; - int ap_num = DP_APSEL_INVALID; + uint32_t ap_num = DP_APSEL_INVALID; unsigned int misc_max_items = (h->version.stlink == 2) ? STLINK_V2_RW_MISC_SIZE : STLINK_V3_RW_MISC_SIZE; if (!(h->version.flags & STLINK_F_HAS_RW_MISC)) @@ -4584,7 +4635,7 @@ static void stlink_dap_run_internal(struct adiv5_dap *dap) break; case CMD_AP_WRITE: /* ignore increment packed, not supported */ - if (q->ap_w.reg == MEM_AP_REG_CSW) + if (q->ap_w.reg == ADIV5_MEM_AP_REG_CSW) q->ap_w.data &= ~CSW_ADDRINC_PACKED; retval = stlink_dap_ap_write(q->ap_w.ap, q->ap_w.reg, q->ap_w.data); break; @@ -4729,18 +4780,18 @@ static int stlink_dap_op_queue_ap_read(struct adiv5_ap *ap, unsigned int reg, /* test STLINK_F_HAS_CSW implicitly tests STLINK_F_HAS_MEM_16BIT, STLINK_F_HAS_MEM_RD_NO_INC * and STLINK_F_HAS_RW_MISC */ if ((stlink_dap_handle->version.flags & STLINK_F_HAS_CSW) && - (reg == MEM_AP_REG_DRW || reg == MEM_AP_REG_BD0 || reg == MEM_AP_REG_BD1 || - reg == MEM_AP_REG_BD2 || reg == MEM_AP_REG_BD3)) { + (reg == ADIV5_MEM_AP_REG_DRW || reg == ADIV5_MEM_AP_REG_BD0 || reg == ADIV5_MEM_AP_REG_BD1 || + reg == ADIV5_MEM_AP_REG_BD2 || reg == ADIV5_MEM_AP_REG_BD3)) { /* de-queue previous write-TAR */ struct dap_queue *prev_q = q - 1; - if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == MEM_AP_REG_TAR) { + if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == ADIV5_MEM_AP_REG_TAR) { stlink_dap_handle->queue_index = i; i--; q = prev_q; prev_q--; } /* de-queue previous write-CSW if it didn't changed ap->csw_default */ - if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == MEM_AP_REG_CSW && + if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == ADIV5_MEM_AP_REG_CSW && !prev_q->ap_w.changes_csw_default) { stlink_dap_handle->queue_index = i; q = prev_q; @@ -4762,7 +4813,7 @@ static int stlink_dap_op_queue_ap_read(struct adiv5_ap *ap, unsigned int reg, return ERROR_FAIL; } - q->mem_ap.addr = (reg == MEM_AP_REG_DRW) ? ap->tar_value : ((ap->tar_value & ~0x0f) | (reg & 0x0c)); + q->mem_ap.addr = (reg == ADIV5_MEM_AP_REG_DRW) ? ap->tar_value : ((ap->tar_value & ~0x0f) | (reg & 0x0c)); q->mem_ap.ap = ap; q->mem_ap.p_data = data; q->mem_ap.csw = ap->csw_default; @@ -4795,18 +4846,18 @@ static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned int reg, /* test STLINK_F_HAS_CSW implicitly tests STLINK_F_HAS_MEM_16BIT, STLINK_F_HAS_MEM_WR_NO_INC * and STLINK_F_HAS_RW_MISC */ if ((stlink_dap_handle->version.flags & STLINK_F_HAS_CSW) && - (reg == MEM_AP_REG_DRW || reg == MEM_AP_REG_BD0 || reg == MEM_AP_REG_BD1 || - reg == MEM_AP_REG_BD2 || reg == MEM_AP_REG_BD3)) { + (reg == ADIV5_MEM_AP_REG_DRW || reg == ADIV5_MEM_AP_REG_BD0 || reg == ADIV5_MEM_AP_REG_BD1 || + reg == ADIV5_MEM_AP_REG_BD2 || reg == ADIV5_MEM_AP_REG_BD3)) { /* de-queue previous write-TAR */ struct dap_queue *prev_q = q - 1; - if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == MEM_AP_REG_TAR) { + if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == ADIV5_MEM_AP_REG_TAR) { stlink_dap_handle->queue_index = i; i--; q = prev_q; prev_q--; } /* de-queue previous write-CSW if it didn't changed ap->csw_default */ - if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == MEM_AP_REG_CSW && + if (i && prev_q->cmd == CMD_AP_WRITE && prev_q->ap_w.ap == ap && prev_q->ap_w.reg == ADIV5_MEM_AP_REG_CSW && !prev_q->ap_w.changes_csw_default) { stlink_dap_handle->queue_index = i; q = prev_q; @@ -4828,7 +4879,7 @@ static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned int reg, return ERROR_FAIL; } - q->mem_ap.addr = (reg == MEM_AP_REG_DRW) ? ap->tar_value : ((ap->tar_value & ~0x0f) | (reg & 0x0c)); + q->mem_ap.addr = (reg == ADIV5_MEM_AP_REG_DRW) ? ap->tar_value : ((ap->tar_value & ~0x0f) | (reg & 0x0c)); q->mem_ap.ap = ap; q->mem_ap.data = data; q->mem_ap.csw = ap->csw_default; @@ -4841,9 +4892,10 @@ static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned int reg, q->ap_w.reg = reg; q->ap_w.ap = ap; q->ap_w.data = data; - if (reg == MEM_AP_REG_CSW && ap->csw_default != last_csw_default[ap->ap_num]) { + uint8_t ap_num = ap->ap_num; + if (reg == ADIV5_MEM_AP_REG_CSW && ap->csw_default != last_csw_default[ap_num]) { q->ap_w.changes_csw_default = true; - last_csw_default[ap->ap_num] = ap->csw_default; + last_csw_default[ap_num] = ap->csw_default; } else { q->ap_w.changes_csw_default = false; } diff --git a/src/jtag/drivers/sysfsgpio.c b/src/jtag/drivers/sysfsgpio.c index 103b810092..a5f5fd3ac0 100644 --- a/src/jtag/drivers/sysfsgpio.c +++ b/src/jtag/drivers/sysfsgpio.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au * - * * - * 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/>. * ***************************************************************************/ /* 2014-12: Addition of the SWD protocol support is based on the initial work @@ -582,7 +571,7 @@ static struct bitbang_interface sysfsgpio_bitbang = { .swdio_read = sysfsgpio_swdio_read, .swdio_drive = sysfsgpio_swdio_drive, .swd_write = sysfsgpio_swd_write, - .blink = 0 + .blink = NULL, }; /* helper func to close and cleanup files only if they were valid/ used */ diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c index e48d0e269e..4260e2d39d 100644 --- a/src/jtag/drivers/ti_icdi_usb.c +++ b/src/jtag/drivers/ti_icdi_usb.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -380,7 +369,7 @@ static int icdi_usb_query(void *handle) if (h->max_packet != ICDI_PACKET_SIZE) { h->read_buffer = realloc(h->read_buffer, h->max_packet); h->write_buffer = realloc(h->write_buffer, h->max_packet); - if (h->read_buffer == 0 || h->write_buffer == 0) { + if (!h->read_buffer || !h->write_buffer) { LOG_ERROR("unable to reallocate memory"); return ERROR_FAIL; } @@ -675,7 +664,7 @@ static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) h = calloc(1, sizeof(struct icdi_usb_handle_s)); - if (h == 0) { + if (!h) { LOG_ERROR("unable to allocate memory"); return ERROR_FAIL; } @@ -686,7 +675,7 @@ static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) /* TI (Stellaris) ICDI provides its serial number in the USB descriptor; no need to provide a callback here. */ - jtag_libusb_open(param->vid, param->pid, &h->usb_dev, NULL); + jtag_libusb_open(param->vid, param->pid, NULL, &h->usb_dev, NULL); if (!h->usb_dev) { LOG_ERROR("open failed"); @@ -723,7 +712,7 @@ static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) h->write_buffer = malloc(ICDI_PACKET_SIZE); h->max_packet = ICDI_PACKET_SIZE; - if (h->read_buffer == 0 || h->write_buffer == 0) { + if (!h->read_buffer || !h->write_buffer) { LOG_DEBUG("malloc failed"); goto error_open; } diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index 50609a64b1..4f23c6c7fa 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011-2013 by Martin Schmoelzer * * <martin.schmoelzer@student.tuwien.ac.at> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -238,7 +227,7 @@ static int ulink_post_process_scan(struct ulink_cmd *ulink_cmd); static int ulink_post_process_queue(struct ulink *device); /* adapter driver functions */ -static int ulink_execute_queue(void); +static int ulink_execute_queue(struct jtag_command *cmd_queue); static int ulink_khz(int khz, int *jtag_speed); static int ulink_speed(int speed); static int ulink_speed_div(int speed, int *khz); @@ -1916,9 +1905,9 @@ static int ulink_post_process_queue(struct ulink *device) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -static int ulink_execute_queue(void) +static int ulink_execute_queue(struct jtag_command *cmd_queue) { - struct jtag_command *cmd = jtag_command_queue; + struct jtag_command *cmd = cmd_queue; int ret; while (cmd) { diff --git a/src/jtag/drivers/usb_blaster/Makefile.am b/src/jtag/drivers/usb_blaster/Makefile.am index a6694c5437..0fb8a07f1f 100644 --- a/src/jtag/drivers/usb_blaster/Makefile.am +++ b/src/jtag/drivers/usb_blaster/Makefile.am @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libocdusbblaster.la %C%_libocdusbblaster_la_SOURCES = $(USB_BLASTER_SRC) %C%_libocdusbblaster_la_CPPFLAGS = -I$(top_srcdir)/src/jtag/drivers $(AM_CPPFLAGS) $(LIBUSB1_CFLAGS) $(LIBFTDI_CFLAGS) diff --git a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c index 21f9ae72ba..de0d2d8472 100644 --- a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c +++ b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Driver for USB-JTAG, Altera USB-Blaster II and compatibles * * Copyright (C) 2013 Franck Jullien franck.jullien@gmail.com * - * 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/>. - * */ #ifdef HAVE_CONFIG_H @@ -114,7 +103,8 @@ static int ublast2_write_firmware_section(struct libusb_device_handle *libusb_de 0, (char *)data_ptr, chunk_size, - 100); + 100, + NULL); bytes_remaining -= chunk_size; addr += chunk_size; @@ -165,7 +155,8 @@ static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev, 0, &value, 1, - 100); + 100, + NULL); /* Download all sections in the image to ULINK */ for (unsigned int i = 0; i < ublast2_firmware_image.num_sections; i++) { @@ -186,7 +177,8 @@ static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev, 0, &value, 1, - 100); + 100, + NULL); error_close_firmware: image_close(&ublast2_firmware_image); @@ -210,7 +202,7 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low) bool renumeration = false; int ret; - if (jtag_libusb_open(vids, pids, &temp, NULL) == ERROR_OK) { + if (jtag_libusb_open(vids, pids, NULL, &temp, NULL) == ERROR_OK) { LOG_INFO("Altera USB-Blaster II (uninitialized) found"); LOG_INFO("Loading firmware..."); ret = load_usb_blaster_firmware(temp, low); @@ -224,13 +216,13 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low) const uint16_t pids_renum[] = { low->ublast_pid, 0 }; if (renumeration == false) { - if (jtag_libusb_open(vids_renum, pids_renum, &low->libusb_dev, NULL) != ERROR_OK) { + if (jtag_libusb_open(vids_renum, pids_renum, NULL, &low->libusb_dev, NULL) != ERROR_OK) { LOG_ERROR("Altera USB-Blaster II not found"); return ERROR_FAIL; } } else { int retry = 10; - while (jtag_libusb_open(vids_renum, pids_renum, &low->libusb_dev, NULL) != ERROR_OK && retry--) { + while (jtag_libusb_open(vids_renum, pids_renum, NULL, &low->libusb_dev, NULL) != ERROR_OK && retry--) { usleep(1000000); LOG_INFO("Waiting for reenumerate..."); } @@ -256,7 +248,8 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low) 0, buffer, 5, - 100); + 100, + NULL); LOG_INFO("Altera USB-Blaster II found (Firm. rev. = %s)", buffer); diff --git a/src/jtag/drivers/usb_blaster/ublast_access.h b/src/jtag/drivers/usb_blaster/ublast_access.h index ada764c1c1..3e138bd23b 100644 --- a/src/jtag/drivers/usb_blaster/ublast_access.h +++ b/src/jtag/drivers/usb_blaster/ublast_access.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Driver for USB-JTAG, Altera USB-Blaster and compatibles * @@ -10,19 +12,6 @@ * Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca * Copyright (C) 2006 Kolja Waschk usbjtag@ixo.de * - * 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/>. - * */ #ifndef OPENOCD_JTAG_DRIVERS_USB_BLASTER_UBLAST_ACCESS_H diff --git a/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c b/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c index cb442f2b5f..eb312ef4ee 100644 --- a/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c +++ b/src/jtag/drivers/usb_blaster/ublast_access_ftdi.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Driver for USB-JTAG, Altera USB-Blaster and compatibles * @@ -9,19 +11,6 @@ * Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca * Copyright (C) 2006 Kolja Waschk usbjtag@ixo.de * - * 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/>. - * */ #ifdef HAVE_CONFIG_H diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c index 049a24378b..c84055c4a1 100644 --- a/src/jtag/drivers/usb_blaster/usb_blaster.c +++ b/src/jtag/drivers/usb_blaster/usb_blaster.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Driver for USB-JTAG, Altera USB-Blaster and compatibles * @@ -10,19 +12,6 @@ * Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca * Copyright (C) 2006 Kolja Waschk usbjtag@ixo.de * - * 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/>. - * */ /* @@ -776,7 +765,7 @@ static void ublast_initial_wipeout(void) tap_set_state(TAP_RESET); } -static int ublast_execute_queue(void) +static int ublast_execute_queue(struct jtag_command *cmd_queue) { struct jtag_command *cmd; static int first_call = 1; @@ -787,7 +776,7 @@ static int ublast_execute_queue(void) ublast_initial_wipeout(); } - for (cmd = jtag_command_queue; ret == ERROR_OK && cmd; + for (cmd = cmd_queue; ret == ERROR_OK && cmd; cmd = cmd->next) { switch (cmd->type) { case JTAG_RESET: diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c index a2ebdbc86a..2d666d0728 100644 --- a/src/jtag/drivers/usbprog.c +++ b/src/jtag/drivers/usbprog.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Benedikt Sauter * * sauter@ixbat.de * - * * - * 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/>. * ***************************************************************************/ /* @@ -94,9 +83,9 @@ static void usbprog_jtag_write_slice(struct usbprog_jtag *usbprog_jtag, unsigned static void usbprog_jtag_set_bit(struct usbprog_jtag *usbprog_jtag, int bit, int value); /* static int usbprog_jtag_get_bit(struct usbprog_jtag *usbprog_jtag, int bit); */ -static int usbprog_execute_queue(void) +static int usbprog_execute_queue(struct jtag_command *cmd_queue) { - struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ + struct jtag_command *cmd = cmd_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; @@ -159,7 +148,7 @@ static int usbprog_init(void) usbprog_jtag_handle = usbprog_jtag_open(); tms_chain_index = 0; - if (usbprog_jtag_handle == 0) { + if (!usbprog_jtag_handle) { LOG_ERROR("Can't find USB JTAG Interface! Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; } @@ -346,15 +335,13 @@ static void usbprog_reset(int trst, int srst) /*************** jtag lowlevel functions ********************/ -struct usb_bus *busses; - struct usbprog_jtag *usbprog_jtag_open(void) { const uint16_t vids[] = { VID, 0 }; const uint16_t pids[] = { PID, 0 }; struct libusb_device_handle *dev; - if (jtag_libusb_open(vids, pids, &dev, NULL) != ERROR_OK) + if (jtag_libusb_open(vids, pids, NULL, &dev, NULL) != ERROR_OK) return NULL; struct usbprog_jtag *tmp = malloc(sizeof(struct usbprog_jtag)); diff --git a/src/jtag/drivers/vdebug.c b/src/jtag/drivers/vdebug.c index a81740cb18..f1fc4535f3 100644 --- a/src/jtag/drivers/vdebug.c +++ b/src/jtag/drivers/vdebug.c @@ -1,35 +1,14 @@ -/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ -/*---------------------------------------------------------------------------- - * Copyright 2020-2021 Cadence Design Systems, Inc. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - *---------------------------------------------------------------------------- - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------- -*/ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) + +/* Copyright 2020-2022 Cadence Design Systems, Inc. */ /*! * @file * * @brief the virtual debug interface provides a connection between a sw debugger - * and the simulated, emulated core over a soft connection, implemented by DPI - * The vdebug debug driver currently supports JTAG transport - * TODO: implement support and test big endian platforms + * and the simulated, emulated core. The openOCD client connects via TCP sockets + * with vdebug server and over DPI-based transactor with the emulation or simulation + * The vdebug debug driver supports JTAG and DAP-level transports * */ @@ -68,16 +47,18 @@ #include "jtag/interface.h" #include "jtag/commands.h" #include "transport/transport.h" +#include "target/arm_adi_v5.h" #include "helper/time_support.h" #include "helper/replacements.h" #include "helper/log.h" +#include "helper/list.h" -#define VD_VERSION 43 +#define VD_VERSION 48 #define VD_BUFFER_LEN 4024 #define VD_CHEADER_LEN 24 #define VD_SHEADER_LEN 16 -#define VD_MAX_MEMORIES 4 +#define VD_MAX_MEMORIES 20 #define VD_POLL_INTERVAL 500 #define VD_SCALE_PSTOMS 1000000000 @@ -85,7 +66,8 @@ * @brief List of transactor types */ enum { - VD_BFM_JTDP = 0x0001, /* transactor DAP JTAG DP */ + VD_BFM_TPIU = 0x0000, /* transactor trace TPIU */ + VD_BFM_DAP6 = 0x0001, /* transactor DAP ADI V6 */ VD_BFM_SWDP = 0x0002, /* transactor DAP SWD DP */ VD_BFM_AHB = 0x0003, /* transactor AMBA AHB */ VD_BFM_APB = 0x0004, /* transactor AMBA APB */ @@ -149,12 +131,21 @@ enum { VD_CMD_SIGSET = 0x0a, VD_CMD_SIGGET = 0x0b, VD_CMD_JTAGCLOCK = 0x0f, + VD_CMD_REGWRITE = 0x15, + VD_CMD_REGREAD = 0x16, VD_CMD_JTAGSHTAP = 0x1a, VD_CMD_MEMOPEN = 0x21, VD_CMD_MEMCLOSE = 0x22, VD_CMD_MEMWRITE = 0x23, }; +enum { + VD_ASPACE_AP = 0x01, + VD_ASPACE_DP = 0x02, + VD_ASPACE_ID = 0x03, + VD_ASPACE_AB = 0x04, +}; + enum { VD_BATCH_NO = 0, VD_BATCH_WO = 1, @@ -165,37 +156,32 @@ struct vd_shm { struct { /* VD_CHEADER_LEN written by client */ uint8_t cmd; /* 000; command */ uint8_t type; /* 001; interface type */ - uint16_t waddr; /* 002; write pointer */ - uint16_t wbytes; /* 004; data bytes */ - uint16_t rbytes; /* 006; data bytes to read */ - uint16_t wwords; /* 008; data words */ - uint16_t rwords; /* 00a; data words to read */ - uint32_t rwdata; /* 00c; read/write data */ - uint32_t offset; /* 010; address offset */ - uint16_t offseth; /* 014; address offset 47:32 */ - uint16_t wid; /* 016; request id*/ - }; - union { /* 018; */ - uint8_t wd8[VD_BUFFER_LEN]; - uint16_t wd16[VD_BUFFER_LEN / 2]; - uint32_t wd32[VD_BUFFER_LEN / 4]; - uint64_t wd64[VD_BUFFER_LEN / 8]; + uint8_t waddr[2]; /* 002; write pointer */ + uint8_t wbytes[2]; /* 004; data bytes */ + uint8_t rbytes[2]; /* 006; data bytes to read */ + uint8_t wwords[2]; /* 008; data words */ + uint8_t rwords[2]; /* 00a; data words to read */ + uint8_t rwdata[4]; /* 00c; read/write data */ + uint8_t offset[4]; /* 010; address offset */ + uint8_t offseth[2]; /* 014; address offset 47:32 */ + uint8_t wid[2]; /* 016; request id*/ }; + uint8_t wd8[VD_BUFFER_LEN]; /* 018; */ struct { /* VD_SHEADER_LEN written by server */ - uint16_t rid; /* fd0: request id read */ - uint16_t awords; /* fd2: actual data words read back */ - int32_t status; /* fd4; */ - uint64_t duttime; /* fd8; */ - }; - union { /* fe0: */ - uint8_t rd8[VD_BUFFER_LEN]; - uint16_t rd16[VD_BUFFER_LEN / 2]; - uint32_t rd32[VD_BUFFER_LEN / 4]; - uint64_t rd64[VD_BUFFER_LEN / 8]; + uint8_t rid[2]; /* fd0: request id read */ + uint8_t awords[2]; /* fd2: actual data words read back */ + uint8_t status[4]; /* fd4; */ + uint8_t duttime[8]; /* fd8; */ }; - uint32_t state; /* 1f98; connection state */ - uint32_t count; /* 1f9c; */ + uint8_t rd8[VD_BUFFER_LEN]; /* fe0: */ + uint8_t state[4]; /* 1f98; connection state */ + uint8_t count[4]; /* 1f9c; */ uint8_t dummy[96]; /* 1fa0; 48+40B+8B; */ +} __attribute__((packed)); + +struct vd_rdata { + struct list_head lh; + uint8_t *rdata; }; struct vd_client { @@ -222,7 +208,7 @@ struct vd_client { char server_name[32]; char bfm_path[128]; char mem_path[VD_MAX_MEMORIES][128]; - uint8_t *tdo; + struct vd_rdata rdataq; }; struct vd_jtag_hdr { @@ -234,6 +220,16 @@ struct vd_jtag_hdr { uint64_t rlen:16; }; +struct vd_reg_hdr { + uint64_t prot:3; + uint64_t nonincr:1; + uint64_t haddr:12; + uint64_t tlen:11; + uint64_t asize:3; + uint64_t cmd:2; + uint64_t addr:32; +}; + static struct vd_shm *pbuf; static struct vd_client vdc; @@ -258,6 +254,11 @@ static int vdebug_socket_open(char *server_addr, uint32_t port) hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (hsock == INVALID_SOCKET) rc = vdebug_socket_error(); +#elif defined __CYGWIN__ + /* SO_RCVLOWAT unsupported on CYGWIN */ + hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (hsock < 0) + rc = errno; #else uint32_t rcvwat = VD_SHEADER_LEN; /* size of the rcv header, as rcv min watermark */ hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); @@ -277,7 +278,7 @@ static int vdebug_socket_open(char *server_addr, uint32_t port) LOG_ERROR("socket_open: cannot resolve address %s, error %d", server_addr, vdebug_socket_error()); rc = VD_ERR_SOC_ADDR; } else { - ((struct sockaddr_in *)(ainfo->ai_addr))->sin_port = htons(port); + h_u16_to_be((uint8_t *)ainfo->ai_addr->sa_data, port); if (connect(hsock, ainfo->ai_addr, sizeof(struct sockaddr)) < 0) { LOG_ERROR("socket_open: cannot connect to %s:%d, error %d", server_addr, port, vdebug_socket_error()); rc = VD_ERR_SOC_CONN; @@ -299,8 +300,8 @@ static int vdebug_socket_receive(int hsock, struct vd_shm *pmem) { int rc; int dreceived = 0; - int offset = (uint8_t *)&pmem->rid - &pmem->cmd; - int to_receive = VD_SHEADER_LEN + pmem->rbytes; + int offset = &pmem->rid[0] - &pmem->cmd; + int to_receive = VD_SHEADER_LEN + le_to_h_u16(pmem->rbytes); char *pb = (char *)pmem; do { @@ -320,7 +321,7 @@ static int vdebug_socket_receive(int hsock, struct vd_shm *pmem) static int vdebug_socket_send(int hsock, struct vd_shm *pmem) { - int rc = send(hsock, (const char *)&pmem->cmd, VD_CHEADER_LEN + pmem->wbytes, 0); + int rc = send(hsock, (const char *)&pmem->cmd, VD_CHEADER_LEN + le_to_h_u16(pmem->wbytes), 0); if (rc <= 0) LOG_WARNING("socket_send: send failed, error %d", vdebug_socket_error()); else @@ -333,6 +334,7 @@ static uint32_t vdebug_wait_server(int hsock, struct vd_shm *pmem) { if (!hsock) return VD_ERR_SOC_OPEN; + int st = vdebug_socket_send(hsock, pmem); if (st <= 0) return VD_ERR_SOC_SEND; @@ -341,14 +343,14 @@ static uint32_t vdebug_wait_server(int hsock, struct vd_shm *pmem) if (rd <= 0) return VD_ERR_SOC_RECV; - int rc = pmem->status; + int rc = le_to_h_u32(pmem->status); LOG_DEBUG_IO("wait_server: cmd %02" PRIx8 " done, sent %d, rcvd %d, status %d", - pmem->cmd, st, rd, rc); + pmem->cmd, st, rd, rc); return rc; } -int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count) +static int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count) { uint8_t num_pre, num_post, tdi, tms; unsigned int num, anum, bytes, hwords, words; @@ -356,22 +358,23 @@ int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count) int64_t ts, te; uint8_t *tdo; int rc; - struct vd_jtag_hdr *hdr; + uint64_t jhdr; + struct vd_rdata *rd; req = 0; /* beginning of request */ waddr = 0; rwords = 0; - pm->wbytes = pm->wwords * vdc.buf_width; - pm->rbytes = pm->rwords * vdc.buf_width; + h_u16_to_le(pm->wbytes, le_to_h_u16(pm->wwords) * vdc.buf_width); + h_u16_to_le(pm->rbytes, le_to_h_u16(pm->rwords) * vdc.buf_width); ts = timeval_ms(); rc = vdebug_wait_server(hsock, pm); while (!rc && (req < count)) { /* loop over requests to read data and print out */ - hdr = (struct vd_jtag_hdr *)&pm->wd8[waddr * 4]; - hwords = hdr->wlen; - words = hdr->rlen; - anum = hdr->tlen; - num_pre = hdr->pre; - num_post = hdr->post; + jhdr = le_to_h_u64(&pm->wd8[waddr * 4]); + words = jhdr >> 48; + hwords = (jhdr >> 32) & 0xffff; + anum = jhdr & 0xffffff; + num_pre = (jhdr >> 27) & 0x7; + num_post = (jhdr >> 24) & 0x7; if (num_post) num = anum - num_pre - num_post + 1; else @@ -379,21 +382,29 @@ int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count) bytes = (num + 7) / 8; vdc.trans_last = (req + 1) < count ? 0 : 1; vdc.trans_first = waddr ? 0 : 1; - if (hdr->cmd == 3) { /* read */ - tdo = vdc.tdo; + if (((jhdr >> 30) & 0x3) == 3) { /* cmd is read */ + if (!rwords) { + rd = &vdc.rdataq; + tdo = rd->rdata; + } else { + rd = list_first_entry(&vdc.rdataq.lh, struct vd_rdata, lh); + tdo = rd->rdata; + list_del(&rd->lh); + free(rd); + } for (unsigned int j = 0; j < bytes; j++) { tdo[j] = (pm->rd8[rwords * 8 + j] >> num_pre) | (pm->rd8[rwords * 8 + j + 1] << (8 - num_pre)); - LOG_DEBUG_IO("%04x D0[%02x]:%02x", pm->wid - count + req, j, tdo[j]); + LOG_DEBUG_IO("%04x D0[%02x]:%02x", le_to_h_u16(pm->wid) - count + req, j, tdo[j]); } rwords += words; /* read data offset */ } else { tdo = NULL; } - waddr += sizeof(struct vd_jtag_hdr) / 4; /* waddr past header */ + waddr += sizeof(uint64_t) / 4; /* waddr past header */ tdi = (pm->wd8[waddr * 4] >> num_pre) | (pm->wd8[waddr * 4 + 1] << (8 - num_pre)); tms = (pm->wd8[waddr * 4 + 4] >> num_pre) | (pm->wd8[waddr * 4 + 4 + 1] << (8 - num_pre)); - LOG_DEBUG("%04x L:%02d O:%05x @%03x DI:%02x MS:%02x DO:%02x", - pm->wid - count + req, num, (vdc.trans_first << 14) | (vdc.trans_last << 15), + LOG_DEBUG_IO("%04x L:%02d O:%05x @%03x DI:%02x MS:%02x DO:%02x", + le_to_h_u16(pm->wid) - count + req, num, (vdc.trans_first << 14) | (vdc.trans_last << 15), waddr - 2, tdi, tms, (tdo ? tdo[0] : 0xdd)); waddr += hwords * 2; /* start of next request */ req += 1; @@ -406,10 +417,83 @@ int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count) te = timeval_ms(); vdc.targ_time += (uint32_t)(te - ts); - pm->offseth = 0; /* reset buffer write address */ - pm->offset = 0; - pm->rwords = 0; - pm->waddr = 0; + h_u16_to_le(pm->offseth, 0); /* reset buffer write address */ + h_u32_to_le(pm->offset, 0); + h_u16_to_le(pm->rwords, 0); + h_u16_to_le(pm->waddr, 0); + assert(list_empty(&vdc.rdataq.lh));/* list should be empty after run queue */ + + return rc; +} + +static int vdebug_run_reg_queue(int hsock, struct vd_shm *pm, unsigned int count) +{ + unsigned int num, awidth, wwidth; + unsigned int req, waddr, rwords; + uint8_t aspace; + uint32_t addr; + int64_t ts, te; + uint8_t *data; + int rc; + uint64_t rhdr; + struct vd_rdata *rd; + + req = 0; /* beginning of request */ + waddr = 0; + rwords = 0; + h_u16_to_le(pm->wbytes, le_to_h_u16(pm->wwords) * vdc.buf_width); + h_u16_to_le(pm->rbytes, le_to_h_u16(pm->rwords) * vdc.buf_width); + ts = timeval_ms(); + rc = vdebug_wait_server(hsock, pm); + while (!rc && (req < count)) { /* loop over requests to read data and print out */ + rhdr = le_to_h_u64(&pm->wd8[waddr * 4]); + addr = rhdr >> 32; /* reconstruct data for a single request */ + num = (rhdr >> 16) & 0x7ff; + aspace = rhdr & 0x3; + awidth = (1 << ((rhdr >> 27) & 0x7)); + wwidth = (awidth + vdc.buf_width - 1) / vdc.buf_width; + vdc.trans_last = (req + 1) < count ? 0 : 1; + vdc.trans_first = waddr ? 0 : 1; + if (((rhdr >> 30) & 0x3) == 2) { /* cmd is read */ + if (num) { + if (!rwords) { + rd = &vdc.rdataq; + data = rd->rdata; + } else { + rd = list_first_entry(&vdc.rdataq.lh, struct vd_rdata, lh); + data = rd->rdata; + list_del(&rd->lh); + free(rd); + } + for (unsigned int j = 0; j < num; j++) + memcpy(&data[j * awidth], &pm->rd8[(rwords + j) * awidth], awidth); + } + LOG_DEBUG("read %04x AS:%1x RG:%1x O:%05x @%03x D:%08x", le_to_h_u16(pm->wid) - count + req, + aspace, addr << 2, (vdc.trans_first << 14) | (vdc.trans_last << 15), waddr, + (num ? le_to_h_u32(&pm->rd8[rwords * 4]) : 0xdead)); + rwords += num * wwidth; + waddr += sizeof(uint64_t) / 4; /* waddr past header */ + } else { + LOG_DEBUG("write %04x AS:%1x RG:%1x O:%05x @%03x D:%08x", le_to_h_u16(pm->wid) - count + req, + aspace, addr << 2, (vdc.trans_first << 14) | (vdc.trans_last << 15), waddr, + le_to_h_u32(&pm->wd8[(waddr + num + 1) * 4])); + waddr += sizeof(uint64_t) / 4 + (num * wwidth * awidth + 3) / 4; + } + req += 1; + } + + if (rc) { + LOG_ERROR("0x%x executing transaction", rc); + rc = ERROR_FAIL; + } + + te = timeval_ms(); + vdc.targ_time += (uint32_t)(te - ts); + h_u16_to_le(pm->offseth, 0); /* reset buffer write address */ + h_u32_to_le(pm->offset, 0); + h_u16_to_le(pm->rwords, 0); + h_u16_to_le(pm->waddr, 0); + assert(list_empty(&vdc.rdataq.lh));/* list should be empty after run queue */ return rc; } @@ -420,35 +504,35 @@ static int vdebug_open(int hsock, struct vd_shm *pm, const char *path, int rc = VD_ERR_NOT_OPEN; pm->cmd = VD_CMD_OPEN; - pm->wid = VD_VERSION; /* client version */ - pm->wbytes = 0; - pm->rbytes = 0; - pm->wwords = 0; - pm->rwords = 0; + h_u16_to_le(pm->wid, VD_VERSION); /* client version */ + h_u16_to_le(pm->wbytes, 0); + h_u16_to_le(pm->rbytes, 0); + h_u16_to_le(pm->wwords, 0); + h_u16_to_le(pm->rwords, 0); rc = vdebug_wait_server(hsock, pm); if (rc != 0) { /* communication problem */ LOG_ERROR("0x%x connecting to server", rc); - } else if (pm->rid < pm->wid) { - LOG_ERROR("server version %d too old for the client %d", pm->rid, pm->wid); + } else if (le_to_h_u16(pm->rid) < le_to_h_u16(pm->wid)) { + LOG_ERROR("server version %d too old for the client %d", le_to_h_u16(pm->rid), le_to_h_u16(pm->wid)); pm->cmd = VD_CMD_CLOSE; /* let server close the connection */ vdebug_wait_server(hsock, pm); rc = VD_ERR_VERSION; } else { pm->cmd = VD_CMD_CONNECT; - pm->type = type; /* BFM type to connect to, here JTAG */ - pm->rwdata = sig_mask | VD_SIG_BUF | (VD_SIG_BUF << 16); - pm->wbytes = strlen(path) + 1; - pm->rbytes = 12; - pm->wid = 0; /* reset wid for transaction ID */ - pm->wwords = 0; - pm->rwords = 0; - memcpy(pm->wd8, path, pm->wbytes + 1); + pm->type = type; /* BFM type to connect to */ + h_u32_to_le(pm->rwdata, sig_mask | VD_SIG_BUF | (VD_SIG_BUF << 16)); + h_u16_to_le(pm->wbytes, strlen(path) + 1); + h_u16_to_le(pm->rbytes, 12); + h_u16_to_le(pm->wid, 0); /* reset wid for transaction ID */ + h_u16_to_le(pm->wwords, 0); + h_u16_to_le(pm->rwords, 0); + memcpy(pm->wd8, path, le_to_h_u16(pm->wbytes)); rc = vdebug_wait_server(hsock, pm); - vdc.sig_read = pm->rwdata >> 16; /* signal read mask */ - vdc.sig_write = pm->rwdata; /* signal write mask */ + vdc.sig_read = le_to_h_u32(pm->rwdata) >> 16; /* signal read mask */ + vdc.sig_write = le_to_h_u32(pm->rwdata); /* signal write mask */ vdc.bfm_period = period_ps; - vdc.buf_width = pm->rd32[0] / 8;/* access width in bytes */ - vdc.addr_bits = pm->rd32[2]; /* supported address bits */ + vdc.buf_width = le_to_h_u32(&pm->rd8[0]) / 8;/* access width in bytes */ + vdc.addr_bits = le_to_h_u32(&pm->rd8[2 * 4]); /* supported address bits */ } if (rc) { @@ -456,6 +540,7 @@ static int vdebug_open(int hsock, struct vd_shm *pm, const char *path, return ERROR_FAIL; } + INIT_LIST_HEAD(&vdc.rdataq.lh); LOG_DEBUG("%s type %0x, period %dps, buffer %dx%dB signals r%04xw%04x", path, type, vdc.bfm_period, VD_BUFFER_LEN / vdc.buf_width, vdc.buf_width, vdc.sig_read, vdc.sig_write); @@ -467,17 +552,17 @@ static int vdebug_close(int hsock, struct vd_shm *pm, uint8_t type) { pm->cmd = VD_CMD_DISCONNECT; pm->type = type; /* BFM type, here JTAG */ - pm->wbytes = 0; - pm->rbytes = 0; - pm->wwords = 0; - pm->rwords = 0; + h_u16_to_le(pm->wbytes, 0); + h_u16_to_le(pm->rbytes, 0); + h_u16_to_le(pm->wwords, 0); + h_u16_to_le(pm->rwords, 0); vdebug_wait_server(hsock, pm); pm->cmd = VD_CMD_CLOSE; - pm->wid = VD_VERSION; /* client version */ - pm->wbytes = 0; - pm->rbytes = 0; - pm->wwords = 0; - pm->rwords = 0; + h_u16_to_le(pm->wid, VD_VERSION); /* client version */ + h_u16_to_le(pm->wbytes, 0); + h_u16_to_le(pm->rbytes, 0); + h_u16_to_le(pm->wwords, 0); + h_u16_to_le(pm->rwords, 0); vdebug_wait_server(hsock, pm); LOG_DEBUG("type %0x", type); @@ -488,9 +573,9 @@ static int vdebug_wait(int hsock, struct vd_shm *pm, uint32_t cycles) { if (cycles) { pm->cmd = VD_CMD_WAIT; - pm->wbytes = 0; - pm->rbytes = 0; - pm->rwdata = cycles; /* clock sycles to wait */ + h_u16_to_le(pm->wbytes, 0); + h_u16_to_le(pm->rbytes, 0); + h_u32_to_le(pm->rwdata, cycles); /* clock sycles to wait */ int rc = vdebug_wait_server(hsock, pm); if (rc) { LOG_ERROR("0x%x waiting %" PRIx32 " cycles", rc, cycles); @@ -505,9 +590,9 @@ static int vdebug_wait(int hsock, struct vd_shm *pm, uint32_t cycles) static int vdebug_sig_set(int hsock, struct vd_shm *pm, uint32_t write_mask, uint32_t value) { pm->cmd = VD_CMD_SIGSET; - pm->wbytes = 0; - pm->rbytes = 0; - pm->rwdata = (write_mask << 16) | (value & 0xffff); /* mask and value of signals to set */ + h_u16_to_le(pm->wbytes, 0); + h_u16_to_le(pm->rbytes, 0); + h_u32_to_le(pm->rwdata, (write_mask << 16) | (value & 0xffff)); /* mask and value of signals to set */ int rc = vdebug_wait_server(hsock, pm); if (rc) { LOG_ERROR("0x%x setting signals %04" PRIx32, rc, write_mask); @@ -522,9 +607,9 @@ static int vdebug_sig_set(int hsock, struct vd_shm *pm, uint32_t write_mask, uin static int vdebug_jtag_clock(int hsock, struct vd_shm *pm, uint32_t value) { pm->cmd = VD_CMD_JTAGCLOCK; - pm->wbytes = 0; - pm->rbytes = 0; - pm->rwdata = value; /* divider value */ + h_u16_to_le(pm->wbytes, 0); + h_u16_to_le(pm->rbytes, 0); + h_u32_to_le(pm->rwdata, value); /* divider value */ int rc = vdebug_wait_server(hsock, pm); if (rc) { LOG_ERROR("0x%x setting jtag_clock", rc); @@ -546,11 +631,11 @@ static int vdebug_jtag_shift_tap(int hsock, struct vd_shm *pm, uint8_t num_pre, int rc = 0; pm->cmd = VD_CMD_JTAGSHTAP; - vdc.trans_last = f_last || (vdc.trans_batch == VD_BATCH_NO) || tdo; + vdc.trans_last = f_last || (vdc.trans_batch == VD_BATCH_NO); if (vdc.trans_first) waddr = 0; /* reset buffer offset */ else - waddr = pm->offseth; /* continue from the previous transaction */ + waddr = le_to_h_u32(pm->offseth); /* continue from the previous transaction */ if (num_post) /* actual number of bits to shift */ anum = num + num_pre + num_post - 1; else @@ -559,25 +644,22 @@ static int vdebug_jtag_shift_tap(int hsock, struct vd_shm *pm, uint8_t num_pre, words = (hwords + 1) / 2; /* in 8B TDO words to read */ bytes = (num + 7) / 8; /* data only portion in bytes */ /* buffer overflow check and flush */ - if (4 * waddr + sizeof(struct vd_jtag_hdr) + 8 * hwords + 64 > VD_BUFFER_LEN) { + if (4 * waddr + sizeof(uint64_t) + 8 * hwords + 64 > VD_BUFFER_LEN) { vdc.trans_last = 1; /* force flush within 64B of buffer end */ - } else if (4 * waddr + sizeof(struct vd_jtag_hdr) + 8 * hwords > VD_BUFFER_LEN) { + } else if (4 * waddr + sizeof(uint64_t) + 8 * hwords > VD_BUFFER_LEN) { /* this req does not fit, discard it */ LOG_ERROR("%04x L:%02d O:%05x @%04x too many bits to shift", - pm->wid, anum, (vdc.trans_first << 14) | (vdc.trans_last << 15), waddr); + le_to_h_u16(pm->wid), anum, (vdc.trans_first << 14) | (vdc.trans_last << 15), waddr); rc = ERROR_FAIL; } if (!rc && anum) { - uint16_t i, j; - struct vd_jtag_hdr *hdr = (struct vd_jtag_hdr *)&pm->wd8[4 * waddr]; /* 8 bytes header */ - hdr->cmd = (tdo ? 3 : 1); /* R and W bits */ - hdr->pre = num_pre; - hdr->post = num_post; - hdr->tlen = anum; - hdr->wlen = hwords; - hdr->rlen = words; - pm->wid++; /* transaction ID */ + uint16_t i, j; /* portability requires to use bit operations for 8B JTAG header */ + uint64_t jhdr = (tdo ? ((uint64_t)(words) << 48) : 0) + ((uint64_t)(hwords) << 32) + + ((tdo ? 3UL : 1UL) << 30) + (num_pre << 27) + (num_post << 24) + anum; + h_u64_to_le(&pm->wd8[4 * waddr], jhdr); + + h_u16_to_le(pm->wid, le_to_h_u16(pm->wid) + 1); /* transaction ID */ waddr += 2; /* waddr past header */ /* TDI/TMS data follows as 32 bit word pairs {TMS,TDI} */ pm->wd8[4 * waddr] = (tdi ? (tdi[0] << num_pre) : 0); @@ -615,19 +697,102 @@ static int vdebug_jtag_shift_tap(int hsock, struct vd_shm *pm, uint8_t num_pre, } if (tdo) { - pm->rwords += words; /* keep track of the words to read */ - vdc.tdo = tdo; + struct vd_rdata *rd; + if (le_to_h_u16(pm->rwords) == 0) { + rd = &vdc.rdataq; + } else { + rd = calloc(1, sizeof(struct vd_rdata)); + if (!rd) /* check allocation for 24B */ + return ERROR_FAIL; + list_add_tail(&rd->lh, &vdc.rdataq.lh); + } + rd->rdata = tdo; + h_u16_to_le(pm->rwords, le_to_h_u16(pm->rwords) + words);/* keep track of the words to read */ } - pm->wwords = waddr / 2 + hwords; /* payload size *2 to include both TDI and TMS data */ - pm->waddr++; + h_u16_to_le(pm->wwords, waddr / 2 + hwords); /* payload size *2 to include both TDI and TMS data */ + h_u16_to_le(pm->waddr, le_to_h_u16(pm->waddr) + 1); } if (!waddr) /* flush issued, but buffer empty */ ; else if (!vdc.trans_last) /* buffered request */ - pm->offseth = waddr + hwords * 2; /* offset for next transaction, must be even */ + h_u16_to_le(pm->offseth, waddr + hwords * 2); /* offset for next transaction, must be even */ else /* execute batch of requests */ - rc = vdebug_run_jtag_queue(hsock, pm, pm->waddr); + rc = vdebug_run_jtag_queue(hsock, pm, le_to_h_u16(pm->waddr)); + vdc.trans_first = vdc.trans_last; /* flush forces trans_first flag */ + + return rc; +} + +static int vdebug_reg_write(int hsock, struct vd_shm *pm, const uint32_t reg, + const uint32_t data, uint8_t aspace, uint8_t f_last) +{ + uint32_t waddr; + int rc = ERROR_OK; + + pm->cmd = VD_CMD_REGWRITE; + vdc.trans_last = f_last || (vdc.trans_batch == VD_BATCH_NO); + if (vdc.trans_first) + waddr = 0; /* reset buffer offset */ + else + waddr = le_to_h_u16(pm->offseth); /* continue from the previous transaction */ + + if (4 * waddr + 2 * sizeof(uint64_t) + 4 > VD_BUFFER_LEN) + vdc.trans_last = 1; /* force flush, no room for next request */ + + uint64_t rhdr = ((uint64_t)reg << 32) + (1UL << 30) + (2UL << 27) + (1UL << 16) + aspace; + h_u64_to_le(&pm->wd8[4 * waddr], rhdr); + h_u32_to_le(&pm->wd8[4 * (waddr + 2)], data); + h_u16_to_le(pm->wid, le_to_h_u16(pm->wid) + 1); + h_u16_to_le(pm->wwords, waddr + 3); + h_u16_to_le(pm->waddr, le_to_h_u16(pm->waddr) + 1); + if (!vdc.trans_last) /* buffered request */ + h_u16_to_le(pm->offseth, waddr + 3); + else + rc = vdebug_run_reg_queue(hsock, pm, le_to_h_u16(pm->waddr)); + vdc.trans_first = vdc.trans_last; /* flush forces trans_first flag */ + + return rc; +} + +static int vdebug_reg_read(int hsock, struct vd_shm *pm, const uint32_t reg, + uint32_t *data, uint8_t aspace, uint8_t f_last) +{ + uint32_t waddr; + int rc = ERROR_OK; + + pm->cmd = VD_CMD_REGREAD; + vdc.trans_last = f_last || (vdc.trans_batch == VD_BATCH_NO); + if (vdc.trans_first) + waddr = 0; /* reset buffer offset */ + else + waddr = le_to_h_u16(pm->offseth); /* continue from the previous transaction */ + + if (4 * waddr + 2 * sizeof(uint64_t) + 4 > VD_BUFFER_LEN) + vdc.trans_last = 1; /* force flush, no room for next request */ + + uint64_t rhdr = ((uint64_t)reg << 32) + (2UL << 30) + (2UL << 27) + ((data ? 1UL : 0UL) << 16) + aspace; + h_u64_to_le(&pm->wd8[4 * waddr], rhdr); + h_u16_to_le(pm->wid, le_to_h_u16(pm->wid) + 1); + if (data) { + struct vd_rdata *rd; + if (le_to_h_u16(pm->rwords) == 0) { + rd = &vdc.rdataq; + } else { + rd = calloc(1, sizeof(struct vd_rdata)); + if (!rd) /* check allocation for 24B */ + return ERROR_FAIL; + list_add_tail(&rd->lh, &vdc.rdataq.lh); + } + rd->rdata = (uint8_t *)data; + h_u16_to_le(pm->rwords, le_to_h_u16(pm->rwords) + 1); + } + h_u16_to_le(pm->wwords, waddr + 2); + h_u16_to_le(pm->waddr, le_to_h_u16(pm->waddr) + 1); + if (!vdc.trans_last) /* buffered request */ + h_u16_to_le(pm->offseth, waddr + 2); + else + rc = vdebug_run_reg_queue(hsock, pm, le_to_h_u16(pm->waddr)); vdc.trans_first = vdc.trans_last; /* flush forces trans_first flag */ return rc; @@ -641,19 +806,19 @@ static int vdebug_mem_open(int hsock, struct vd_shm *pm, const char *path, uint8 return ERROR_OK; pm->cmd = VD_CMD_MEMOPEN; - pm->wbytes = strlen(path) + 1; /* includes terminating 0 */ - pm->rbytes = 8; - pm->wwords = 0; - pm->rwords = 0; - memcpy(pm->wd8, path, pm->wbytes); + h_u16_to_le(pm->wbytes, strlen(path) + 1); /* includes terminating 0 */ + h_u16_to_le(pm->rbytes, 8); + h_u16_to_le(pm->wwords, 0); + h_u16_to_le(pm->rwords, 0); + memcpy(pm->wd8, path, le_to_h_u16(pm->wbytes)); rc = vdebug_wait_server(hsock, pm); if (rc) { LOG_ERROR("0x%x opening memory %s", rc, path); - } else if (ndx != pm->rd16[1]) { - LOG_WARNING("Invalid memory index %" PRIu16 " returned. Direct memory access disabled", pm->rd16[1]); + } else if (ndx != pm->rd8[2]) { + LOG_WARNING("Invalid memory index %" PRIu16 " returned. Direct memory access disabled", pm->rd8[2]); } else { - vdc.mem_width[ndx] = pm->rd16[0] / 8; /* memory width in bytes */ - vdc.mem_depth[ndx] = pm->rd32[1]; /* memory depth in words */ + vdc.mem_width[ndx] = le_to_h_u16(&pm->rd8[0]) / 8; /* memory width in bytes */ + vdc.mem_depth[ndx] = le_to_h_u32(&pm->rd8[4]); /* memory depth in words */ LOG_DEBUG("%" PRIx8 ": %s memory %" PRIu32 "x%" PRIu32 "B, buffer %" PRIu32 "x%" PRIu32 "B", ndx, path, vdc.mem_depth[ndx], vdc.mem_width[ndx], VD_BUFFER_LEN / vdc.mem_width[ndx], vdc.mem_width[ndx]); } @@ -664,15 +829,16 @@ static int vdebug_mem_open(int hsock, struct vd_shm *pm, const char *path, uint8 static void vdebug_mem_close(int hsock, struct vd_shm *pm, uint8_t ndx) { pm->cmd = VD_CMD_MEMCLOSE; - pm->rwdata = ndx; /* which memory */ - pm->wbytes = 0; - pm->rbytes = 0; - pm->wwords = 0; - pm->rwords = 0; + h_u32_to_le(pm->rwdata, ndx); /* which memory */ + h_u16_to_le(pm->wbytes, 0); + h_u16_to_le(pm->rbytes, 0); + h_u16_to_le(pm->wwords, 0); + h_u16_to_le(pm->rwords, 0); vdebug_wait_server(hsock, pm); LOG_DEBUG("%" PRIx8 ": %s", ndx, vdc.mem_path[ndx]); } + static int vdebug_init(void) { vdc.hsocket = vdebug_socket_open(vdc.server_name, vdc.server_port); @@ -680,7 +846,7 @@ static int vdebug_init(void) if (!pbuf) { close_socket(vdc.hsocket); vdc.hsocket = 0; - LOG_ERROR("cannot allocate %lu bytes", sizeof(struct vd_shm)); + LOG_ERROR("cannot allocate %zu bytes", sizeof(struct vd_shm)); return ERROR_FAIL; } if (vdc.hsocket <= 0) { @@ -692,10 +858,13 @@ static int vdebug_init(void) } vdc.trans_first = 1; vdc.poll_cycles = vdc.poll_max; - uint32_t sig_mask = VD_SIG_RESET | VD_SIG_TRST | VD_SIG_TCKDIV; + uint32_t sig_mask = VD_SIG_RESET; + if (transport_is_jtag()) + sig_mask |= VD_SIG_TRST | VD_SIG_TCKDIV; + int rc = vdebug_open(vdc.hsocket, pbuf, vdc.bfm_path, vdc.bfm_type, vdc.bfm_period, sig_mask); if (rc != 0) { - LOG_ERROR("cannot connect to %s, rc 0x%x", vdc.bfm_path, rc); + LOG_ERROR("0x%x cannot connect to %s", rc, vdc.bfm_path); close_socket(vdc.hsocket); vdc.hsocket = 0; free(pbuf); @@ -704,7 +873,7 @@ static int vdebug_init(void) for (uint8_t i = 0; i < vdc.mem_ndx; i++) { rc = vdebug_mem_open(vdc.hsocket, pbuf, vdc.mem_path[i], i); if (rc != 0) - LOG_ERROR("cannot connect to %s, rc 0x%x", vdc.mem_path[i], rc); + LOG_ERROR("0x%x cannot connect to %s", rc, vdc.mem_path[i]); } LOG_INFO("vdebug %d connected to %s through %s:%" PRIu16, @@ -754,7 +923,7 @@ static int vdebug_reset(int trst, int srst) static int vdebug_jtag_tms_seq(const uint8_t *tms, int num, uint8_t f_flush) { - LOG_INFO("tms len:%d tms:%x", num, *(const uint32_t *)tms); + LOG_DEBUG_IO("tms len:%d tms:%x", num, *tms); return vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num, *tms, 0, NULL, 0, 0, NULL, f_flush); } @@ -762,7 +931,7 @@ static int vdebug_jtag_tms_seq(const uint8_t *tms, int num, uint8_t f_flush) static int vdebug_jtag_path_move(struct pathmove_command *cmd, uint8_t f_flush) { uint8_t tms[DIV_ROUND_UP(cmd->num_states, 8)]; - LOG_INFO("path num states %d", cmd->num_states); + LOG_DEBUG_IO("path num states %d", cmd->num_states); memset(tms, 0, DIV_ROUND_UP(cmd->num_states, 8)); @@ -779,10 +948,10 @@ static int vdebug_jtag_tlr(tap_state_t state, uint8_t f_flush) { int rc = ERROR_OK; - uint8_t cur = tap_get_state(); + tap_state_t cur = tap_get_state(); uint8_t tms_pre = tap_get_tms_path(cur, state); uint8_t num_pre = tap_get_tms_path_len(cur, state); - LOG_INFO("tlr from %" PRIx8 " to %" PRIx8, cur, state); + LOG_DEBUG_IO("tlr from %x to %x", cur, state); if (cur != state) { rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, 0, NULL, 0, 0, NULL, f_flush); tap_set_state(state); @@ -795,14 +964,14 @@ static int vdebug_jtag_scan(struct scan_command *cmd, uint8_t f_flush) { int rc = ERROR_OK; - uint8_t cur = tap_get_state(); + tap_state_t cur = tap_get_state(); uint8_t state = cmd->ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT; uint8_t tms_pre = tap_get_tms_path(cur, state); uint8_t num_pre = tap_get_tms_path_len(cur, state); uint8_t tms_post = tap_get_tms_path(state, cmd->end_state); uint8_t num_post = tap_get_tms_path_len(state, cmd->end_state); int num_bits = jtag_scan_size(cmd); - LOG_DEBUG("scan len:%d fields:%d ir/!dr:%d state cur:%x end:%x", + LOG_DEBUG_IO("scan len:%d fields:%d ir/!dr:%d state cur:%x end:%x", num_bits, cmd->num_fields, cmd->ir_scan, cur, cmd->end_state); for (int i = 0; i < cmd->num_fields; i++) { uint8_t cur_num_pre = i == 0 ? num_pre : 0; @@ -811,8 +980,8 @@ static int vdebug_jtag_scan(struct scan_command *cmd, uint8_t f_flush) uint8_t cur_tms_post = i == cmd->num_fields - 1 ? tms_post : 0; uint8_t cur_flush = i == cmd->num_fields - 1 ? f_flush : 0; rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, cur_num_pre, cur_tms_pre, - cmd->fields[i].num_bits, cmd->fields[i].out_value, cur_num_post, cur_tms_post, - cmd->fields[i].in_value, cur_flush); + cmd->fields[i].num_bits, cmd->fields[i].out_value, cur_num_post, cur_tms_post, + cmd->fields[i].in_value, cur_flush); if (rc) break; } @@ -825,10 +994,10 @@ static int vdebug_jtag_scan(struct scan_command *cmd, uint8_t f_flush) static int vdebug_jtag_runtest(int cycles, tap_state_t state, uint8_t f_flush) { - uint8_t cur = tap_get_state(); + tap_state_t cur = tap_get_state(); uint8_t tms_pre = tap_get_tms_path(cur, state); uint8_t num_pre = tap_get_tms_path_len(cur, state); - LOG_DEBUG("idle len:%d state cur:%x end:%x", cycles, cur, state); + LOG_DEBUG_IO("idle len:%d state cur:%x end:%x", cycles, cur, state); int rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, cycles, NULL, 0, 0, NULL, f_flush); if (cur != state) tap_set_state(state); @@ -838,7 +1007,7 @@ static int vdebug_jtag_runtest(int cycles, tap_state_t state, uint8_t f_flush) static int vdebug_jtag_stableclocks(int num, uint8_t f_flush) { - LOG_INFO("stab len:%d state cur:%x", num, tap_get_state()); + LOG_DEBUG("stab len:%d state cur:%x", num, tap_get_state()); return vdebug_jtag_shift_tap(vdc.hsocket, pbuf, 0, 0, num, NULL, 0, 0, NULL, f_flush); } @@ -877,11 +1046,11 @@ static int vdebug_jtag_div(int speed, int *khz) return ERROR_OK; } -static int vdebug_jtag_execute_queue(void) +static int vdebug_jtag_execute_queue(struct jtag_command *cmd_queue) { int rc = ERROR_OK; - for (struct jtag_command *cmd = jtag_command_queue; rc == ERROR_OK && cmd; cmd = cmd->next) { + for (struct jtag_command *cmd = cmd_queue; rc == ERROR_OK && cmd; cmd = cmd->next) { switch (cmd->type) { case JTAG_RUNTEST: rc = vdebug_jtag_runtest(cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state, !cmd->next); @@ -913,6 +1082,101 @@ static int vdebug_jtag_execute_queue(void) return rc; } +static int vdebug_dap_bankselect(struct adiv5_ap *ap, unsigned int reg) +{ + int rc = ERROR_OK; + uint64_t sel; + + if (is_adiv6(ap->dap)) { + sel = ap->ap_num | (reg & 0x00000FF0); + if (sel != (ap->dap->select & ~0xfull)) { + sel |= ap->dap->select & DP_SELECT_DPBANK; + if (ap->dap->asize > 32) + sel |= (DP_SELECT1 >> 4) & DP_SELECT_DPBANK; + ap->dap->select = sel; + ap->dap->select_valid = true; + rc = vdebug_reg_write(vdc.hsocket, pbuf, DP_SELECT >> 2, (uint32_t)sel, VD_ASPACE_DP, 0); + if (rc == ERROR_OK) { + ap->dap->select_valid = true; + if (ap->dap->asize > 32) + rc = vdebug_reg_write(vdc.hsocket, pbuf, (DP_SELECT1 & DP_SELECT_DPBANK) >> 2, + (uint32_t)(sel >> 32), VD_ASPACE_DP, 0); + if (rc == ERROR_OK) + ap->dap->select1_valid = true; + } + } + } else { /* ADIv5 */ + sel = (ap->ap_num << 24) | (reg & ADIV5_DP_SELECT_APBANK); + if (sel != ap->dap->select) { + ap->dap->select = sel; + rc = vdebug_reg_write(vdc.hsocket, pbuf, DP_SELECT >> 2, (uint32_t)sel, VD_ASPACE_DP, 0); + if (rc == ERROR_OK) + ap->dap->select_valid = true; + } + } + return rc; +} + +static int vdebug_dap_connect(struct adiv5_dap *dap) +{ + return dap_dp_init(dap); +} + +static int vdebug_dap_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq) +{ + return ERROR_OK; +} + +static int vdebug_dap_queue_dp_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *data) +{ + if (reg != DP_SELECT && reg != DP_RDBUFF + && (!dap->select_valid || ((reg >> 4) & DP_SELECT_DPBANK) != (dap->select & DP_SELECT_DPBANK))) { + dap->select = (dap->select & ~DP_SELECT_DPBANK) | ((reg >> 4) & DP_SELECT_DPBANK); + vdebug_reg_write(vdc.hsocket, pbuf, DP_SELECT >> 2, dap->select, VD_ASPACE_DP, 0); + dap->select_valid = true; + } + return vdebug_reg_read(vdc.hsocket, pbuf, (reg & DP_SELECT_DPBANK) >> 2, data, VD_ASPACE_DP, 0); +} + +static int vdebug_dap_queue_dp_write(struct adiv5_dap *dap, unsigned int reg, uint32_t data) +{ + if (reg != DP_SELECT && reg != DP_RDBUFF + && (!dap->select_valid || ((reg >> 4) & DP_SELECT_DPBANK) != (dap->select & DP_SELECT_DPBANK))) { + dap->select = (dap->select & ~DP_SELECT_DPBANK) | ((reg >> 4) & DP_SELECT_DPBANK); + vdebug_reg_write(vdc.hsocket, pbuf, DP_SELECT >> 2, dap->select, VD_ASPACE_DP, 0); + dap->select_valid = true; + } + return vdebug_reg_write(vdc.hsocket, pbuf, (reg & DP_SELECT_DPBANK) >> 2, data, VD_ASPACE_DP, 0); +} + +static int vdebug_dap_queue_ap_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data) +{ + vdebug_dap_bankselect(ap, reg); + + vdebug_reg_read(vdc.hsocket, pbuf, (reg & DP_SELECT_DPBANK) >> 2, NULL, VD_ASPACE_AP, 0); + + return vdebug_reg_read(vdc.hsocket, pbuf, DP_RDBUFF >> 2, data, VD_ASPACE_DP, 0); +} + +static int vdebug_dap_queue_ap_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data) +{ + vdebug_dap_bankselect(ap, reg); + return vdebug_reg_write(vdc.hsocket, pbuf, (reg & DP_SELECT_DPBANK) >> 2, data, VD_ASPACE_AP, 0); +} + +static int vdebug_dap_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) +{ + return vdebug_reg_write(vdc.hsocket, pbuf, 0, 0x1, VD_ASPACE_AB, 0); +} + +static int vdebug_dap_run(struct adiv5_dap *dap) +{ + if (le_to_h_u16(pbuf->waddr)) + return vdebug_run_reg_queue(vdc.hsocket, pbuf, le_to_h_u16(pbuf->waddr)); + + return ERROR_OK; +} + COMMAND_HANDLER(vdebug_set_server) { if ((CMD_ARGC != 1) || !strchr(CMD_ARGV[0], ':')) @@ -951,7 +1215,10 @@ COMMAND_HANDLER(vdebug_set_bfm) default: break; } - vdc.bfm_type = VD_BFM_JTAG; + if (transport_is_dapdirect_swd()) + vdc.bfm_type = strstr(vdc.bfm_path, "dap6") ? VD_BFM_DAP6 : VD_BFM_SWDP; + else + vdc.bfm_type = VD_BFM_JTAG; LOG_DEBUG("bfm_path: %s clk_period %ups", vdc.bfm_path, vdc.bfm_period); return ERROR_OK; @@ -1025,7 +1292,7 @@ static const struct command_registration vdebug_command_handlers[] = { { .name = "mem_path", .handler = &vdebug_set_mem, - .mode = COMMAND_ANY, + .mode = COMMAND_CONFIG, .help = "set the design memory for the code load", .usage = "<path> <base_address> <size>", }, @@ -1062,9 +1329,24 @@ static struct jtag_interface vdebug_jtag_ops = { .execute_queue = vdebug_jtag_execute_queue, }; +static const struct dap_ops vdebug_dap_ops = { + .connect = vdebug_dap_connect, + .send_sequence = vdebug_dap_send_sequence, + .queue_dp_read = vdebug_dap_queue_dp_read, + .queue_dp_write = vdebug_dap_queue_dp_write, + .queue_ap_read = vdebug_dap_queue_ap_read, + .queue_ap_write = vdebug_dap_queue_ap_write, + .queue_ap_abort = vdebug_dap_queue_ap_abort, + .run = vdebug_dap_run, + .sync = NULL, /* optional */ + .quit = NULL, /* optional */ +}; + +static const char *const vdebug_transports[] = { "jtag", "dapdirect_swd", NULL }; + struct adapter_driver vdebug_adapter_driver = { .name = "vdebug", - .transports = jtag_only, + .transports = vdebug_transports, .speed = vdebug_jtag_speed, .khz = vdebug_jtag_khz, .speed_div = vdebug_jtag_div, @@ -1073,4 +1355,5 @@ struct adapter_driver vdebug_adapter_driver = { .quit = vdebug_quit, .reset = vdebug_reset, .jtag_ops = &vdebug_jtag_ops, + .dap_swd_ops = &vdebug_dap_ops, }; diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtogpio.c b/src/jtag/drivers/versaloon/usbtoxxx/usbtogpio.c index 0d60725a6c..ac5b1a2454 100644 --- a/src/jtag/drivers/versaloon/usbtoxxx/usbtogpio.c +++ b/src/jtag/drivers/versaloon/usbtoxxx/usbtogpio.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtojtagraw.c b/src/jtag/drivers/versaloon/usbtoxxx/usbtojtagraw.c index bd6104935c..be2d8c303a 100644 --- a/src/jtag/drivers/versaloon/usbtoxxx/usbtojtagraw.c +++ b/src/jtag/drivers/versaloon/usbtoxxx/usbtojtagraw.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtopwr.c b/src/jtag/drivers/versaloon/usbtoxxx/usbtopwr.c index e7568171c4..941680a44a 100644 --- a/src/jtag/drivers/versaloon/usbtoxxx/usbtopwr.c +++ b/src/jtag/drivers/versaloon/usbtoxxx/usbtopwr.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c b/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c index 23a5097c20..42c8023cfc 100644 --- a/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c +++ b/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c index f701bb0525..070f68c1ed 100644 --- a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c +++ b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.h b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.h index 0ae3c0353b..caeaa26517 100644 --- a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.h +++ b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_VERSALOON_USBTOXXX_USBTOXXX_H diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx_internal.h b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx_internal.h index 36988869ac..8a6e476d7c 100644 --- a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx_internal.h +++ b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx_internal.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_VERSALOON_USBTOXXX_USBTOXXX_INTERNAL_H diff --git a/src/jtag/drivers/versaloon/versaloon.c b/src/jtag/drivers/versaloon/versaloon.c index 7c2efefaa0..48d317436b 100644 --- a/src/jtag/drivers/versaloon/versaloon.c +++ b/src/jtag/drivers/versaloon/versaloon.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/jtag/drivers/versaloon/versaloon.h b/src/jtag/drivers/versaloon/versaloon.h index e4aafb2506..5d7aa19c75 100644 --- a/src/jtag/drivers/versaloon/versaloon.h +++ b/src/jtag/drivers/versaloon/versaloon.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 by Simon Qian <SimonQian@SimonQian.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_H diff --git a/src/jtag/drivers/versaloon/versaloon_include.h b/src/jtag/drivers/versaloon/versaloon_include.h index a954b48e3f..5804ad5210 100644 --- a/src/jtag/drivers/versaloon/versaloon_include.h +++ b/src/jtag/drivers/versaloon/versaloon_include.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 by Simon Qian <SimonQian@SimonQian.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_INCLUDE_H diff --git a/src/jtag/drivers/versaloon/versaloon_internal.h b/src/jtag/drivers/versaloon/versaloon_internal.h index 8372970b1d..edeb335a2d 100644 --- a/src/jtag/drivers/versaloon/versaloon_internal.h +++ b/src/jtag/drivers/versaloon/versaloon_internal.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_DRIVERS_VERSALOON_VERSALOON_INTERNAL_H diff --git a/src/jtag/drivers/vsllink.c b/src/jtag/drivers/vsllink.c index dbbdef4ba9..34525d5468 100644 --- a/src/jtag/drivers/vsllink.c +++ b/src/jtag/drivers/vsllink.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009-2010 by Simon Qian <SimonQian@SimonQian.com> * - * * - * 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/>. * ***************************************************************************/ /* Versaloon is a programming tool for multiple MCUs. @@ -95,9 +84,9 @@ static bool swd_mode; static struct vsllink *vsllink_handle; -static int vsllink_execute_queue(void) +static int vsllink_execute_queue(struct jtag_command *cmd_queue) { - struct jtag_command *cmd = jtag_command_queue; + struct jtag_command *cmd = cmd_queue; int scan_size; enum scan_type type; uint8_t *buffer; diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index c5249b2966..11fbaaab2a 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2017 by Texas Instruments, Inc. * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -590,9 +579,6 @@ static bool usb_get_response(uint32_t *total_bytes_read, uint32_t timeout) static bool usb_send_command(uint16_t size) { - int written; - bool success = true; - /* Check the packet length */ if (size > USB_PAYLOAD_SIZE) return false; @@ -607,13 +593,7 @@ static bool usb_send_command(uint16_t size) size += 3; /* Send the data via the USB connection */ - success = usb_write(xds110.write_packet, (int)size, &written); - - /* Check if the correct number of bytes was written */ - if (written != (int)size) - success = false; - - return success; + return usb_write(xds110.write_packet, (int)size, NULL); } /*************************************************************************** @@ -1311,7 +1291,7 @@ static int xds110_swd_run_queue(void) /* Transfer results into caller's buffers */ for (result = 0; result < xds110.txn_result_count; result++) - if (xds110.txn_dap_results[result] != 0) + if (xds110.txn_dap_results[result]) *xds110.txn_dap_results[result] = dap_results[result]; xds110.txn_request_size = 0; @@ -1365,11 +1345,13 @@ static void xds110_swd_queue_cmd(uint8_t cmd, uint32_t *value) static void xds110_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { + assert(cmd & SWD_CMD_RNW); xds110_swd_queue_cmd(cmd, value); } static void xds110_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { + assert(!(cmd & SWD_CMD_RNW)); xds110_swd_queue_cmd(cmd, &value); } @@ -1620,7 +1602,7 @@ static void xds110_flush(void) } bits = 0; } - if (xds110.txn_scan_results[result].buffer != 0) + if (xds110.txn_scan_results[result].buffer) bit_copy(xds110.txn_scan_results[result].buffer, 0, data_pntr, bits, xds110.txn_scan_results[result].num_bits); bits += xds110.txn_scan_results[result].num_bits; @@ -1696,8 +1678,8 @@ static void xds110_execute_pathmove(struct jtag_command *cmd) if (num_states == 0) return; - path = (uint8_t *)malloc(num_states * sizeof(uint8_t)); - if (path == 0) { + path = malloc(num_states * sizeof(uint8_t)); + if (!path) { LOG_ERROR("XDS110: unable to allocate memory"); return; } @@ -1775,7 +1757,7 @@ static void xds110_queue_scan(struct jtag_command *cmd) /* Clear data out buffer to default value of all zeros */ memset((void *)buffer, 0x00, total_bytes); for (i = 0; i < cmd->cmd.scan->num_fields; i++) { - if (cmd->cmd.scan->fields[i].out_value != 0) { + if (cmd->cmd.scan->fields[i].out_value) { /* Copy over data to scan out into request buffer */ bit_copy(buffer, offset, cmd->cmd.scan->fields[i].out_value, 0, cmd->cmd.scan->fields[i].num_bits); @@ -1858,9 +1840,9 @@ static void xds110_execute_command(struct jtag_command *cmd) } } -static int xds110_execute_queue(void) +static int xds110_execute_queue(struct jtag_command *cmd_queue) { - struct jtag_command *cmd = jtag_command_queue; + struct jtag_command *cmd = cmd_queue; while (cmd) { xds110_execute_command(cmd); diff --git a/src/jtag/drivers/xlnx-pcie-xvc.c b/src/jtag/drivers/xlnx-pcie-xvc.c index c05b9cf4ab..233ade3f88 100644 --- a/src/jtag/drivers/xlnx-pcie-xvc.c +++ b/src/jtag/drivers/xlnx-pcie-xvc.c @@ -1,5 +1,6 @@ -/* SPDX-License-Identifier: GPL-2.0 - * +// SPDX-License-Identifier: GPL-2.0-only + +/* * Copyright (c) 2019 Google, LLC. * Author: Moritz Fischer <moritzf@google.com> */ @@ -361,9 +362,9 @@ static int xlnx_pcie_xvc_execute_command(struct jtag_command *cmd) return ERROR_OK; } -static int xlnx_pcie_xvc_execute_queue(void) +static int xlnx_pcie_xvc_execute_queue(struct jtag_command *cmd_queue) { - struct jtag_command *cmd = jtag_command_queue; + struct jtag_command *cmd = cmd_queue; int ret; while (cmd) { diff --git a/src/jtag/hla/Makefile.am b/src/jtag/hla/Makefile.am index 6bb2960ebc..ea6e11dd63 100644 --- a/src/jtag/hla/Makefile.am +++ b/src/jtag/hla/Makefile.am @@ -1,11 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libocdhla.la %C%_libocdhla_la_SOURCES = \ %D%/hla_transport.c \ - %D%/hla_tcl.c \ %D%/hla_interface.c \ %D%/hla_layout.c \ %D%/hla_transport.h \ %D%/hla_interface.h \ - %D%/hla_layout.h \ - %D%/hla_tcl.h + %D%/hla_layout.h diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index 074e3c2fba..9c8d0fadea 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester <kesmtp@freenet.de> * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -28,7 +17,6 @@ #include <transport/transport.h> #include <helper/time_support.h> -#include <jtag/hla/hla_tcl.h> #include <jtag/hla/hla_layout.h> #include <jtag/hla/hla_transport.h> #include <jtag/hla/hla_interface.h> @@ -112,7 +100,7 @@ int hl_interface_init_target(struct target *t) } t->tap->priv = &hl_if; - t->tap->hasidcode = 1; + t->tap->has_idcode = true; return ERROR_OK; } diff --git a/src/jtag/hla/hla_interface.h b/src/jtag/hla/hla_interface.h index 31d055a3ca..fa4965806b 100644 --- a/src/jtag/hla/hla_interface.h +++ b/src/jtag/hla/hla_interface.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester <kesmtp@freenet.de> * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_HLA_HLA_INTERFACE_H diff --git a/src/jtag/hla/hla_layout.c b/src/jtag/hla/hla_layout.c index 16b2217976..51671d60aa 100644 --- a/src/jtag/hla/hla_layout.c +++ b/src/jtag/hla/hla_layout.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester <kesmtp@freenet.de> * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -29,7 +18,6 @@ #include <helper/time_support.h> #include <jtag/hla/hla_layout.h> -#include <jtag/hla/hla_tcl.h> #include <jtag/hla/hla_transport.h> #include <jtag/hla/hla_interface.h> diff --git a/src/jtag/hla/hla_layout.h b/src/jtag/hla/hla_layout.h index 732fe1e6ae..e13da6531c 100644 --- a/src/jtag/hla/hla_layout.h +++ b/src/jtag/hla/hla_layout.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester <kesmtp@freenet.de> * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_HLA_HLA_LAYOUT_H diff --git a/src/jtag/hla/hla_tcl.c b/src/jtag/hla/hla_tcl.c deleted file mode 100644 index 6b206d2316..0000000000 --- a/src/jtag/hla/hla_tcl.c +++ /dev/null @@ -1,154 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Mathias Kuester * - * Mathias Kuester <kesmtp@freenet.de> * - * * - * Copyright (C) 2012 by Spencer Oliver * - * spen@spen-soft.co.uk * - * * - * 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/>. * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* project specific includes */ -#include <jtag/interface.h> -#include <transport/transport.h> -#include <helper/time_support.h> - -static int jim_newtap_expected_id(struct jim_nvp *n, struct jim_getopt_info *goi, - struct jtag_tap *tap) -{ - jim_wide w; - int e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi->interp, "option: %s bad parameter", - n->name); - return e; - } - - uint32_t *p = realloc(tap->expected_ids, - (tap->expected_ids_cnt + 1) * sizeof(uint32_t)); - if (!p) { - Jim_SetResultFormatted(goi->interp, "no memory"); - return JIM_ERR; - } - - tap->expected_ids = p; - tap->expected_ids[tap->expected_ids_cnt++] = w; - - return JIM_OK; -} - -#define NTAP_OPT_IRLEN 0 -#define NTAP_OPT_IRMASK 1 -#define NTAP_OPT_IRCAPTURE 2 -#define NTAP_OPT_ENABLED 3 -#define NTAP_OPT_DISABLED 4 -#define NTAP_OPT_EXPECTED_ID 5 -#define NTAP_OPT_VERSION 6 -#define NTAP_OPT_BYPASS 7 - -static int jim_hl_newtap_cmd(struct jim_getopt_info *goi) -{ - struct jtag_tap *tap; - int x; - int e; - struct jim_nvp *n; - char *cp; - const struct jim_nvp opts[] = { - { .name = "-irlen", .value = NTAP_OPT_IRLEN }, - { .name = "-irmask", .value = NTAP_OPT_IRMASK }, - { .name = "-ircapture", .value = NTAP_OPT_IRCAPTURE }, - { .name = "-enable", .value = NTAP_OPT_ENABLED }, - { .name = "-disable", .value = NTAP_OPT_DISABLED }, - { .name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID }, - { .name = "-ignore-version", .value = NTAP_OPT_VERSION }, - { .name = "-ignore-bypass", .value = NTAP_OPT_BYPASS }, - { .name = NULL, .value = -1}, - }; - - tap = calloc(1, sizeof(struct jtag_tap)); - if (!tap) { - Jim_SetResultFormatted(goi->interp, "no memory"); - return JIM_ERR; - } - - /* - * we expect CHIP + TAP + OPTIONS - * */ - if (goi->argc < 3) { - Jim_SetResultFormatted(goi->interp, - "Missing CHIP TAP OPTIONS ...."); - free(tap); - return JIM_ERR; - } - - const char *tmp; - jim_getopt_string(goi, &tmp, NULL); - tap->chip = strdup(tmp); - - jim_getopt_string(goi, &tmp, NULL); - tap->tapname = strdup(tmp); - - /* name + dot + name + null */ - x = strlen(tap->chip) + 1 + strlen(tap->tapname) + 1; - cp = malloc(x); - sprintf(cp, "%s.%s", tap->chip, tap->tapname); - tap->dotted_name = cp; - - LOG_DEBUG("Creating New Tap, Chip: %s, Tap: %s, Dotted: %s, %d params", - tap->chip, tap->tapname, tap->dotted_name, goi->argc); - - while (goi->argc) { - e = jim_getopt_nvp(goi, opts, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(goi, opts, 0); - free(cp); - free(tap); - return e; - } - LOG_DEBUG("Processing option: %s", n->name); - switch (n->value) { - case NTAP_OPT_EXPECTED_ID: - e = jim_newtap_expected_id(n, goi, tap); - if (e != JIM_OK) { - free(cp); - free(tap); - return e; - } - break; - case NTAP_OPT_IRLEN: - case NTAP_OPT_IRMASK: - case NTAP_OPT_IRCAPTURE: - /* dummy read to ignore the next argument */ - jim_getopt_wide(goi, NULL); - break; - } /* switch (n->value) */ - } /* while (goi->argc) */ - - /* default is enabled-after-reset */ - tap->enabled = !tap->disabled_after_reset; - - jtag_tap_init(tap); - return JIM_OK; -} - -int jim_hl_newtap(Jim_Interp *interp, int argc, Jim_Obj * const *argv) -{ - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - return jim_hl_newtap_cmd(&goi); -} diff --git a/src/jtag/hla/hla_tcl.h b/src/jtag/hla/hla_tcl.h deleted file mode 100644 index ac00add512..0000000000 --- a/src/jtag/hla/hla_tcl.h +++ /dev/null @@ -1,28 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Mathias Kuester * - * Mathias Kuester <kesmtp@freenet.de> * - * * - * Copyright (C) 2012 by Spencer Oliver * - * spen@spen-soft.co.uk * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_JTAG_HLA_HLA_TCL_H -#define OPENOCD_JTAG_HLA_HLA_TCL_H - -/** */ -int jim_hl_newtap(Jim_Interp *interp, int argc, Jim_Obj * const *argv); - -#endif /* OPENOCD_JTAG_HLA_HLA_TCL_H */ diff --git a/src/jtag/hla/hla_transport.c b/src/jtag/hla/hla_transport.c index 58dfe4b636..b826eb0fe6 100644 --- a/src/jtag/hla/hla_transport.c +++ b/src/jtag/hla/hla_transport.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester <kesmtp@freenet.de> * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -29,7 +18,6 @@ #include <transport/transport.h> #include <helper/time_support.h> #include <target/target.h> -#include <jtag/hla/hla_tcl.h> #include <jtag/hla/hla_transport.h> #include <jtag/hla/hla_interface.h> @@ -49,8 +37,16 @@ static const struct command_registration hl_swd_transport_subcommand_handlers[] { .name = "newdap", .mode = COMMAND_CONFIG, - .jim_handler = jim_hl_newtap, + .handler = handle_jtag_newtap, .help = "declare a new SWD DAP", + .usage = "basename dap_type ['-irlen' count] " + "['-enable'|'-disable'] " + "['-expected_id' number] " + "['-ignore-version'] " + "['-ignore-bypass'] " + "['-ircapture' number] " + "['-ir-bypass' number] " + "['-mask' number]", }, COMMAND_REGISTRATION_DONE }; @@ -70,11 +66,17 @@ static const struct command_registration hl_transport_jtag_subcommand_handlers[] { .name = "newtap", .mode = COMMAND_CONFIG, - .jim_handler = jim_hl_newtap, + .handler = handle_jtag_newtap, .help = "Create a new TAP instance named basename.tap_type, " "and appends it to the scan chain.", .usage = "basename tap_type '-irlen' count " - "['-expected_id' number]", + "['-enable'|'-disable'] " + "['-expected_id' number] " + "['-ignore-version'] " + "['-ignore-bypass'] " + "['-ircapture' number] " + "['-ir-bypass' number] " + "['-mask' number]", }, { .name = "init", @@ -97,12 +99,18 @@ static const struct command_registration hl_transport_jtag_subcommand_handlers[] { .name = "tapisenabled", .mode = COMMAND_EXEC, - .jim_handler = jim_jtag_tap_enabler, + .handler = handle_jtag_tap_enabler, + .help = "Returns a Tcl boolean (0/1) indicating whether " + "the TAP is enabled (1) or not (0).", + .usage = "tap_name", }, { .name = "tapenable", .mode = COMMAND_EXEC, - .jim_handler = jim_jtag_tap_enabler, + .handler = handle_jtag_tap_enabler, + .help = "Try to enable the specified TAP using the " + "'tap-enable' TAP event.", + .usage = "tap_name", }, { .name = "tapdisable", @@ -119,7 +127,8 @@ static const struct command_registration hl_transport_jtag_subcommand_handlers[] { .name = "cget", .mode = COMMAND_EXEC, - .jim_handler = jim_jtag_configure, + .handler = handle_jtag_configure, + .usage = "", }, { .name = "names", diff --git a/src/jtag/hla/hla_transport.h b/src/jtag/hla/hla_transport.h index 0e0bea25f4..965f561148 100644 --- a/src/jtag/hla/hla_transport.h +++ b/src/jtag/hla/hla_transport.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester <kesmtp@freenet.de> * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_HLA_HLA_TRANSPORT_H diff --git a/src/jtag/interface.c b/src/jtag/interface.c index 56bbf6e51b..1230bb1b3d 100644 --- a/src/jtag/interface.c +++ b/src/jtag/interface.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -11,19 +13,6 @@ * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -383,7 +372,7 @@ tap_state_t tap_state_by_name(const char *name) tap_state_name(a), tap_state_name(b), astr, bstr) tap_state_t jtag_debug_state_machine_(const void *tms_buf, const void *tdi_buf, - unsigned tap_bits, tap_state_t next_state) + unsigned int tap_bits, tap_state_t next_state) { const uint8_t *tms_buffer; const uint8_t *tdi_buffer; diff --git a/src/jtag/interface.h b/src/jtag/interface.h index 58bfd02b0a..c1915f04fd 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_INTERFACE_H @@ -158,6 +147,8 @@ void tap_use_new_tms_table(bool use_new); /** @returns True if new TMS table is active; false otherwise. */ bool tap_uses_new_tms_table(void); +tap_state_t jtag_debug_state_machine_(const void *tms_buf, const void *tdi_buf, + unsigned int tap_len, tap_state_t start_tap_state); /** * @brief Prints verbose TAP state transitions for the given TMS/TDI buffers. @@ -170,10 +161,6 @@ bool tap_uses_new_tms_table(void); static inline tap_state_t jtag_debug_state_machine(const void *tms_buf, const void *tdi_buf, unsigned tap_len, tap_state_t start_tap_state) { - /* Private declaration */ - tap_state_t jtag_debug_state_machine_(const void *tms_buf, const void *tdi_buf, - unsigned tap_len, tap_state_t start_tap_state); - if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) return jtag_debug_state_machine_(tms_buf, tdi_buf, tap_len, start_tap_state); else @@ -200,10 +187,12 @@ struct jtag_interface { #define DEBUG_CAP_TMS_SEQ (1 << 0) /** - * Execute queued commands. + * Execute commands in the supplied queue + * @param cmd_queue - a linked list of commands to execute * @returns ERROR_OK on success, or an error code on failure. */ - int (*execute_queue)(void); + + int (*execute_queue)(struct jtag_command *cmd_queue); }; /** @@ -375,4 +364,45 @@ int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, unsigned int traceclkin_freq, uint16_t *prescaler); int adapter_poll_trace(uint8_t *buf, size_t *size); +extern struct adapter_driver am335xgpio_adapter_driver; +extern struct adapter_driver amt_jtagaccel_adapter_driver; +extern struct adapter_driver angie_adapter_driver; +extern struct adapter_driver armjtagew_adapter_driver; +extern struct adapter_driver at91rm9200_adapter_driver; +extern struct adapter_driver bcm2835gpio_adapter_driver; +extern struct adapter_driver buspirate_adapter_driver; +extern struct adapter_driver cmsis_dap_adapter_driver; +extern struct adapter_driver dmem_dap_adapter_driver; +extern struct adapter_driver dummy_adapter_driver; +extern struct adapter_driver ep93xx_adapter_driver; +extern struct adapter_driver esp_usb_adapter_driver; +extern struct adapter_driver ft232r_adapter_driver; +extern struct adapter_driver ftdi_adapter_driver; +extern struct adapter_driver gw16012_adapter_driver; +extern struct adapter_driver hl_adapter_driver; +extern struct adapter_driver imx_gpio_adapter_driver; +extern struct adapter_driver jlink_adapter_driver; +extern struct adapter_driver jtag_dpi_adapter_driver; +extern struct adapter_driver jtag_tcp_adapter_driver; +extern struct adapter_driver jtag_vpi_adapter_driver; +extern struct adapter_driver kitprog_adapter_driver; +extern struct adapter_driver linuxgpiod_adapter_driver; +extern struct adapter_driver opendous_adapter_driver; +extern struct adapter_driver openjtag_adapter_driver; +extern struct adapter_driver osbdm_adapter_driver; +extern struct adapter_driver parport_adapter_driver; +extern struct adapter_driver presto_adapter_driver; +extern struct adapter_driver remote_bitbang_adapter_driver; +extern struct adapter_driver rlink_adapter_driver; +extern struct adapter_driver rshim_dap_adapter_driver; +extern struct adapter_driver stlink_dap_adapter_driver; +extern struct adapter_driver sysfsgpio_adapter_driver; +extern struct adapter_driver ulink_adapter_driver; +extern struct adapter_driver usb_blaster_adapter_driver; +extern struct adapter_driver usbprog_adapter_driver; +extern struct adapter_driver vdebug_adapter_driver; +extern struct adapter_driver vsllink_adapter_driver; +extern struct adapter_driver xds110_adapter_driver; +extern struct adapter_driver xlnx_pcie_xvc_adapter_driver; + #endif /* OPENOCD_JTAG_INTERFACE_H */ diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index f2b4ad5723..620002a8a8 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -13,19 +15,6 @@ * zw@superlucidity.net * * * * Copyright (C) 2020, Ampere Computing LLC * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -35,123 +24,13 @@ #include "interfaces.h" /** @file - * This file includes declarations for all built-in jtag interfaces, - * which are then listed in the adapter_drivers array. + * This file collects all the built-in JTAG interfaces in the adapter_drivers + * array. * * Dynamic loading can be implemented be searching for shared libraries * that contain an adapter_driver structure that can added to this list. */ -#if BUILD_PARPORT == 1 -extern struct adapter_driver parport_adapter_driver; -#endif -#if BUILD_DUMMY == 1 -extern struct adapter_driver dummy_adapter_driver; -#endif -extern struct adapter_driver jtag_tcp_adapter_driver; -#if BUILD_FTDI == 1 -extern struct adapter_driver ftdi_adapter_driver; -#endif -#if BUILD_USB_BLASTER == 1 || BUILD_USB_BLASTER_2 == 1 -extern struct adapter_driver usb_blaster_adapter_driver; -#endif -#if BUILD_JTAG_VPI == 1 -extern struct adapter_driver jtag_vpi_adapter_driver; -#endif -#if BUILD_VDEBUG == 1 -extern struct adapter_driver vdebug_adapter_driver; -#endif -#if BUILD_JTAG_DPI == 1 -extern struct adapter_driver jtag_dpi_adapter_driver; -#endif -#if BUILD_FT232R == 1 -extern struct adapter_driver ft232r_adapter_driver; -#endif -#if BUILD_AMTJTAGACCEL == 1 -extern struct adapter_driver amt_jtagaccel_adapter_driver; -#endif -#if BUILD_EP93XX == 1 -extern struct adapter_driver ep93xx_adapter_driver; -#endif -#if BUILD_AT91RM9200 == 1 -extern struct adapter_driver at91rm9200_adapter_driver; -#endif -#if BUILD_GW16012 == 1 -extern struct adapter_driver gw16012_adapter_driver; -#endif -#if BUILD_PRESTO -extern struct adapter_driver presto_adapter_driver; -#endif -#if BUILD_USBPROG == 1 -extern struct adapter_driver usbprog_adapter_driver; -#endif -#if BUILD_OPENJTAG == 1 -extern struct adapter_driver openjtag_adapter_driver; -#endif -#if BUILD_JLINK == 1 -extern struct adapter_driver jlink_adapter_driver; -#endif -#if BUILD_VSLLINK == 1 -extern struct adapter_driver vsllink_adapter_driver; -#endif -#if BUILD_RLINK == 1 -extern struct adapter_driver rlink_adapter_driver; -#endif -#if BUILD_ULINK == 1 -extern struct adapter_driver ulink_adapter_driver; -#endif -#if BUILD_ARMJTAGEW == 1 -extern struct adapter_driver armjtagew_adapter_driver; -#endif -#if BUILD_BUSPIRATE == 1 -extern struct adapter_driver buspirate_adapter_driver; -#endif -#if BUILD_REMOTE_BITBANG == 1 -extern struct adapter_driver remote_bitbang_adapter_driver; -#endif -#if BUILD_HLADAPTER == 1 -extern struct adapter_driver hl_adapter_driver; -#endif -#if BUILD_OSBDM == 1 -extern struct adapter_driver osbdm_adapter_driver; -#endif -#if BUILD_OPENDOUS == 1 -extern struct adapter_driver opendous_adapter_driver; -#endif -#if BUILD_SYSFSGPIO == 1 -extern struct adapter_driver sysfsgpio_adapter_driver; -#endif -#if BUILD_LINUXGPIOD == 1 -extern struct adapter_driver linuxgpiod_adapter_driver; -#endif -#if BUILD_XLNX_PCIE_XVC == 1 -extern struct adapter_driver xlnx_pcie_xvc_adapter_driver; -#endif -#if BUILD_AICE == 1 -extern struct adapter_driver aice_adapter_driver; -#endif -#if BUILD_BCM2835GPIO == 1 -extern struct adapter_driver bcm2835gpio_adapter_driver; -#endif -#if BUILD_CMSIS_DAP_USB == 1 || BUILD_CMSIS_DAP_HID == 1 -extern struct adapter_driver cmsis_dap_adapter_driver; -#endif -#if BUILD_KITPROG == 1 -extern struct adapter_driver kitprog_adapter_driver; -#endif -#if BUILD_IMX_GPIO == 1 -extern struct adapter_driver imx_gpio_adapter_driver; -#endif -#if BUILD_XDS110 == 1 -extern struct adapter_driver xds110_adapter_driver; -#endif -#if BUILD_HLADAPTER_STLINK == 1 -extern struct adapter_driver stlink_dap_adapter_driver; -#endif -#if BUILD_RSHIM == 1 -extern struct adapter_driver rshim_dap_adapter_driver; -#endif - /** * The list of built-in JTAG interfaces, containing entries for those * drivers that were enabled by the @c configure script. @@ -170,6 +49,9 @@ struct adapter_driver *adapter_drivers[] = { #if BUILD_USB_BLASTER || BUILD_USB_BLASTER_2 == 1 &usb_blaster_adapter_driver, #endif +#if BUILD_ESP_USB_JTAG == 1 + &esp_usb_adapter_driver, +#endif #if BUILD_JTAG_VPI == 1 &jtag_vpi_adapter_driver, #endif @@ -215,6 +97,9 @@ struct adapter_driver *adapter_drivers[] = { #if BUILD_ULINK == 1 &ulink_adapter_driver, #endif +#if BUILD_ANGIE == 1 + &angie_adapter_driver, +#endif #if BUILD_ARMJTAGEW == 1 &armjtagew_adapter_driver, #endif @@ -242,9 +127,6 @@ struct adapter_driver *adapter_drivers[] = { #if BUILD_XLNX_PCIE_XVC == 1 &xlnx_pcie_xvc_adapter_driver, #endif -#if BUILD_AICE == 1 - &aice_adapter_driver, -#endif #if BUILD_BCM2835GPIO == 1 &bcm2835gpio_adapter_driver, #endif @@ -265,6 +147,12 @@ struct adapter_driver *adapter_drivers[] = { #endif #if BUILD_RSHIM == 1 &rshim_dap_adapter_driver, +#endif +#if BUILD_DMEM == 1 + &dmem_dap_adapter_driver, +#endif +#if BUILD_AM335XGPIO == 1 + &am335xgpio_adapter_driver, #endif NULL, }; diff --git a/src/jtag/interfaces.h b/src/jtag/interfaces.h index ddbd735060..6e6c2ce15d 100644 --- a/src/jtag/interfaces.h +++ b/src/jtag/interfaces.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -11,19 +13,6 @@ * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_INTERFACES_H diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index 4ec2f1e311..470ae18334 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -1,28 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * -* * -* 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_JTAG_H #define OPENOCD_JTAG_JTAG_H #include <helper/binarybuffer.h> +#include <helper/command.h> #include <helper/log.h> #include <helper/replacements.h> @@ -125,7 +115,7 @@ struct jtag_tap { uint32_t idcode; /**< device identification code */ /** not all devices have idcode, * we'll discover this during chain examination */ - bool hasidcode; + bool has_idcode; /** Array of expected identification codes */ uint32_t *expected_ids; @@ -141,7 +131,10 @@ struct jtag_tap { /** current instruction */ uint8_t *cur_instr; /** Bypass register selected */ - int bypass; + bool bypass; + + /** Bypass instruction value */ + uint64_t ir_bypass_value; struct jtag_tap_event_action *event_action; @@ -598,8 +591,21 @@ bool jtag_poll_get_enabled(void); */ void jtag_poll_set_enabled(bool value); +/** + * Mask (disable) polling and return the current mask status that should be + * feed to jtag_poll_unmask() to restore it. + * Multiple nested calls to jtag_poll_mask() are allowed, each balanced with + * its call to jtag_poll_unmask(). + */ +bool jtag_poll_mask(void); + +/** + * Restore saved mask for polling. + */ +void jtag_poll_unmask(bool saved); + #include <jtag/minidriver.h> -int jim_jtag_newtap(Jim_Interp *interp, int argc, Jim_Obj *const *argv); +__COMMAND_HANDLER(handle_jtag_newtap); #endif /* OPENOCD_JTAG_JTAG_H */ diff --git a/src/jtag/minidriver.h b/src/jtag/minidriver.h index 0624c55fb9..a40cffa2bd 100644 --- a/src/jtag/minidriver.h +++ b/src/jtag/minidriver.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_MINIDRIVER_H diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl index ee116269e9..4eca67771d 100644 --- a/src/jtag/startup.tcl +++ b/src/jtag/startup.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Defines basic Tcl procs for OpenOCD JTAG module # Executed during "init". Can be overridden @@ -120,6 +122,66 @@ proc jtag_ntrst_assert_width args { # # FIXME phase these aids out after some releases # +lappend _telnet_autocomplete_skip adapter_gpio_helper_with_caller +# Helper for deprecated driver functions that should call "adapter gpio XXX". + +# Call this function as: +# adapter_gpio_helper_with_caller caller sig_name +# adapter_gpio_helper_with_caller caller sig_name gpio_num +# adapter_gpio_helper_with_caller caller sig_name chip_num gpio_num +proc adapter_gpio_helper_with_caller {caller sig_name args} { + echo "DEPRECATED! use 'adapter gpio $sig_name' not '$caller'" + switch [llength $args] { + 0 {} + 1 {eval adapter gpio $sig_name $args} + 2 {eval adapter gpio $sig_name [lindex $args 1] -chip [lindex $args 0]} + default {return -code 1 -level 1 "$caller: syntax error"} + } + eval adapter gpio $sig_name +} + +lappend _telnet_autocomplete_skip adapter_gpio_helper +# Call this function as: +# adapter_gpio_helper sig_name +# adapter_gpio_helper sig_name gpio_num +# adapter_gpio_helper sig_name chip_num gpio_num +proc adapter_gpio_helper {sig_name args} { + set caller [lindex [info level -1] 0] + eval adapter_gpio_helper_with_caller {"$caller"} $sig_name $args +} + +lappend _telnet_autocomplete_skip adapter_gpio_jtag_nums_with_caller +# Helper for deprecated driver functions that implemented jtag_nums +proc adapter_gpio_jtag_nums_with_caller {caller tck_num tms_num tdi_num tdo_num} { + echo "DEPRECATED! use 'adapter gpio tck; adapter gpio tms; adapter gpio tdi; adapter gpio tdo' not '$caller'" + eval adapter gpio tck $tck_num + eval adapter gpio tms $tms_num + eval adapter gpio tdi $tdi_num + eval adapter gpio tdo $tdo_num +} + +lappend _telnet_autocomplete_skip adapter_gpio_jtag_nums +# Helper for deprecated driver functions that implemented jtag_nums +proc adapter_gpio_jtag_nums {args} { + set caller [lindex [info level -1] 0] + eval adapter_gpio_jtag_nums_with_caller {"$caller"} $args +} + +lappend _telnet_autocomplete_skip adapter_gpio_swd_nums_with_caller +# Helper for deprecated driver functions that implemented swd_nums +proc adapter_gpio_swd_nums_with_caller {caller swclk_num swdio_num} { + echo "DEPRECATED! use 'adapter gpio swclk; adapter gpio swdio' not '$caller'" + eval adapter gpio swclk $swclk_num + eval adapter gpio swdio $swdio_num +} + +lappend _telnet_autocomplete_skip adapter_gpio_swd_nums +# Helper for deprecated driver functions that implemented jtag_nums +proc adapter_gpio_swd_nums {args} { + set caller [lindex [info level -1] 0] + eval adapter_gpio_swd_nums_with_caller {"$caller"} $args +} + lappend _telnet_autocomplete_skip jtag_reset proc jtag_reset args { echo "DEPRECATED! use 'adapter \[de\]assert' not 'jtag_reset'" @@ -393,70 +455,140 @@ proc vsllink_usb_interface args { eval vsllink usb_interface $args } + +lappend _telnet_autocomplete_skip bcm2835_gpio_helper +proc bcm2835_gpio_helper {sig_name args} { + set caller [lindex [info level -1] 0] + echo "DEPRECATED! use 'adapter gpio $sig_name' not '$caller'" + switch [llength $args] { + 0 {} + 1 {eval adapter gpio $sig_name $args -chip 0} + 2 {eval adapter gpio $sig_name [lindex $args 1] -chip [lindex $args 0]} + default {return -code 1 -level 1 "$caller: syntax error"} + } + eval adapter gpio $sig_name +} + lappend _telnet_autocomplete_skip bcm2835gpio_jtag_nums -proc bcm2835gpio_jtag_nums args { - echo "DEPRECATED! use 'bcm2835gpio jtag_nums' not 'bcm2835gpio_jtag_nums'" - eval bcm2835gpio jtag_nums $args +proc bcm2835gpio_jtag_nums {tck_num tms_num tdi_num tdo_num} { + echo "DEPRECATED! use 'adapter gpio tck; adapter gpio tms; adapter gpio tdi; adapter gpio tdo' not 'bcm2835gpio_jtag_nums'" + eval adapter gpio tck $tck_num -chip 0 + eval adapter gpio tms $tms_num -chip 0 + eval adapter gpio tdi $tdi_num -chip 0 + eval adapter gpio tdo $tdo_num -chip 0 } lappend _telnet_autocomplete_skip bcm2835gpio_tck_num proc bcm2835gpio_tck_num args { - echo "DEPRECATED! use 'bcm2835gpio tck_num' not 'bcm2835gpio_tck_num'" - eval bcm2835gpio tck_num $args + eval bcm2835_gpio_helper tck $args } lappend _telnet_autocomplete_skip bcm2835gpio_tms_num proc bcm2835gpio_tms_num args { - echo "DEPRECATED! use 'bcm2835gpio tms_num' not 'bcm2835gpio_tms_num'" - eval bcm2835gpio tms_num $args + eval bcm2835_gpio_helper tms $args } lappend _telnet_autocomplete_skip bcm2835gpio_tdo_num proc bcm2835gpio_tdo_num args { - echo "DEPRECATED! use 'bcm2835gpio tdo_num' not 'bcm2835gpio_tdo_num'" - eval bcm2835gpio tdo_num $args + eval bcm2835_gpio_helper tdo $args } lappend _telnet_autocomplete_skip bcm2835gpio_tdi_num proc bcm2835gpio_tdi_num args { - echo "DEPRECATED! use 'bcm2835gpio tdi_num' not 'bcm2835gpio_tdi_num'" - eval bcm2835gpio tdi_num $args + eval bcm2835_gpio_helper tdi $args } lappend _telnet_autocomplete_skip bcm2835gpio_swd_nums -proc bcm2835gpio_swd_nums args { - echo "DEPRECATED! use 'bcm2835gpio swd_nums' not 'bcm2835gpio_swd_nums'" - eval bcm2835gpio swd_nums $args +proc bcm2835gpio_swd_nums {swclk_num swdio_num} { + echo "DEPRECATED! use 'adapter gpio swclk; adapter gpio swdio' not 'bcm2835gpio_swd_nums'" + eval adapter gpio swclk $swclk_num -chip 0 + eval adapter gpio swdio $swdio_num -chip 0 } lappend _telnet_autocomplete_skip bcm2835gpio_swclk_num proc bcm2835gpio_swclk_num args { - echo "DEPRECATED! use 'bcm2835gpio swclk_num' not 'bcm2835gpio_swclk_num'" - eval bcm2835gpio swclk_num $args + eval bcm2835_gpio_helper swclk $args } lappend _telnet_autocomplete_skip bcm2835gpio_swdio_num proc bcm2835gpio_swdio_num args { - echo "DEPRECATED! use 'bcm2835gpio swdio_num' not 'bcm2835gpio_swdio_num'" - eval bcm2835gpio swdio_num $args + eval bcm2835_gpio_helper swdio $args } lappend _telnet_autocomplete_skip bcm2835gpio_swdio_dir_num proc bcm2835gpio_swdio_dir_num args { - echo "DEPRECATED! use 'bcm2835gpio swdio_dir_num' not 'bcm2835gpio_swdio_dir_num'" - eval bcm2835gpio swdio_dir_num $args + eval bcm2835_gpio_helper swdio_dir $args } lappend _telnet_autocomplete_skip bcm2835gpio_srst_num proc bcm2835gpio_srst_num args { - echo "DEPRECATED! use 'bcm2835gpio srst_num' not 'bcm2835gpio_srst_num'" - eval bcm2835gpio srst_num $args + eval bcm2835_gpio_helper srst $args } lappend _telnet_autocomplete_skip bcm2835gpio_trst_num proc bcm2835gpio_trst_num args { - echo "DEPRECATED! use 'bcm2835gpio trst_num' not 'bcm2835gpio_trst_num'" - eval bcm2835gpio trst_num $args + eval bcm2835_gpio_helper trst $args +} + +lappend _telnet_autocomplete_skip "bcm2835gpio jtag_nums" +proc "bcm2835gpio jtag_nums" {tck_num tms_num tdi_num tdo_num} { + echo "DEPRECATED! use 'adapter gpio tck; adapter gpio tms; adapter gpio tdi; adapter gpio tdo' not 'bcm2835gpio jtag_nums'" + eval adapter gpio tck $tck_num -chip 0 + eval adapter gpio tms $tms_num -chip 0 + eval adapter gpio tdi $tdi_num -chip 0 + eval adapter gpio tdo $tdo_num -chip 0 +} + +lappend _telnet_autocomplete_skip "bcm2835gpio tck_num" +proc "bcm2835gpio tck_num" args { + eval bcm2835_gpio_helper tck $args +} + +lappend _telnet_autocomplete_skip "bcm2835gpio tms_num" +proc "bcm2835gpio tms_num" args { + eval bcm2835_gpio_helper tms $args +} + +lappend _telnet_autocomplete_skip "bcm2835gpio tdo_num" +proc "bcm2835gpio tdo_num" args { + eval bcm2835_gpio_helper tdo $args +} + +lappend _telnet_autocomplete_skip "bcm2835gpio tdi_num" +proc "bcm2835gpio tdi_num" args { + eval bcm2835_gpio_helper tdi $args +} + +lappend _telnet_autocomplete_skip "bcm2835gpio swd_nums" +proc "bcm2835gpio swd_nums" {swclk_num swdio_num} { + echo "DEPRECATED! use 'adapter gpio swclk; adapter gpio swdio' not 'bcm2835gpio swd_nums'" + eval adapter gpio swclk $swclk_num -chip 0 + eval adapter gpio swdio $swdio_num -chip 0 +} + +lappend _telnet_autocomplete_skip "bcm2835gpio swclk_num" +proc "bcm2835gpio swclk_num" args { + eval bcm2835_gpio_helper swclk $args +} + +lappend _telnet_autocomplete_skip "bcm2835gpio swdio_num" +proc "bcm2835gpio swdio_num" args { + eval bcm2835_gpio_helper swdio $args +} + +lappend _telnet_autocomplete_skip "bcm2835gpio swdio_dir_num" +proc "bcm2835gpio swdio_dir_num" args { + eval bcm2835_gpio_helper swdio_dir $args +} + +lappend _telnet_autocomplete_skip "bcm2835gpio srst_num" +proc "bcm2835gpio srst_num" args { + eval bcm2835_gpio_helper srst $args +} + +lappend _telnet_autocomplete_skip "bcm2835gpio trst_num" +proc "bcm2835gpio trst_num" args { + eval bcm2835_gpio_helper trst $args } lappend _telnet_autocomplete_skip bcm2835gpio_speed_coeffs @@ -473,74 +605,72 @@ proc bcm2835gpio_peripheral_base args { lappend _telnet_autocomplete_skip linuxgpiod_jtag_nums proc linuxgpiod_jtag_nums args { - echo "DEPRECATED! use 'linuxgpiod jtag_nums' not 'linuxgpiod_jtag_nums'" - eval linuxgpiod jtag_nums $args + eval adapter_gpio_jtag_nums $args } lappend _telnet_autocomplete_skip linuxgpiod_tck_num proc linuxgpiod_tck_num args { - echo "DEPRECATED! use 'linuxgpiod tck_num' not 'linuxgpiod_tck_num'" - eval linuxgpiod tck_num $args + eval adapter_gpio_helper tck $args } lappend _telnet_autocomplete_skip linuxgpiod_tms_num proc linuxgpiod_tms_num args { - echo "DEPRECATED! use 'linuxgpiod tms_num' not 'linuxgpiod_tms_num'" - eval linuxgpiod tms_num $args + eval adapter_gpio_helper tms $args } lappend _telnet_autocomplete_skip linuxgpiod_tdo_num proc linuxgpiod_tdo_num args { - echo "DEPRECATED! use 'linuxgpiod tdo_num' not 'linuxgpiod_tdo_num'" - eval linuxgpiod tdo_num $args + eval adapter_gpio_helper tdo $args } lappend _telnet_autocomplete_skip linuxgpiod_tdi_num proc linuxgpiod_tdi_num args { - echo "DEPRECATED! use 'linuxgpiod tdi_num' not 'linuxgpiod_tdi_num'" - eval linuxgpiod tdi_num $args + eval adapter_gpio_helper tdi $args } lappend _telnet_autocomplete_skip linuxgpiod_srst_num proc linuxgpiod_srst_num args { - echo "DEPRECATED! use 'linuxgpiod srst_num' not 'linuxgpiod_srst_num'" - eval linuxgpiod srst_num $args + eval adapter_gpio_helper srst $args } lappend _telnet_autocomplete_skip linuxgpiod_trst_num proc linuxgpiod_trst_num args { - echo "DEPRECATED! use 'linuxgpiod trst_num' not 'linuxgpiod_trst_num'" - eval linuxgpiod trst_num $args + eval adapter_gpio_helper trst $args } lappend _telnet_autocomplete_skip linuxgpiod_swd_nums proc linuxgpiod_swd_nums args { - echo "DEPRECATED! use 'linuxgpiod swd_nums' not 'linuxgpiod_swd_nums'" - eval linuxgpiod swd_nums $args + eval adapter_gpio_swd_nums $args } lappend _telnet_autocomplete_skip linuxgpiod_swclk_num proc linuxgpiod_swclk_num args { - echo "DEPRECATED! use 'linuxgpiod swclk_num' not 'linuxgpiod_swclk_num'" - eval linuxgpiod swclk_num $args + eval adapter_gpio_helper swclk $args } lappend _telnet_autocomplete_skip linuxgpiod_swdio_num proc linuxgpiod_swdio_num args { - echo "DEPRECATED! use 'linuxgpiod swdio_num' not 'linuxgpiod_swdio_num'" - eval linuxgpiod swdio_num $args + eval adapter_gpio_helper swdio $args } lappend _telnet_autocomplete_skip linuxgpiod_led_num proc linuxgpiod_led_num args { - echo "DEPRECATED! use 'linuxgpiod led_num' not 'linuxgpiod_led_num'" - eval linuxgpiod led_num $args + eval adapter_gpio_helper led $args } lappend _telnet_autocomplete_skip linuxgpiod_gpiochip proc linuxgpiod_gpiochip args { - echo "DEPRECATED! use 'linuxgpiod gpiochip' not 'linuxgpiod_gpiochip'" - eval linuxgpiod gpiochip $args + echo "DEPRECATED! use 'adapter <signal_name> -chip' not 'linuxgpiod_gpiochip'" + switch [llength $args] { + 0 { } + 1 { + foreach sig_name {tck tms tdi tdo trst srst swclk swdio swdio_dir led} { + eval adapter gpio $sig_name -chip $args + } + } + default {return -code 1 -level 1 "linuxgpiod_gpiochip: syntax error"} + } + eval adapter gpio } lappend _telnet_autocomplete_skip sysfsgpio_jtag_nums @@ -735,12 +865,6 @@ proc ft232r_restore_serial args { eval ft232r restore_serial $args } -lappend _telnet_autocomplete_skip "aice serial" -proc "aice serial" {args} { - echo "DEPRECATED! use 'adapter serial' not 'aice serial'" - eval adapter serial $args -} - lappend _telnet_autocomplete_skip cmsis_dap_serial proc cmsis_dap_serial args { echo "DEPRECATED! use 'adapter serial' not 'cmsis_dap_serial'" @@ -801,4 +925,225 @@ proc "xds110 serial" {args} { eval adapter serial $args } +lappend _telnet_autocomplete_skip linuxgpiod +# linuxgpiod command completely removed, this is required for the sub-commands to work +proc linuxgpiod {subcommand args} { + eval {"linuxgpiod $subcommand"} $args +} + +lappend _telnet_autocomplete_skip "linuxgpiod tck_num" +proc "linuxgpiod tck_num" {args} { + eval adapter_gpio_helper tck $args +} + +lappend _telnet_autocomplete_skip "linuxgpiod tms_num" +proc "linuxgpiod tms_num" {args} { + eval adapter_gpio_helper tms $args +} + +lappend _telnet_autocomplete_skip "linuxgpiod tdi_num" +proc "linuxgpiod tdi_num" {args} { + eval adapter_gpio_helper tdi $args +} + +lappend _telnet_autocomplete_skip "linuxgpiod tdo_num" +proc "linuxgpiod tdo_num" {args} { + eval adapter_gpio_helper tdo $args +} + +lappend _telnet_autocomplete_skip "linuxgpiod trst_num" +proc "linuxgpiod trst_num" {args} { + eval adapter_gpio_helper trst $args +} + +lappend _telnet_autocomplete_skip "linuxgpiod srst_num" +proc "linuxgpiod srst_num" {args} { + eval adapter_gpio_helper srst $args +} + +lappend _telnet_autocomplete_skip "linuxgpiod swclk_num" +proc "linuxgpiod swclk_num" {args} { + eval adapter_gpio_helper swclk $args +} + +lappend _telnet_autocomplete_skip "linuxgpiod swdio_num" +proc "linuxgpiod swdio_num" {args} { + eval adapter_gpio_helper swdio $args +} + +lappend _telnet_autocomplete_skip "linuxgpiod swdio_dir_num" +proc "linuxgpiod swdio_dir_num" {args} { + eval adapter_gpio_helper swdio_dir $args +} + +lappend _telnet_autocomplete_skip "linuxgpiod led_num" +proc "linuxgpiod led_num" {args} { + eval adapter_gpio_helper led $args +} + +lappend _telnet_autocomplete_skip "linuxgpiod gpiochip" +proc "linuxgpiod gpiochip" {num} { + echo "DEPRECATED! use 'adapter <signal_name> -chip' not 'linuxgpiod gpiochip'" + foreach sig_name {tck tms tdi tdo trst srst swclk swdio swdio_dir led} { + eval adapter gpio $sig_name -chip $num + } + eval adapter gpio +} + +lappend _telnet_autocomplete_skip "linuxgpiod jtag_nums" +proc "linuxgpiod jtag_nums" {tck_num tms_num tdi_num tdo_num} { + echo "DEPRECATED! use 'adapter gpio tck; adapter gpio tms; adapter gpio tdi; adapter gpio tdo' not 'linuxgpiod jtag_nums'" + eval adapter gpio tck $tck_num + eval adapter gpio tms $tms_num + eval adapter gpio tdi $tdi_num + eval adapter gpio tdo $tdo_num +} + +lappend _telnet_autocomplete_skip "linuxgpiod swd_nums" +proc "linuxgpiod swd_nums" {swclk swdio} { + echo "DEPRECATED! use 'adapter gpio swclk; adapter gpio swdio' not 'linuxgpiod jtag_nums'" + eval adapter gpio swclk $swclk + eval adapter gpio swdio $swdio +} + +lappend _telnet_autocomplete_skip "am335xgpio jtag_nums" +proc "am335xgpio jtag_nums" {tck_num tms_num tdi_num tdo_num} { + echo "DEPRECATED! use 'adapter gpio tck; adapter gpio tms; adapter gpio tdi; adapter gpio tdo' not 'am335xgpio jtag_nums'" + eval adapter gpio tck [expr {$tck_num % 32}] -chip [expr {$tck_num / 32}] + eval adapter gpio tms [expr {$tms_num % 32}] -chip [expr {$tms_num / 32}] + eval adapter gpio tdi [expr {$tdi_num % 32}] -chip [expr {$tdi_num / 32}] + eval adapter gpio tdo [expr {$tdo_num % 32}] -chip [expr {$tdo_num / 32}] +} + +lappend _telnet_autocomplete_skip "am335xgpio tck_num" +proc "am335xgpio tck_num" {num} { + echo "DEPRECATED! use 'adapter gpio tck' not 'am335xgpio tck_num'" + eval adapter gpio tck [expr {$num % 32}] -chip [expr {$num / 32}] +} + +lappend _telnet_autocomplete_skip "am335xgpio tms_num" +proc "am335xgpio tms_num" {num} { + echo "DEPRECATED! use 'adapter gpio tms' not 'am335xgpio tms_num'" + eval adapter gpio tms [expr {$num % 32}] -chip [expr {$num / 32}] +} + +lappend _telnet_autocomplete_skip "am335xgpio tdi_num" +proc "am335xgpio tdi_num" {num} { + echo "DEPRECATED! use 'adapter gpio tdi' not 'am335xgpio tdi_num'" + eval adapter gpio tdi [expr {$num % 32}] -chip [expr {$num / 32}] +} + +lappend _telnet_autocomplete_skip "am335xgpio tdo_num" +proc "am335xgpio tdo_num" {num} { + echo "DEPRECATED! use 'adapter gpio tdo' not 'am335xgpio tdo_num'" + eval adapter gpio tdo [expr {$num % 32}] -chip [expr {$num / 32}] +} + +lappend _telnet_autocomplete_skip "am335xgpio swd_nums" +proc "am335xgpio swd_nums" {swclk swdio} { + echo "DEPRECATED! use 'adapter gpio swclk; adapter gpio swdio' not 'am335xgpio jtag_nums'" + eval adapter gpio swclk [expr {$swclk % 32}] -chip [expr {$swclk / 32}] + eval adapter gpio swdio [expr {$swdio % 32}] -chip [expr {$swdio / 32}] +} + +lappend _telnet_autocomplete_skip "am335xgpio swclk_num" +proc "am335xgpio swclk_num" {num} { + echo "DEPRECATED! use 'adapter gpio swclk' not 'am335xgpio swclk_num'" + eval adapter gpio swclk [expr {$num % 32}] -chip [expr {$num / 32}] +} + +lappend _telnet_autocomplete_skip "am335xgpio swdio_num" +proc "am335xgpio swdio_num" {num} { + echo "DEPRECATED! use 'adapter gpio swdio' not 'am335xgpio swdio_num'" + eval adapter gpio swdio [expr {$num % 32}] -chip [expr {$num / 32}] +} + +lappend _telnet_autocomplete_skip "am335xgpio swdio_dir_num" +proc "am335xgpio swdio_dir_num" {num} { + echo "DEPRECATED! use 'adapter gpio swdio_dir' not 'am335xgpio swdio_dir_num'" + eval adapter gpio swdio_dir [expr {$num % 32}] -chip [expr {$num / 32}] +} + +lappend _telnet_autocomplete_skip "am335xgpio swdio_dir_output_state" +proc "am335xgpio swdio_dir_output_state" {state} { + echo "DEPRECATED! use 'adapter gpio swdio_dir -active-high' or 'adapter gpio swdio_dir -active-low', not 'am335xgpio swdio_dir_output_state'" + switch $state { + "high" + {eval adapter gpio swdio_dir -active-high} + "low" + {eval adapter gpio swdio_dir -active-low} + default + {return -code 1 -level 1 "am335xgpio swdio_dir_output_state: syntax error"} + } +} + +lappend _telnet_autocomplete_skip "am335xgpio srst_num" +proc "am335xgpio srst_num" {num} { + echo "DEPRECATED! use 'adapter gpio srst' not 'am335xgpio srst_num'" + eval adapter gpio srst [expr {$num % 32}] -chip [expr {$num / 32}] +} + +lappend _telnet_autocomplete_skip "am335xgpio trst_num" +proc "am335xgpio trst_num" {num} { + echo "DEPRECATED! use 'adapter gpio trst' not 'am335xgpio trst_num'" + eval adapter gpio trst [expr {$num % 32}] -chip [expr {$num / 32}] +} + +lappend _telnet_autocomplete_skip "am335xgpio led_num" +proc "am335xgpio led_num" {num} { + echo "DEPRECATED! use 'adapter gpio led' not 'am335xgpio led_num'" + eval adapter gpio led [expr {$num % 32}] -chip [expr {$num / 32}] +} + +lappend _telnet_autocomplete_skip "am335xgpio led_on_state" +proc "am335xgpio led_on_state" {state} { + echo "DEPRECATED! use 'adapter gpio led -active-high' or 'adapter gpio led -active-low', not 'am335xgpio led_on_state'" + switch $state { + "high" + {eval adapter gpio led -active-high} + "low" + {eval adapter gpio led -active-low} + default + {return -code 1 -level 1 "am335xgpio led_on_state: syntax error"} + } +} + +lappend _telnet_autocomplete_skip "cmsis_dap_backend" +proc "cmsis_dap_backend" {backend} { + echo "DEPRECATED! use 'cmsis-dap backend', not 'cmsis_dap_backend'" + eval cmsis-dap backend $backend +} + +lappend _telnet_autocomplete_skip "cmsis_dap_vid_pid" +proc "cmsis_dap_vid_pid" {args} { + echo "DEPRECATED! use 'cmsis-dap vid_pid', not 'cmsis_dap_vid_pid'" + eval cmsis-dap vid_pid $args +} + +lappend _telnet_autocomplete_skip "cmsis_dap_usb" +proc "cmsis_dap_usb" {args} { + echo "DEPRECATED! use 'cmsis-dap usb', not 'cmsis_dap_usb'" + eval cmsis-dap usb $args +} + +lappend _telnet_autocomplete_skip "kitprog_init_acquire_psoc" +proc "kitprog_init_acquire_psoc" {} { + echo "DEPRECATED! use 'kitprog init_acquire_psoc', not 'kitprog_init_acquire_psoc'" + eval kitprog init_acquire_psoc +} + +lappend _telnet_autocomplete_skip "pld device" +proc "pld device" {driver tap_name {opt 0}} { + echo "DEPRECATED! use 'pld create ...', not 'pld device ...'" + if {[string is integer -strict $opt]} { + if {$opt == 0} { + eval pld create [lindex [split $tap_name .] 0].pld $driver -chain-position $tap_name + } else { + eval pld create [lindex [split $tap_name .] 0].pld $driver -chain-position $tap_name -no_jstart + } + } else { + eval pld create [lindex [split $tap_name .] 0].pld $driver -chain-position $tap_name -family $opt + } +} + # END MIGRATION AIDS diff --git a/src/jtag/swd.h b/src/jtag/swd.h index 8a436d0c66..5f626c1bf8 100644 --- a/src/jtag/swd.h +++ b/src/jtag/swd.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009-2010 by David Brownell * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_SWD_H diff --git a/src/jtag/swim.c b/src/jtag/swim.c index 936268b25a..de3e106a1a 100644 --- a/src/jtag/swim.c +++ b/src/jtag/swim.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2020 by Antonio Borneo <borneo.antonio@gmail.com diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index e6e976d77d..7995529018 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -11,19 +13,6 @@ * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -42,6 +31,8 @@ #include <strings.h> #endif +#include <helper/command.h> +#include <helper/nvp.h> #include <helper/time_support.h> #include "transport/transport.h" @@ -50,7 +41,7 @@ * Holds support for accessing JTAG-specific mechanisms from TCl scripts. */ -static const struct jim_nvp nvp_jtag_tap_event[] = { +static const struct nvp nvp_jtag_tap_event[] = { { .value = JTAG_TRST_ASSERTED, .name = "post-reset" }, { .value = JTAG_TAP_EVENT_SETUP, .name = "setup" }, { .value = JTAG_TAP_EVENT_ENABLE, .name = "tap-enable" }, @@ -83,189 +74,145 @@ static bool scan_is_safe(tap_state_t state) } } -static int jim_command_drscan(Jim_Interp *interp, int argc, Jim_Obj * const *args) +static COMMAND_HELPER(handle_jtag_command_drscan_fields, struct scan_field *fields) { - int retval; - struct scan_field *fields; - int num_fields; - int field_count = 0; - int i, e; - struct jtag_tap *tap; - tap_state_t endstate; + unsigned int field_count = 0; + for (unsigned int i = 1; i < CMD_ARGC; i += 2) { + unsigned int bits; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[i], bits); + fields[field_count].num_bits = bits; - /* args[1] = device - * args[2] = num_bits - * args[3] = hex string - * ... repeat num bits and hex string ... - * - * .. optionally: - * args[N-2] = "-endstate" - * args[N-1] = statename - */ - if ((argc < 4) || ((argc % 2) != 0)) { - Jim_WrongNumArgs(interp, 1, args, "wrong arguments"); - return JIM_ERR; + void *t = malloc(DIV_ROUND_UP(bits, 8)); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + fields[field_count].out_value = t; + str_to_buf(CMD_ARGV[i + 1], strlen(CMD_ARGV[i + 1]), t, bits, 0); + fields[field_count].in_value = t; + field_count++; } - endstate = TAP_IDLE; + return ERROR_OK; +} - /* validate arguments as numbers */ - e = JIM_OK; - for (i = 2; i < argc; i += 2) { - long bits; - const char *cp; +COMMAND_HANDLER(handle_jtag_command_drscan) +{ + /* + * CMD_ARGV[0] = device + * CMD_ARGV[1] = num_bits + * CMD_ARGV[2] = hex string + * ... repeat num bits and hex string ... + * + * ... optionally: + * CMD_ARGV[CMD_ARGC-2] = "-endstate" + * CMD_ARGV[CMD_ARGC-1] = statename + */ - e = Jim_GetLong(interp, args[i], &bits); - /* If valid - try next arg */ - if (e == JIM_OK) - continue; + if (CMD_ARGC < 3 || (CMD_ARGC % 2) != 1) + return ERROR_COMMAND_SYNTAX_ERROR; - /* Not valid.. are we at the end? */ - if (((i + 2) != argc)) { - /* nope, then error */ - return e; - } + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[0]); + if (!tap) { + command_print(CMD, "Tap '%s' could not be found", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } - /* it could be: "-endstate FOO" - * e.g. DRPAUSE so we can issue more instructions - * before entering RUN/IDLE and executing them. - */ + if (tap->bypass) { + command_print(CMD, "Can't execute as the selected tap is in BYPASS"); + return ERROR_FAIL; + } - /* get arg as a string. */ - cp = Jim_GetString(args[i], NULL); - /* is it the magic? */ - if (strcmp("-endstate", cp) == 0) { - /* is the statename valid? */ - cp = Jim_GetString(args[i + 1], NULL); - - /* see if it is a valid state name */ - endstate = tap_state_by_name(cp); - if (endstate < 0) { - /* update the error message */ - Jim_SetResultFormatted(interp, "endstate: %s invalid", cp); - } else { - if (!scan_is_safe(endstate)) - LOG_WARNING("drscan with unsafe " - "endstate \"%s\"", cp); - - /* valid - so clear the error */ - e = JIM_OK; - /* and remove the last 2 args */ - argc -= 2; - } + tap_state_t endstate = TAP_IDLE; + if (CMD_ARGC > 3 && !strcmp("-endstate", CMD_ARGV[CMD_ARGC - 2])) { + const char *state_name = CMD_ARGV[CMD_ARGC - 1]; + endstate = tap_state_by_name(state_name); + if (endstate < 0) { + command_print(CMD, "endstate: %s invalid", state_name); + return ERROR_COMMAND_ARGUMENT_INVALID; } - /* Still an error? */ - if (e != JIM_OK) - return e; /* too bad */ - } /* validate args */ + if (!scan_is_safe(endstate)) + LOG_WARNING("drscan with unsafe endstate \"%s\"", state_name); - assert(e == JIM_OK); - - tap = jtag_tap_by_jim_obj(interp, args[1]); - if (!tap) - return JIM_ERR; - - num_fields = (argc-2)/2; - if (num_fields <= 0) { - Jim_SetResultString(interp, "drscan: no scan fields supplied", -1); - return JIM_ERR; + CMD_ARGC -= 2; } - fields = malloc(sizeof(struct scan_field) * num_fields); - for (i = 2; i < argc; i += 2) { - long bits; - int len; - const char *str; - - Jim_GetLong(interp, args[i], &bits); - str = Jim_GetString(args[i + 1], &len); - fields[field_count].num_bits = bits; - void *t = malloc(DIV_ROUND_UP(bits, 8)); - fields[field_count].out_value = t; - str_to_buf(str, len, t, bits, 0); - fields[field_count].in_value = t; - field_count++; + unsigned int num_fields = (CMD_ARGC - 1) / 2; + struct scan_field *fields = calloc(num_fields, sizeof(struct scan_field)); + if (!fields) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; } + int retval = CALL_COMMAND_HANDLER(handle_jtag_command_drscan_fields, fields); + if (retval != ERROR_OK) + goto fail; + jtag_add_dr_scan(tap, num_fields, fields, endstate); retval = jtag_execute_queue(); if (retval != ERROR_OK) { - Jim_SetResultString(interp, "drscan: jtag execute failed", -1); - - for (i = 0; i < field_count; i++) - free(fields[i].in_value); - free(fields); - - return JIM_ERR; + command_print(CMD, "drscan: jtag execute failed"); + goto fail; } - field_count = 0; - Jim_Obj *list = Jim_NewListObj(interp, NULL, 0); - for (i = 2; i < argc; i += 2) { - long bits; - char *str; - - Jim_GetLong(interp, args[i], &bits); - str = buf_to_hex_str(fields[field_count].in_value, bits); - free(fields[field_count].in_value); - - Jim_ListAppendElement(interp, list, Jim_NewStringObj(interp, str, strlen(str))); + for (unsigned int i = 0; i < num_fields; i++) { + char *str = buf_to_hex_str(fields[i].in_value, fields[i].num_bits); + command_print(CMD, "%s", str); free(str); - field_count++; } - Jim_SetResult(interp, list); - +fail: + for (unsigned int i = 0; i < num_fields; i++) + free(fields[i].in_value); free(fields); - return JIM_OK; + return retval; } - -static int jim_command_pathmove(Jim_Interp *interp, int argc, Jim_Obj * const *args) +COMMAND_HANDLER(handle_jtag_command_pathmove) { tap_state_t states[8]; - if ((argc < 2) || ((size_t)argc > (ARRAY_SIZE(states) + 1))) { - Jim_WrongNumArgs(interp, 1, args, "wrong arguments"); - return JIM_ERR; - } + if (CMD_ARGC < 1 || CMD_ARGC > ARRAY_SIZE(states)) + return ERROR_COMMAND_SYNTAX_ERROR; - int i; - for (i = 0; i < argc-1; i++) { - const char *cp; - cp = Jim_GetString(args[i + 1], NULL); - states[i] = tap_state_by_name(cp); + for (unsigned int i = 0; i < CMD_ARGC; i++) { + states[i] = tap_state_by_name(CMD_ARGV[i]); if (states[i] < 0) { - /* update the error message */ - Jim_SetResultFormatted(interp, "endstate: %s invalid", cp); - return JIM_ERR; + command_print(CMD, "endstate: %s invalid", CMD_ARGV[i]); + return ERROR_COMMAND_ARGUMENT_INVALID; } } - if ((jtag_add_statemove(states[0]) != ERROR_OK) || (jtag_execute_queue() != ERROR_OK)) { - Jim_SetResultString(interp, "pathmove: jtag execute failed", -1); - return JIM_ERR; + int retval = jtag_add_statemove(states[0]); + if (retval == ERROR_OK) + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + command_print(CMD, "pathmove: jtag execute failed"); + return retval; } - jtag_add_pathmove(argc - 2, states + 1); - - if (jtag_execute_queue() != ERROR_OK) { - Jim_SetResultString(interp, "pathmove: failed", -1); - return JIM_ERR; + jtag_add_pathmove(CMD_ARGC - 1, states + 1); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + command_print(CMD, "pathmove: failed"); + return retval; } - return JIM_OK; + return ERROR_OK; } - -static int jim_command_flush_count(Jim_Interp *interp, int argc, Jim_Obj * const *args) +COMMAND_HANDLER(handle_jtag_flush_count) { - Jim_SetResult(interp, Jim_NewIntObj(interp, jtag_get_flush_queue_count())); + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; - return JIM_OK; + int count = jtag_get_flush_queue_count(); + command_print_sameline(CMD, "%d", count); + + return ERROR_OK; } /* REVISIT Just what about these should "move" ... ? @@ -282,22 +229,23 @@ static const struct command_registration jtag_command_handlers_to_move[] = { { .name = "drscan", .mode = COMMAND_EXEC, - .jim_handler = jim_command_drscan, + .handler = handle_jtag_command_drscan, .help = "Execute Data Register (DR) scan for one TAP. " "Other TAPs must be in BYPASS mode.", - .usage = "tap_name [num_bits value]* ['-endstate' state_name]", + .usage = "tap_name (num_bits value)+ ['-endstate' state_name]", }, { .name = "flush_count", .mode = COMMAND_EXEC, - .jim_handler = jim_command_flush_count, + .handler = handle_jtag_flush_count, .help = "Returns the number of times the JTAG queue " "has been flushed.", + .usage = "", }, { .name = "pathmove", .mode = COMMAND_EXEC, - .jim_handler = jim_command_pathmove, + .handler = handle_jtag_command_pathmove, .usage = "start_state state1 [state2 [state3 ...]]", .help = "Move JTAG state machine from current state " "(start_state) to state1, then state2, state3, etc.", @@ -311,156 +259,104 @@ enum jtag_tap_cfg_param { JCFG_IDCODE, }; -static struct jim_nvp nvp_config_opts[] = { +static struct nvp nvp_config_opts[] = { { .name = "-event", .value = JCFG_EVENT }, { .name = "-idcode", .value = JCFG_IDCODE }, { .name = NULL, .value = -1 } }; -static int jtag_tap_configure_event(struct jim_getopt_info *goi, struct jtag_tap *tap) +static int jtag_tap_set_event(struct command_context *cmd_ctx, struct jtag_tap *tap, + const struct nvp *event, Jim_Obj *body) { - if (goi->argc == 0) { - Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event <event-name> ..."); - return JIM_ERR; - } - - struct jim_nvp *n; - int e = jim_getopt_nvp(goi, nvp_jtag_tap_event, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(goi, nvp_jtag_tap_event, 1); - return e; - } - - if (goi->isconfigure) { - if (goi->argc != 1) { - Jim_WrongNumArgs(goi->interp, - goi->argc, - goi->argv, - "-event <event-name> <event-body>"); - return JIM_ERR; - } - } else { - if (goi->argc != 0) { - Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event <event-name>"); - return JIM_ERR; - } - } + struct jtag_tap_event_action *jteap = tap->event_action; - struct jtag_tap_event_action *jteap = tap->event_action; - /* replace existing event body */ - bool found = false; while (jteap) { - if (jteap->event == (enum jtag_event)n->value) { - found = true; + if (jteap->event == (enum jtag_event)event->value) break; - } jteap = jteap->next; } - Jim_SetEmptyResult(goi->interp); - - if (goi->isconfigure) { - if (!found) - jteap = calloc(1, sizeof(*jteap)); - else if (jteap->body) - Jim_DecrRefCount(goi->interp, jteap->body); + if (!jteap) { + jteap = calloc(1, sizeof(*jteap)); + if (!jteap) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } - jteap->interp = goi->interp; - jteap->event = n->value; + /* add to head of event list */ + jteap->next = tap->event_action; + tap->event_action = jteap; + } else { + Jim_DecrRefCount(cmd_ctx->interp, jteap->body); + } - Jim_Obj *o; - jim_getopt_obj(goi, &o); - jteap->body = Jim_DuplicateObj(goi->interp, o); - Jim_IncrRefCount(jteap->body); + jteap->interp = cmd_ctx->interp; + jteap->event = (enum jtag_event)event->value; + jteap->body = Jim_DuplicateObj(cmd_ctx->interp, body); + Jim_IncrRefCount(jteap->body); - if (!found) { - /* add to head of event list */ - jteap->next = tap->event_action; - tap->event_action = jteap; - } - } else if (found) { - jteap->interp = goi->interp; - Jim_SetResult(goi->interp, - Jim_DuplicateObj(goi->interp, jteap->body)); - } - return JIM_OK; + return ERROR_OK; } -static int jtag_tap_configure_cmd(struct jim_getopt_info *goi, struct jtag_tap *tap) +__COMMAND_HANDLER(handle_jtag_configure) { - /* parse config or cget options */ - while (goi->argc > 0) { - Jim_SetEmptyResult(goi->interp); - - struct jim_nvp *n; - int e = jim_getopt_nvp(goi, nvp_config_opts, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(goi, nvp_config_opts, 0); - return e; - } + bool is_configure = !strcmp(CMD_NAME, "configure"); - switch (n->value) { - case JCFG_EVENT: - e = jtag_tap_configure_event(goi, tap); - if (e != JIM_OK) - return e; - break; - case JCFG_IDCODE: - if (goi->isconfigure) { - Jim_SetResultFormatted(goi->interp, - "not settable: %s", n->name); - return JIM_ERR; - } else { - if (goi->argc != 0) { - Jim_WrongNumArgs(goi->interp, - goi->argc, goi->argv, - "NO PARAMS"); - return JIM_ERR; - } - } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, tap->idcode)); - break; - default: - Jim_SetResultFormatted(goi->interp, "unknown value: %s", n->name); - return JIM_ERR; - } - } + if (CMD_ARGC < (is_configure ? 3 : 2)) + return ERROR_COMMAND_SYNTAX_ERROR; - return JIM_OK; -} + /* FIXME: rework jtag_tap_by_jim_obj */ + struct jtag_tap *tap = jtag_tap_by_jim_obj(CMD_CTX->interp, CMD_JIMTCL_ARGV[0]); + if (!tap) + return ERROR_FAIL; -static int is_bad_irval(int ir_length, jim_wide w) -{ - jim_wide v = 1; + for (unsigned int i = 1; i < CMD_ARGC; i++) { + const struct nvp *n = nvp_name2value(nvp_config_opts, CMD_ARGV[i]); + switch (n->value) { + case JCFG_EVENT: + if (i + (is_configure ? 2 : 1) >= CMD_ARGC) { + command_print(CMD, "wrong # args: should be \"-event <event-name>%s\"", + is_configure ? " <event-body>" : ""); + return ERROR_COMMAND_ARGUMENT_INVALID; + } - v <<= ir_length; - v -= 1; - v = ~v; - return (w & v) != 0; -} + const struct nvp *event = nvp_name2value(nvp_jtag_tap_event, CMD_ARGV[i + 1]); + if (!event->name) { + nvp_unknown_command_print(CMD, nvp_jtag_tap_event, CMD_ARGV[i], CMD_ARGV[i + 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } -static int jim_newtap_expected_id(struct jim_nvp *n, struct jim_getopt_info *goi, - struct jtag_tap *tap) -{ - jim_wide w; - int e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi->interp, "option: %s bad parameter", n->name); - return e; - } + if (is_configure) { + int retval = jtag_tap_set_event(CMD_CTX, tap, event, CMD_JIMTCL_ARGV[i + 2]); + if (retval != ERROR_OK) + return retval; + } else { + struct jtag_tap_event_action *jteap = tap->event_action; + while (jteap) { + if (jteap->event == (enum jtag_event)event->value) { + command_print(CMD, "%s", Jim_GetString(jteap->body, NULL)); + break; + } + jteap = jteap->next; + } + } - uint32_t *p = realloc(tap->expected_ids, - (tap->expected_ids_cnt + 1) * sizeof(uint32_t)); - if (!p) { - Jim_SetResultFormatted(goi->interp, "no memory"); - return JIM_ERR; + i += is_configure ? 2 : 1; + break; + case JCFG_IDCODE: + if (is_configure) { + command_print(CMD, "not settable: %s", n->name); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + command_print(CMD, "0x%08x", tap->idcode); + break; + default: + nvp_unknown_command_print(CMD, nvp_config_opts, NULL, CMD_ARGV[i]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } } - - tap->expected_ids = p; - tap->expected_ids[tap->expected_ids_cnt++] = w; - - return JIM_OK; + return ERROR_OK; } #define NTAP_OPT_IRLEN 0 @@ -471,174 +367,167 @@ static int jim_newtap_expected_id(struct jim_nvp *n, struct jim_getopt_info *goi #define NTAP_OPT_EXPECTED_ID 5 #define NTAP_OPT_VERSION 6 #define NTAP_OPT_BYPASS 7 +#define NTAP_OPT_IRBYPASS 8 + +static const struct nvp jtag_newtap_opts[] = { + { .name = "-irlen", .value = NTAP_OPT_IRLEN }, + { .name = "-irmask", .value = NTAP_OPT_IRMASK }, + { .name = "-ircapture", .value = NTAP_OPT_IRCAPTURE }, + { .name = "-enable", .value = NTAP_OPT_ENABLED }, + { .name = "-disable", .value = NTAP_OPT_DISABLED }, + { .name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID }, + { .name = "-ignore-version", .value = NTAP_OPT_VERSION }, + { .name = "-ignore-bypass", .value = NTAP_OPT_BYPASS }, + { .name = "-ir-bypass", .value = NTAP_OPT_IRBYPASS }, + { .name = NULL, .value = -1 }, +}; -static int jim_newtap_ir_param(struct jim_nvp *n, struct jim_getopt_info *goi, - struct jtag_tap *tap) +static COMMAND_HELPER(handle_jtag_newtap_args, struct jtag_tap *tap) { - jim_wide w; - int e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi->interp, - "option: %s bad parameter", n->name); - return e; + /* we expect CHIP + TAP + OPTIONS */ + if (CMD_ARGC < 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + tap->chip = strdup(CMD_ARGV[0]); + tap->tapname = strdup(CMD_ARGV[1]); + tap->dotted_name = alloc_printf("%s.%s", CMD_ARGV[0], CMD_ARGV[1]); + if (!tap->chip || !tap->tapname || !tap->dotted_name) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; } - switch (n->value) { - case NTAP_OPT_IRLEN: - if (w > (jim_wide) (8 * sizeof(tap->ir_capture_value))) { - LOG_WARNING("%s: huge IR length %d", - tap->dotted_name, (int) w); - } - tap->ir_length = w; - break; - case NTAP_OPT_IRMASK: - if (is_bad_irval(tap->ir_length, w)) { - LOG_ERROR("%s: IR mask %x too big", - tap->dotted_name, - (int) w); - return JIM_ERR; - } - if ((w & 3) != 3) - LOG_WARNING("%s: nonstandard IR mask", tap->dotted_name); - tap->ir_capture_mask = w; + CMD_ARGC -= 2; + CMD_ARGV += 2; + + LOG_DEBUG("Creating New Tap, Chip: %s, Tap: %s, Dotted: %s, %d params", + tap->chip, tap->tapname, tap->dotted_name, CMD_ARGC); + + /* + * IEEE specifies that the two LSBs of an IR scan are 01, so make + * that the default. The "-ircapture" and "-irmask" options are only + * needed to cope with nonstandard TAPs, or to specify more bits. + */ + tap->ir_capture_mask = 0x03; + tap->ir_capture_value = 0x01; + + while (CMD_ARGC) { + const struct nvp *n = nvp_name2value(jtag_newtap_opts, CMD_ARGV[0]); + CMD_ARGC--; + CMD_ARGV++; + switch (n->value) { + case NTAP_OPT_ENABLED: + tap->disabled_after_reset = false; break; - case NTAP_OPT_IRCAPTURE: - if (is_bad_irval(tap->ir_length, w)) { - LOG_ERROR("%s: IR capture %x too big", - tap->dotted_name, (int) w); - return JIM_ERR; - } - if ((w & 3) != 1) - LOG_WARNING("%s: nonstandard IR value", - tap->dotted_name); - tap->ir_capture_value = w; + + case NTAP_OPT_DISABLED: + tap->disabled_after_reset = true; break; - default: - return JIM_ERR; - } - return JIM_OK; -} -static int jim_newtap_cmd(struct jim_getopt_info *goi) -{ - struct jtag_tap *tap; - int x; - int e; - struct jim_nvp *n; - char *cp; - const struct jim_nvp opts[] = { - { .name = "-irlen", .value = NTAP_OPT_IRLEN }, - { .name = "-irmask", .value = NTAP_OPT_IRMASK }, - { .name = "-ircapture", .value = NTAP_OPT_IRCAPTURE }, - { .name = "-enable", .value = NTAP_OPT_ENABLED }, - { .name = "-disable", .value = NTAP_OPT_DISABLED }, - { .name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID }, - { .name = "-ignore-version", .value = NTAP_OPT_VERSION }, - { .name = "-ignore-bypass", .value = NTAP_OPT_BYPASS }, - { .name = NULL, .value = -1 }, - }; - - tap = calloc(1, sizeof(struct jtag_tap)); - if (!tap) { - Jim_SetResultFormatted(goi->interp, "no memory"); - return JIM_ERR; - } + case NTAP_OPT_EXPECTED_ID: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; - /* - * we expect CHIP + TAP + OPTIONS - * */ - if (goi->argc < 3) { - Jim_SetResultFormatted(goi->interp, "Missing CHIP TAP OPTIONS ...."); - free(tap); - return JIM_ERR; - } + tap->expected_ids = realloc(tap->expected_ids, + (tap->expected_ids_cnt + 1) * sizeof(uint32_t)); + if (!tap->expected_ids) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } - const char *tmp; - jim_getopt_string(goi, &tmp, NULL); - tap->chip = strdup(tmp); + uint32_t id; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], id); + CMD_ARGC--; + CMD_ARGV++; + tap->expected_ids[tap->expected_ids_cnt++] = id; - jim_getopt_string(goi, &tmp, NULL); - tap->tapname = strdup(tmp); + break; - /* name + dot + name + null */ - x = strlen(tap->chip) + 1 + strlen(tap->tapname) + 1; - cp = malloc(x); - sprintf(cp, "%s.%s", tap->chip, tap->tapname); - tap->dotted_name = cp; + case NTAP_OPT_IRLEN: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; - LOG_DEBUG("Creating New Tap, Chip: %s, Tap: %s, Dotted: %s, %d params", - tap->chip, tap->tapname, tap->dotted_name, goi->argc); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tap->ir_length); + CMD_ARGC--; + CMD_ARGV++; + if (tap->ir_length > (int)(8 * sizeof(tap->ir_capture_value))) + LOG_WARNING("%s: huge IR length %d", tap->dotted_name, tap->ir_length); + break; - if (!transport_is_jtag()) { - /* SWD doesn't require any JTAG tap parameters */ - tap->enabled = true; - jtag_tap_init(tap); - return JIM_OK; - } + case NTAP_OPT_IRMASK: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; - /* IEEE specifies that the two LSBs of an IR scan are 01, so make - * that the default. The "-ircapture" and "-irmask" options are only - * needed to cope with nonstandard TAPs, or to specify more bits. - */ - tap->ir_capture_mask = 0x03; - tap->ir_capture_value = 0x01; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], tap->ir_capture_mask); + CMD_ARGC--; + CMD_ARGV++; + if ((tap->ir_capture_mask & 3) != 3) + LOG_WARNING("%s: nonstandard IR mask", tap->dotted_name); + break; + + case NTAP_OPT_IRCAPTURE: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], tap->ir_capture_value); + CMD_ARGC--; + CMD_ARGV++; + if ((tap->ir_capture_value & 3) != 1) + LOG_WARNING("%s: nonstandard IR value", tap->dotted_name); + break; - while (goi->argc) { - e = jim_getopt_nvp(goi, opts, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(goi, opts, 0); - free(cp); - free(tap); - return e; + case NTAP_OPT_VERSION: + tap->ignore_version = true; + break; + + case NTAP_OPT_BYPASS: + tap->ignore_bypass = true; + break; + + case NTAP_OPT_IRBYPASS: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; + + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], tap->ir_bypass_value); + CMD_ARGC--; + CMD_ARGV++; + break; + + default: + nvp_unknown_command_print(CMD, jtag_newtap_opts, NULL, CMD_ARGV[-1]); + return ERROR_COMMAND_ARGUMENT_INVALID; } - LOG_DEBUG("Processing option: %s", n->name); - switch (n->value) { - case NTAP_OPT_ENABLED: - tap->disabled_after_reset = false; - break; - case NTAP_OPT_DISABLED: - tap->disabled_after_reset = true; - break; - case NTAP_OPT_EXPECTED_ID: - e = jim_newtap_expected_id(n, goi, tap); - if (e != JIM_OK) { - free(cp); - free(tap); - return e; - } - break; - case NTAP_OPT_IRLEN: - case NTAP_OPT_IRMASK: - case NTAP_OPT_IRCAPTURE: - e = jim_newtap_ir_param(n, goi, tap); - if (e != JIM_OK) { - free(cp); - free(tap); - return e; - } - break; - case NTAP_OPT_VERSION: - tap->ignore_version = true; - break; - case NTAP_OPT_BYPASS: - tap->ignore_bypass = true; - break; - } /* switch (n->value) */ - } /* while (goi->argc) */ + } /* default is enabled-after-reset */ tap->enabled = !tap->disabled_after_reset; - /* Did all the required option bits get cleared? */ - if (tap->ir_length != 0) { - jtag_tap_init(tap); - return JIM_OK; + if (transport_is_jtag() && tap->ir_length == 0) { + command_print(CMD, "newtap: %s missing IR length", tap->dotted_name); + return ERROR_COMMAND_ARGUMENT_INVALID; } - Jim_SetResultFormatted(goi->interp, - "newtap: %s missing IR length", - tap->dotted_name); - jtag_tap_free(tap); - return JIM_ERR; + return ERROR_OK; +} + +__COMMAND_HANDLER(handle_jtag_newtap) +{ + struct jtag_tap *tap = calloc(1, sizeof(struct jtag_tap)); + if (!tap) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + int retval = CALL_COMMAND_HANDLER(handle_jtag_newtap_args, tap); + if (retval != ERROR_OK) { + free(tap->chip); + free(tap->tapname); + free(tap->dotted_name); + free(tap->expected_ids); + free(tap); + return retval; + } + + jtag_tap_init(tap); + return ERROR_OK; } static void jtag_tap_handle_event(struct jtag_tap *tap, enum jtag_event e) @@ -650,7 +539,7 @@ static void jtag_tap_handle_event(struct jtag_tap *tap, enum jtag_event e) if (jteap->event != e) continue; - struct jim_nvp *nvp = jim_nvp_value2name_simple(nvp_jtag_tap_event, e); + const struct nvp *nvp = nvp_value2name(nvp_jtag_tap_event, e); LOG_DEBUG("JTAG tap: %s event: %d (%s)\n\taction: %s", tap->dotted_name, e, nvp->name, Jim_GetString(jteap->body, NULL)); @@ -682,58 +571,32 @@ static void jtag_tap_handle_event(struct jtag_tap *tap, enum jtag_event e) } } -static int jim_jtag_arp_init(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_jtag_arp_init) { - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc-1, argv + 1); - if (goi.argc != 0) { - Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)"); - return JIM_ERR; - } - struct command_context *context = current_command_context(interp); - int e = jtag_init_inner(context); - if (e != ERROR_OK) { - Jim_Obj *obj = Jim_NewIntObj(goi.interp, e); - Jim_SetResultFormatted(goi.interp, "error: %#s", obj); - return JIM_ERR; - } - return JIM_OK; + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + return jtag_init_inner(CMD_CTX); } -static int jim_jtag_arp_init_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_jtag_arp_init_reset) { - int e = ERROR_OK; - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc-1, argv + 1); - if (goi.argc != 0) { - Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)"); - return JIM_ERR; - } - struct command_context *context = current_command_context(interp); + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + if (transport_is_jtag()) - e = jtag_init_reset(context); - else if (transport_is_swd()) - e = swd_init_reset(context); - - if (e != ERROR_OK) { - Jim_Obj *obj = Jim_NewIntObj(goi.interp, e); - Jim_SetResultFormatted(goi.interp, "error: %#s", obj); - return JIM_ERR; - } - return JIM_OK; -} + return jtag_init_reset(CMD_CTX); -int jim_jtag_newtap(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc-1, argv + 1); - return jim_newtap_cmd(&goi); + if (transport_is_swd()) + return swd_init_reset(CMD_CTX); + + return ERROR_OK; } static bool jtag_tap_enable(struct jtag_tap *t) { if (t->enabled) - return false; + return true; jtag_tap_handle_event(t, JTAG_TAP_EVENT_ENABLE); if (!t->enabled) return false; @@ -748,7 +611,7 @@ static bool jtag_tap_enable(struct jtag_tap *t) static bool jtag_tap_disable(struct jtag_tap *t) { if (!t->enabled) - return false; + return true; jtag_tap_handle_event(t, JTAG_TAP_EVENT_DISABLE); if (t->enabled) return false; @@ -761,86 +624,47 @@ static bool jtag_tap_disable(struct jtag_tap *t) return true; } -int jim_jtag_tap_enabler(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +__COMMAND_HANDLER(handle_jtag_tap_enabler) { - struct command *c = jim_to_command(interp); - const char *cmd_name = c->name; - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc-1, argv + 1); - if (goi.argc != 1) { - Jim_SetResultFormatted(goi.interp, "usage: %s <name>", cmd_name); - return JIM_ERR; - } - - struct jtag_tap *t; + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; - t = jtag_tap_by_jim_obj(goi.interp, goi.argv[0]); - if (!t) - return JIM_ERR; + struct jtag_tap *t = jtag_tap_by_string(CMD_ARGV[0]); + if (!t) { + command_print(CMD, "Tap '%s' could not be found", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } - if (strcasecmp(cmd_name, "tapisenabled") == 0) { + if (strcmp(CMD_NAME, "tapisenabled") == 0) { /* do nothing, just return the value */ - } else if (strcasecmp(cmd_name, "tapenable") == 0) { + } else if (strcmp(CMD_NAME, "tapenable") == 0) { if (!jtag_tap_enable(t)) { - LOG_WARNING("failed to enable tap %s", t->dotted_name); - return JIM_ERR; + command_print(CMD, "failed to enable tap %s", t->dotted_name); + return ERROR_FAIL; } - } else if (strcasecmp(cmd_name, "tapdisable") == 0) { + } else if (strcmp(CMD_NAME, "tapdisable") == 0) { if (!jtag_tap_disable(t)) { - LOG_WARNING("failed to disable tap %s", t->dotted_name); - return JIM_ERR; + command_print(CMD, "failed to disable tap %s", t->dotted_name); + return ERROR_FAIL; } } else { - LOG_ERROR("command '%s' unknown", cmd_name); - return JIM_ERR; - } - bool e = t->enabled; - Jim_SetResult(goi.interp, Jim_NewIntObj(goi.interp, e)); - return JIM_OK; -} - -int jim_jtag_configure(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - struct command *c = jim_to_command(interp); - const char *cmd_name = c->name; - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc-1, argv + 1); - goi.isconfigure = !strcmp(cmd_name, "configure"); - if (goi.argc < 2 + goi.isconfigure) { - Jim_WrongNumArgs(goi.interp, 0, NULL, - "<tap_name> <attribute> ..."); - return JIM_ERR; + command_print(CMD, "command '%s' unknown", CMD_NAME); + return ERROR_FAIL; } - struct jtag_tap *t; - - Jim_Obj *o; - jim_getopt_obj(&goi, &o); - t = jtag_tap_by_jim_obj(goi.interp, o); - if (!t) - return JIM_ERR; - - return jtag_tap_configure_cmd(&goi, t); + command_print(CMD, "%d", t->enabled ? 1 : 0); + return ERROR_OK; } -static int jim_jtag_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_jtag_names) { - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc-1, argv + 1); - if (goi.argc != 0) { - Jim_WrongNumArgs(goi.interp, 1, goi.argv, "Too many parameters"); - return JIM_ERR; - } - Jim_SetResult(goi.interp, Jim_NewListObj(goi.interp, NULL, 0)); - struct jtag_tap *tap; + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; - for (tap = jtag_all_taps(); tap; tap = tap->next_tap) { - Jim_ListAppendElement(goi.interp, - Jim_GetResult(goi.interp), - Jim_NewStringObj(goi.interp, - tap->dotted_name, -1)); - } - return JIM_OK; + for (struct jtag_tap *tap = jtag_all_taps(); tap; tap = tap->next_tap) + command_print(CMD, "%s", tap->dotted_name); + + return ERROR_OK; } COMMAND_HANDLER(handle_jtag_init_command) @@ -870,22 +694,24 @@ static const struct command_registration jtag_subcommand_handlers[] = { { .name = "arp_init", .mode = COMMAND_ANY, - .jim_handler = jim_jtag_arp_init, + .handler = handle_jtag_arp_init, .help = "Validates JTAG scan chain against the list of " "declared TAPs using just the four standard JTAG " "signals.", + .usage = "", }, { .name = "arp_init-reset", .mode = COMMAND_ANY, - .jim_handler = jim_jtag_arp_init_reset, + .handler = handle_jtag_arp_init_reset, .help = "Uses TRST and SRST to try resetting everything on " - "the JTAG scan chain, then performs 'jtag arp_init'." + "the JTAG scan chain, then performs 'jtag arp_init'.", + .usage = "", }, { .name = "newtap", .mode = COMMAND_CONFIG, - .jim_handler = jim_jtag_newtap, + .handler = handle_jtag_newtap, .help = "Create a new TAP instance named basename.tap_type, " "and appends it to the scan chain.", .usage = "basename tap_type '-irlen' count " @@ -894,12 +720,13 @@ static const struct command_registration jtag_subcommand_handlers[] = { "['-ignore-version'] " "['-ignore-bypass'] " "['-ircapture' number] " + "['-ir-bypass' number] " "['-mask' number]", }, { .name = "tapisenabled", .mode = COMMAND_EXEC, - .jim_handler = jim_jtag_tap_enabler, + .handler = handle_jtag_tap_enabler, .help = "Returns a Tcl boolean (0/1) indicating whether " "the TAP is enabled (1) or not (0).", .usage = "tap_name", @@ -907,7 +734,7 @@ static const struct command_registration jtag_subcommand_handlers[] = { { .name = "tapenable", .mode = COMMAND_EXEC, - .jim_handler = jim_jtag_tap_enabler, + .handler = handle_jtag_tap_enabler, .help = "Try to enable the specified TAP using the " "'tap-enable' TAP event.", .usage = "tap_name", @@ -915,7 +742,7 @@ static const struct command_registration jtag_subcommand_handlers[] = { { .name = "tapdisable", .mode = COMMAND_EXEC, - .jim_handler = jim_jtag_tap_enabler, + .handler = handle_jtag_tap_enabler, .help = "Try to disable the specified TAP using the " "'tap-disable' TAP event.", .usage = "tap_name", @@ -923,7 +750,7 @@ static const struct command_registration jtag_subcommand_handlers[] = { { .name = "configure", .mode = COMMAND_ANY, - .jim_handler = jim_jtag_configure, + .handler = handle_jtag_configure, .help = "Provide a Tcl handler for the specified " "TAP event.", .usage = "tap_name '-event' event_name handler", @@ -931,7 +758,7 @@ static const struct command_registration jtag_subcommand_handlers[] = { { .name = "cget", .mode = COMMAND_EXEC, - .jim_handler = jim_jtag_configure, + .handler = handle_jtag_configure, .help = "Return any Tcl handler for the specified " "TAP event.", .usage = "tap_name '-event' event_name", @@ -939,8 +766,9 @@ static const struct command_registration jtag_subcommand_handlers[] = { { .name = "names", .mode = COMMAND_ANY, - .jim_handler = jim_jtag_names, + .handler = handle_jtag_names, .help = "Returns list of all JTAG tap names.", + .usage = "", }, { .chain = jtag_command_handlers_to_move, diff --git a/src/jtag/tcl.h b/src/jtag/tcl.h index 932b47ac8a..4e49e8579f 100644 --- a/src/jtag/tcl.h +++ b/src/jtag/tcl.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -11,27 +13,14 @@ * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_JTAG_TCL_H #define OPENOCD_JTAG_TCL_H -int jim_jtag_configure(Jim_Interp *interp, int argc, - Jim_Obj * const *argv); -int jim_jtag_tap_enabler(Jim_Interp *interp, int argc, - Jim_Obj * const *argv); +#include <helper/command.h> + +__COMMAND_HANDLER(handle_jtag_configure); +__COMMAND_HANDLER(handle_jtag_tap_enabler); #endif /* OPENOCD_JTAG_TCL_H */ diff --git a/src/main.c b/src/main.c index a437b6b4c9..a36e6b55fa 100644 --- a/src/main.c +++ b/src/main.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/openocd.c b/src/openocd.c index 3c96d32145..54c5eb34f7 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 Richard Missenden * * richard.missenden@googlemail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -62,24 +51,23 @@ static const char openocd_startup_tcl[] = { }; /* Give scripts and TELNET a way to find out what version this is */ -static int jim_version_command(Jim_Interp *interp, int argc, - Jim_Obj * const *argv) +COMMAND_HANDLER(handler_version_command) { - if (argc > 2) - return JIM_ERR; - const char *str = ""; - char *version_str; - version_str = OPENOCD_VERSION; + char *version_str = OPENOCD_VERSION; - if (argc == 2) - str = Jim_GetString(argv[1], NULL); + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (CMD_ARGC == 1) { + if (strcmp("git", CMD_ARGV[0])) + return ERROR_COMMAND_ARGUMENT_INVALID; - if (strcmp("git", str) == 0) version_str = GITVERSION; + } - Jim_SetResult(interp, Jim_NewStringObj(interp, version_str, -1)); + command_print(CMD, "%s", version_str); - return JIM_OK; + return ERROR_OK; } static int log_target_callback_event_handler(struct target *target, @@ -130,6 +118,8 @@ COMMAND_HANDLER(handle_init_command) initialized = 1; + bool save_poll_mask = jtag_poll_mask(); + retval = command_run_line(CMD_CTX, "target init"); if (retval != ERROR_OK) return ERROR_FAIL; @@ -177,11 +167,16 @@ COMMAND_HANDLER(handle_init_command) if (command_run_line(CMD_CTX, "tpiu init") != ERROR_OK) return ERROR_FAIL; + jtag_poll_unmask(save_poll_mask); + /* initialize telnet subsystem */ gdb_target_add_all(all_targets); target_register_event_callback(log_target_callback_event_handler, CMD_CTX); + if (command_run_line(CMD_CTX, "_run_post_init_commands") != ERROR_OK) + return ERROR_FAIL; + return ERROR_OK; } @@ -198,9 +193,10 @@ COMMAND_HANDLER(handle_add_script_search_dir_command) static const struct command_registration openocd_command_handlers[] = { { .name = "version", - .jim_handler = jim_version_command, + .handler = handler_version_command, .mode = COMMAND_ANY, .help = "show program version", + .usage = "[git]", }, { .name = "noinit", @@ -234,65 +230,6 @@ static int openocd_register_commands(struct command_context *cmd_ctx) return register_commands(cmd_ctx, NULL, openocd_command_handlers); } -/* - * TODO: to be removed after v0.12.0 - * workaround for syntax change of "expr" in jimtcl 0.81 - * replace "expr" with openocd version that prints the deprecated msg - */ -struct jim_scriptobj { - void *token; - Jim_Obj *filename_obj; - int len; - int subst_flags; - int in_use; - int firstline; - int linenr; - int missing; -}; - -static int jim_expr_command(Jim_Interp *interp, int argc, Jim_Obj * const *argv) -{ - if (argc == 2) - return Jim_EvalExpression(interp, argv[1]); - - if (argc > 2) { - Jim_Obj *obj = Jim_ConcatObj(interp, argc - 1, argv + 1); - Jim_IncrRefCount(obj); - const char *s = Jim_String(obj); - struct jim_scriptobj *script = Jim_GetIntRepPtr(interp->currentScriptObj); - if (interp->currentScriptObj == interp->emptyObj || - strcmp(interp->currentScriptObj->typePtr->name, "script") || - script->subst_flags || - script->filename_obj == interp->emptyObj) - LOG_WARNING("DEPRECATED! use 'expr { %s }' not 'expr %s'", s, s); - else - LOG_WARNING("DEPRECATED! (%s:%d) use 'expr { %s }' not 'expr %s'", - Jim_String(script->filename_obj), script->linenr, s, s); - int retcode = Jim_EvalExpression(interp, obj); - Jim_DecrRefCount(interp, obj); - return retcode; - } - - Jim_WrongNumArgs(interp, 1, argv, "expression ?...?"); - return JIM_ERR; -} - -static const struct command_registration expr_handler[] = { - { - .name = "expr", - .jim_handler = jim_expr_command, - .mode = COMMAND_ANY, - .help = "", - .usage = "", - }, - COMMAND_REGISTRATION_DONE -}; - -static int workaround_for_jimtcl_expr(struct command_context *cmd_ctx) -{ - return register_commands(cmd_ctx, NULL, expr_handler); -} - struct command_context *global_cmd_ctx; static struct command_context *setup_command_handler(Jim_Interp *interp) @@ -305,7 +242,6 @@ static struct command_context *setup_command_handler(Jim_Interp *interp) /* register subsystem commands */ typedef int (*command_registrant_t)(struct command_context *cmd_ctx_value); static const command_registrant_t command_registrants[] = { - &workaround_for_jimtcl_expr, &openocd_register_commands, &server_register_commands, &gdb_register_commands, diff --git a/src/openocd.h b/src/openocd.h index 543ac3c239..1c2a633c76 100644 --- a/src/openocd.h +++ b/src/openocd.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> * * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_OPENOCD_H diff --git a/src/pld/Makefile.am b/src/pld/Makefile.am index 7f3a554231..69e457c96a 100644 --- a/src/pld/Makefile.am +++ b/src/pld/Makefile.am @@ -1,8 +1,27 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libpld.la %C%_libpld_la_SOURCES = \ + %D%/certus.c \ + %D%/ecp2_3.c \ + %D%/ecp5.c \ + %D%/efinix.c \ + %D%/gatemate.c \ + %D%/gowin.c \ + %D%/intel.c \ + %D%/lattice.c \ + %D%/lattice_bit.c \ %D%/pld.c \ + %D%/raw_bit.c \ %D%/xilinx_bit.c \ %D%/virtex2.c \ + %D%/certus.h \ + %D%/ecp2_3.h \ + %D%/ecp5.h \ + %D%/lattice.h \ + %D%/lattice_bit.h \ + %D%/lattice_cmd.h \ %D%/pld.h \ + %D%/raw_bit.h \ %D%/xilinx_bit.h \ %D%/virtex2.h diff --git a/src/pld/certus.c b/src/pld/certus.c new file mode 100644 index 0000000000..ccb3feb90c --- /dev/null +++ b/src/pld/certus.c @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "certus.h" +#include "lattice.h" +#include "lattice_cmd.h" + +#define LSC_ENABLE_X 0x74 +#define LSC_REFRESH 0x79 +#define LSC_DEVICE_CTRL 0x7D + +int lattice_certus_read_status(struct jtag_tap *tap, uint64_t *status, uint64_t out) +{ + return lattice_read_u64_register(tap, LSC_READ_STATUS, status, out); +} + +int lattice_certus_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out) +{ + return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, false); +} + +int lattice_certus_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode) +{ + LOG_ERROR("Not supported to write usercode on certus devices"); + return ERROR_FAIL; +} + +static int lattice_certus_enable_transparent_mode(struct jtag_tap *tap) +{ + struct scan_field field; + + int retval = lattice_set_instr(tap, LSC_ENABLE_X, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + uint8_t buffer = 0x0; + field.num_bits = 8; + field.out_value = &buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(2, TAP_IDLE); + + return jtag_execute_queue(); +} + +static int lattice_certus_erase_device(struct lattice_pld_device *lattice_device) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_set_instr(tap, LSC_DEVICE_CTRL, TAP_IRPAUSE); + if (retval != ERROR_OK) + return retval; + + struct scan_field field; + uint8_t buffer = 8; + field.num_bits = 8; + field.out_value = &buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(2, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + retval = lattice_set_instr(tap, LSC_DEVICE_CTRL, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + buffer = 0; + field.num_bits = 8; + field.out_value = &buffer; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(2, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + retval = lattice_set_instr(tap, ISC_ERASE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + buffer = 0; + field.num_bits = 8; + field.out_value = &buffer; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(100, TAP_IDLE); + jtag_add_sleep(5000); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + /* check done is cleared and fail is cleared */ + const uint64_t status_done_flag = 0x100; + const uint64_t status_fail_flag = 0x2000; + return lattice_verify_status_register_u64(lattice_device, 0x0, 0x0, status_done_flag | status_fail_flag); +} + +static int lattice_certus_enable_programming(struct jtag_tap *tap) +{ + struct scan_field field; + + int retval = lattice_set_instr(tap, LSC_REFRESH, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + uint8_t buffer = 0; + field.num_bits = 8; + field.out_value = &buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(2, TAP_IDLE); + return jtag_execute_queue(); +} + +static int lattice_certus_init_address(struct jtag_tap *tap) +{ + int retval = lattice_set_instr(tap, LSC_INIT_ADDRESS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2, TAP_IDLE); + return jtag_execute_queue(); +} + +static int lattice_certus_exit_programming_mode(struct jtag_tap *tap) +{ + int retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2, TAP_IDLE); + retval = lattice_set_instr(tap, BYPASS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(100, TAP_IDLE); + return jtag_execute_queue(); +} + +static int lattice_certus_program_config_map(struct jtag_tap *tap, struct lattice_bit_file *bit_file) +{ + struct scan_field field; + + int retval = lattice_set_instr(tap, LSC_BITSTREAM_BURST, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + field.num_bits = (bit_file->raw_bit.length - bit_file->offset) * 8; + field.out_value = bit_file->raw_bit.data + bit_file->offset; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + + return jtag_execute_queue(); +} + +int lattice_certus_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_preload(lattice_device); + if (retval != ERROR_OK) + return retval; + + /* check password protection is disabled */ + const uint64_t status_pwd_protection = 0x20000; + retval = lattice_verify_status_register_u64(lattice_device, 0x0, 0x0, status_pwd_protection); + if (retval != ERROR_OK) { + LOG_ERROR("Password protection is set"); + return retval; + } + + retval = lattice_certus_enable_transparent_mode(tap); + if (retval != ERROR_OK) + return retval; + + /* Check the SRAM Erase Lock */ + const uint64_t status_otp = 0x40; + retval = lattice_verify_status_register_u64(lattice_device, 0x0, status_otp, status_otp); + if (retval != ERROR_OK) { + LOG_ERROR("NV User Feature Sector OTP is Set"); + return retval; + } + + /* Check the SRAM Lock */ + const uint64_t status_write_protected = 0x400; + retval = lattice_verify_status_register_u64(lattice_device, 0x0, 0x0, status_write_protected); + if (retval != ERROR_OK) { + LOG_ERROR("NV User Feature Sector OTP is Set"); + return retval; + } + + retval = lattice_certus_enable_programming(tap); + if (retval != ERROR_OK) { + LOG_ERROR("failed to enable programming mode"); + return retval; + } + + retval = lattice_certus_erase_device(lattice_device); + if (retval != ERROR_OK) { + LOG_ERROR("erasing device failed"); + return retval; + } + + retval = lattice_certus_init_address(tap); + if (retval != ERROR_OK) + return retval; + + retval = lattice_certus_program_config_map(tap, bit_file); + if (retval != ERROR_OK) + return retval; + const uint32_t expected = 0x100; // done + const uint32_t mask = expected | + 0x3000 | // Busy Flag and Fail Flag + 0xf000000; // BSE Error + retval = lattice_verify_status_register_u64(lattice_device, 0x0, 0x100, mask); + if (retval != ERROR_OK) + return retval; + + return lattice_certus_exit_programming_mode(tap); +} + +int lattice_certus_connect_spi_to_jtag(struct lattice_pld_device *pld_device_info) +{ + if (!pld_device_info) + return ERROR_FAIL; + + struct jtag_tap *tap = pld_device_info->tap; + if (!tap) + return ERROR_FAIL; + + if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) == PROGRAM_SPI) + return ERROR_OK; + + // erase configuration + int retval = lattice_preload(pld_device_info); + if (retval != ERROR_OK) + return retval; + + retval = lattice_certus_enable_programming(tap); + if (retval != ERROR_OK) + return retval; + + retval = lattice_certus_erase_device(pld_device_info); + if (retval != ERROR_OK) { + LOG_ERROR("erasing device failed"); + return retval; + } + + retval = lattice_certus_exit_programming_mode(tap); + if (retval != ERROR_OK) + return retval; + + // connect jtag to spi pins + retval = lattice_set_instr(tap, PROGRAM_SPI, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + struct scan_field field; + uint8_t buffer[2] = {0xfe, 0x68}; + field.num_bits = 16; + field.out_value = buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + + return jtag_execute_queue(); +} + +int lattice_certus_disconnect_spi_from_jtag(struct lattice_pld_device *pld_device_info) +{ + if (!pld_device_info) + return ERROR_FAIL; + + struct jtag_tap *tap = pld_device_info->tap; + if (!tap) + return ERROR_FAIL; + + /* Connecting it again takes way too long to do it multiple times for writing + a bitstream (ca. 0.4s each access). + We just leave it connected since SCS will not be active when not in shift_dr state. + So there is no need to change instruction, just make sure we are not in shift dr state. */ + jtag_add_runtest(2, TAP_IDLE); + return jtag_execute_queue(); +} + +int lattice_certus_get_facing_read_bits(struct lattice_pld_device *pld_device_info, unsigned int *facing_read_bits) +{ + if (!pld_device_info) + return ERROR_FAIL; + + *facing_read_bits = 0; + + return ERROR_OK; +} + +int lattice_certus_refresh(struct lattice_pld_device *lattice_device) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_preload(lattice_device); + if (retval != ERROR_OK) + return retval; + + retval = lattice_set_instr(tap, LSC_REFRESH, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(200000); + retval = lattice_set_instr(tap, BYPASS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(100, TAP_IDLE); + jtag_add_sleep(1000); + + return jtag_execute_queue(); +} diff --git a/src/pld/certus.h b/src/pld/certus.h new file mode 100644 index 0000000000..0fbfdef45c --- /dev/null +++ b/src/pld/certus.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifndef OPENOCD_PLD_CERTUS_H +#define OPENOCD_PLD_CERTUS_H + +#include "lattice.h" + +int lattice_certus_read_status(struct jtag_tap *tap, uint64_t *status, uint64_t out); +int lattice_certus_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out); +int lattice_certus_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode); +int lattice_certus_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file); +int lattice_certus_connect_spi_to_jtag(struct lattice_pld_device *pld_device_info); +int lattice_certus_disconnect_spi_from_jtag(struct lattice_pld_device *pld_device_info); +int lattice_certus_get_facing_read_bits(struct lattice_pld_device *pld_device_info, unsigned int *facing_read_bits); +int lattice_certus_refresh(struct lattice_pld_device *lattice_device); + +#endif /* OPENOCD_PLD_CERTUS_H */ diff --git a/src/pld/ecp2_3.c b/src/pld/ecp2_3.c new file mode 100644 index 0000000000..5dfea9a277 --- /dev/null +++ b/src/pld/ecp2_3.c @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ecp2_3.h" +#include "lattice.h" + +#define LSCC_REFRESH 0x23 +#define ISC_ENABLE 0x15 +#define LSCC_RESET_ADDRESS 0x21 +#define ISC_PROGRAM_USERCODE 0x1A +#define ISC_ERASE 0x03 +#define READ_USERCODE 0x17 +#define ISC_DISABLE 0x1E +#define LSCC_READ_STATUS 0x53 +#define LSCC_BITSTREAM_BURST 0x02 +#define PROGRAM_SPI 0x3A + +#define STATUS_DONE_BIT 0x00020000 +#define STATUS_ERROR_BITS_ECP2 0x00040003 +#define STATUS_ERROR_BITS_ECP3 0x00040007 +#define REGISTER_ALL_BITS_1 0xffffffff +#define REGISTER_ALL_BITS_0 0x00000000 + +int lattice_ecp2_3_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle) +{ + return lattice_read_u32_register(tap, LSCC_READ_STATUS, status, out, do_idle); +} + +int lattice_ecp2_3_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out) +{ + return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, false); +} + +int lattice_ecp2_3_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(20000); + + retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + struct scan_field field; + uint8_t buffer[4]; + h_u32_to_le(buffer, usercode); + field.num_bits = 32; + field.out_value = buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(2000); + + retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(200000); + + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + return lattice_verify_usercode(lattice_device, 0x0, usercode, REGISTER_ALL_BITS_1); +} + +static int lattice_ecp2_3_erase_device(struct lattice_pld_device *lattice_device) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + /* program user code with all bits set */ + int retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IRPAUSE); + if (retval != ERROR_OK) + return retval; + struct scan_field field; + uint8_t buffer[4] = {0xff, 0xff, 0xff, 0xff}; + field.num_bits = 32; + field.out_value = buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(2000); + + /* verify every bit is set */ + const uint32_t out = REGISTER_ALL_BITS_1; + const uint32_t mask = REGISTER_ALL_BITS_1; + const uint32_t expected_pre = REGISTER_ALL_BITS_1; + retval = lattice_verify_usercode(lattice_device, out, expected_pre, mask); + if (retval != ERROR_OK) + return retval; + + retval = lattice_set_instr(tap, ISC_ERASE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + if (lattice_device->family == LATTICE_ECP2) + jtag_add_sleep(100000); + else + jtag_add_sleep(2000000); + + retval = lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(2000); + + /* after erasing check all bits in user register are cleared */ + const uint32_t expected_post = REGISTER_ALL_BITS_0; + return lattice_verify_usercode(lattice_device, out, expected_post, mask); +} + +static int lattice_ecp2_3_program_config_map(struct lattice_pld_device *lattice_device, + struct lattice_bit_file *bit_file) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(2000); + + struct scan_field field; + retval = lattice_set_instr(tap, LSCC_BITSTREAM_BURST, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + field.num_bits = (bit_file->raw_bit.length - bit_file->offset) * 8; + field.out_value = bit_file->raw_bit.data + bit_file->offset; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(256, TAP_IDLE); + jtag_add_sleep(2000); + return jtag_execute_queue(); +} + +static int lattice_ecp2_3_exit_programming_mode(struct lattice_pld_device *lattice_device) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(200000); + retval = lattice_set_instr(tap, BYPASS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(100, TAP_IDLE); + jtag_add_sleep(1000); + return jtag_execute_queue(); +} + +int lattice_ecp2_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_preload(lattice_device); + if (retval != ERROR_OK) + return retval; + + /* Enable the programming mode */ + retval = lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(20000); + + /* Erase the device */ + retval = lattice_ecp2_3_erase_device(lattice_device); + if (retval != ERROR_OK) + return retval; + + /* Program Fuse Map */ + retval = lattice_ecp2_3_program_config_map(lattice_device, bit_file); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp2_3_exit_programming_mode(lattice_device); + if (retval != ERROR_OK) + return retval; + + const uint32_t out = REGISTER_ALL_BITS_1; + const uint32_t mask = STATUS_DONE_BIT | STATUS_ERROR_BITS_ECP2; + const uint32_t expected = STATUS_DONE_BIT; + return lattice_verify_status_register_u32(lattice_device, out, expected, mask, false); +} + +int lattice_ecp3_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + /* Program Bscan register */ + int retval = lattice_preload(lattice_device); + if (retval != ERROR_OK) + return retval; + + /* Enable the programming mode */ + retval = lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(500000); + retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(20000); + + retval = lattice_ecp2_3_erase_device(lattice_device); + if (retval != ERROR_OK) + return retval; + + /* Program Fuse Map */ + retval = lattice_ecp2_3_program_config_map(lattice_device, bit_file); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp2_3_exit_programming_mode(lattice_device); + if (retval != ERROR_OK) + return retval; + + const uint32_t out = REGISTER_ALL_BITS_1; + const uint32_t mask = STATUS_DONE_BIT | STATUS_ERROR_BITS_ECP3; + const uint32_t expected = STATUS_DONE_BIT; + return lattice_verify_status_register_u32(lattice_device, out, expected, mask, false); +} + +int lattice_ecp2_3_connect_spi_to_jtag(struct lattice_pld_device *pld_device_info) +{ + if (!pld_device_info) + return ERROR_FAIL; + + struct jtag_tap *tap = pld_device_info->tap; + if (!tap) + return ERROR_FAIL; + + // erase configuration + int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + retval = lattice_set_instr(tap, ISC_ERASE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + // connect jtag to spi pins + retval = lattice_set_instr(tap, PROGRAM_SPI, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + return jtag_execute_queue(); +} + +int lattice_ecp2_3_disconnect_spi_from_jtag(struct lattice_pld_device *pld_device_info) +{ + if (!pld_device_info) + return ERROR_FAIL; + + struct jtag_tap *tap = pld_device_info->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_set_instr(tap, BYPASS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + return jtag_execute_queue(); +} + +int lattice_ecp2_3_get_facing_read_bits(struct lattice_pld_device *pld_device_info, unsigned int *facing_read_bits) +{ + if (!pld_device_info) + return ERROR_FAIL; + + *facing_read_bits = 1; + + return ERROR_OK; +} + +int lattice_ecp2_3_refresh(struct lattice_pld_device *lattice_device) +{ + if (!lattice_device || !lattice_device->tap) + return ERROR_FAIL; + + int retval = lattice_set_instr(lattice_device->tap, LSCC_REFRESH, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + return jtag_execute_queue(); +} diff --git a/src/pld/ecp2_3.h b/src/pld/ecp2_3.h new file mode 100644 index 0000000000..d3f7464e12 --- /dev/null +++ b/src/pld/ecp2_3.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifndef OPENOCD_PLD_ECP2_3_H +#define OPENOCD_PLD_ECP2_3_H + +#include "lattice.h" + +int lattice_ecp2_3_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle); +int lattice_ecp2_3_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out); +int lattice_ecp2_3_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode); +int lattice_ecp2_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file); +int lattice_ecp3_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file); +int lattice_ecp2_3_connect_spi_to_jtag(struct lattice_pld_device *pld_device_info); +int lattice_ecp2_3_disconnect_spi_from_jtag(struct lattice_pld_device *pld_device_info); +int lattice_ecp2_3_get_facing_read_bits(struct lattice_pld_device *pld_device_info, unsigned int *facing_read_bits); +int lattice_ecp2_3_refresh(struct lattice_pld_device *lattice_device); + +#endif /* OPENOCD_PLD_ECP2_3_H */ diff --git a/src/pld/ecp5.c b/src/pld/ecp5.c new file mode 100644 index 0000000000..f8ba33eaff --- /dev/null +++ b/src/pld/ecp5.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ecp5.h" +#include "lattice.h" +#include "lattice_cmd.h" + +#define ISC_PROGRAM_USERCODE 0xC2 + +#define STATUS_DONE_BIT 0x00000100 +#define STATUS_ERROR_BITS 0x00020040 +#define STATUS_FEA_OTP 0x00004000 +#define STATUS_FAIL_FLAG 0x00002000 +#define STATUS_BUSY_FLAG 0x00001000 +#define REGISTER_ALL_BITS_1 0xffffffff + +int lattice_ecp5_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle) +{ + return lattice_read_u32_register(tap, LSC_READ_STATUS, status, out, do_idle); +} + +int lattice_ecp5_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out) +{ + return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, true); +} + +int lattice_ecp5_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(20000); + + retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + uint8_t buffer[4]; + struct scan_field field; + h_u32_to_le(buffer, usercode); + field.num_bits = 32; + field.out_value = buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(2000); + + retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(200000); + + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + return lattice_verify_usercode(lattice_device, 0x0, usercode, REGISTER_ALL_BITS_1); +} + +static int lattice_ecp5_enable_sram_programming(struct jtag_tap *tap) +{ + int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + struct scan_field field; + uint8_t buffer = 0x0; + field.num_bits = 8; + field.out_value = &buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(10000); + + return jtag_execute_queue(); +} + +static int lattice_ecp5_erase_sram(struct jtag_tap *tap) +{ + int retval = lattice_set_instr(tap, ISC_ERASE, TAP_IRPAUSE); + if (retval != ERROR_OK) + return retval; + + struct scan_field field; + uint8_t buffer = 1; + field.num_bits = 8; + field.out_value = &buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(200000); + return jtag_execute_queue(); +} + +static int lattice_ecp5_init_address(struct jtag_tap *tap) +{ + int retval = lattice_set_instr(tap, LSC_INIT_ADDRESS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + struct scan_field field; + uint8_t buffer = 1; + field.num_bits = 8; + field.out_value = &buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(10000); + return jtag_execute_queue(); +} + +static int lattice_ecp5_program_config_map(struct jtag_tap *tap, struct lattice_bit_file *bit_file) +{ + int retval = lattice_set_instr(tap, LSC_BITSTREAM_BURST, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(10000); + + struct scan_field field; + field.num_bits = (bit_file->raw_bit.length - bit_file->offset) * 8; + field.out_value = bit_file->raw_bit.data + bit_file->offset; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + retval = lattice_set_instr(tap, BYPASS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(100, TAP_IDLE); + jtag_add_sleep(10000); + + return jtag_execute_queue(); +} + +static int lattice_ecp5_exit_programming_mode(struct jtag_tap *tap) +{ + int retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(200000); + retval = lattice_set_instr(tap, BYPASS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(1000); + return jtag_execute_queue(); +} + +int lattice_ecp5_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_preload(lattice_device); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp5_enable_sram_programming(tap); + if (retval != ERROR_OK) + return retval; + + const uint32_t out = 0x0; + const uint32_t expected1 = 0x0; + const uint32_t mask1 = STATUS_ERROR_BITS | STATUS_FEA_OTP; + retval = lattice_verify_status_register_u32(lattice_device, out, expected1, mask1, true); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp5_erase_sram(tap); + if (retval != ERROR_OK) + return retval; + + const uint32_t mask2 = STATUS_FAIL_FLAG | STATUS_BUSY_FLAG; + retval = lattice_verify_status_register_u32(lattice_device, out, expected1, mask2, false); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp5_init_address(tap); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp5_program_config_map(tap, bit_file); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp5_exit_programming_mode(tap); + if (retval != ERROR_OK) + return retval; + + const uint32_t expected2 = STATUS_DONE_BIT; + const uint32_t mask3 = STATUS_DONE_BIT | STATUS_FAIL_FLAG; + return lattice_verify_status_register_u32(lattice_device, out, expected2, mask3, false); +} + +int lattice_ecp5_connect_spi_to_jtag(struct lattice_pld_device *pld_device_info) +{ + if (!pld_device_info) + return ERROR_FAIL; + + struct jtag_tap *tap = pld_device_info->tap; + if (!tap) + return ERROR_FAIL; + + if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) == PROGRAM_SPI) + return ERROR_OK; + + // erase configuration + int retval = lattice_preload(pld_device_info); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp5_enable_sram_programming(tap); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp5_erase_sram(tap); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp5_exit_programming_mode(tap); + if (retval != ERROR_OK) + return retval; + + // connect jtag to spi pins + retval = lattice_set_instr(tap, PROGRAM_SPI, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + struct scan_field field; + uint8_t buffer[2] = {0xfe, 0x68}; + field.num_bits = 16; + field.out_value = buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + + return jtag_execute_queue(); +} + +int lattice_ecp5_disconnect_spi_from_jtag(struct lattice_pld_device *pld_device_info) +{ + if (!pld_device_info) + return ERROR_FAIL; + + struct jtag_tap *tap = pld_device_info->tap; + if (!tap) + return ERROR_FAIL; + + /* Connecting it again takes way too long to do it multiple times for writing + a bitstream (ca. 0.4s each access). + We just leave it connected since SCS will not be active when not in shift_dr state. + So there is no need to change instruction, just make sure we are not in shift dr state. */ + jtag_add_runtest(2, TAP_IDLE); + return jtag_execute_queue(); +} + +int lattice_ecp5_get_facing_read_bits(struct lattice_pld_device *pld_device_info, unsigned int *facing_read_bits) +{ + if (!pld_device_info) + return ERROR_FAIL; + + *facing_read_bits = 0; + + return ERROR_OK; +} + +int lattice_ecp5_refresh(struct lattice_pld_device *lattice_device) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_preload(lattice_device); + if (retval != ERROR_OK) + return retval; + + retval = lattice_set_instr(tap, LSC_REFRESH, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(200000); + retval = lattice_set_instr(tap, BYPASS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(100, TAP_IDLE); + jtag_add_sleep(1000); + + return jtag_execute_queue(); +} diff --git a/src/pld/ecp5.h b/src/pld/ecp5.h new file mode 100644 index 0000000000..975678ece3 --- /dev/null +++ b/src/pld/ecp5.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifndef OPENOCD_PLD_ECP5_H +#define OPENOCD_PLD_ECP5_H + +#include "lattice.h" + +int lattice_ecp5_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle); +int lattice_ecp5_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out); +int lattice_ecp5_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode); +int lattice_ecp5_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file); +int lattice_ecp5_connect_spi_to_jtag(struct lattice_pld_device *pld_device_info); +int lattice_ecp5_disconnect_spi_from_jtag(struct lattice_pld_device *pld_device_info); +int lattice_ecp5_get_facing_read_bits(struct lattice_pld_device *pld_device_info, unsigned int *facing_read_bits); +int lattice_ecp5_refresh(struct lattice_pld_device *lattice_device); + +#endif /* OPENOCD_PLD_ECP5_H */ diff --git a/src/pld/efinix.c b/src/pld/efinix.c new file mode 100644 index 0000000000..b6e5f9e477 --- /dev/null +++ b/src/pld/efinix.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <jtag/jtag.h> + +#include "pld.h" +#include "raw_bit.h" + +#define PROGRAM 0x4 +#define ENTERUSER 0x7 +#define USER1 0x8 +#define USER2 0x9 +#define USER3 0xa +#define USER4 0xb + +enum efinix_family_e { + EFINIX_TRION, + EFINIX_TITANIUM, + EFINIX_UNKNOWN +}; + +#define TRAILING_ZEROS 4000 +#define RUNTEST_START_CYCLES 100 +#define RUNTEST_FINISH_CYCLES 100 + +struct efinix_device { + uint32_t idcode; + int num_user; +}; + +struct efinix_pld_device { + struct jtag_tap *tap; + enum efinix_family_e family; +}; + +static int efinix_read_bit_file(struct raw_bit_file *bit_file, const char *filename) +{ + FILE *input_file = fopen(filename, "r"); + if (!input_file) { + LOG_ERROR("couldn't open %s: %s", filename, strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + fseek(input_file, 0, SEEK_END); + long length = ftell(input_file); + fseek(input_file, 0, SEEK_SET); + + if (length < 0 || ((length % 3))) { + fclose(input_file); + LOG_ERROR("Failed to get length from file %s: %s", filename, strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + bit_file->length = DIV_ROUND_UP(length, 3); + + bit_file->data = malloc(bit_file->length); + if (!bit_file->data) { + fclose(input_file); + LOG_ERROR("Out of memory"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + bool end_detected = false; + char buffer[3]; + for (size_t idx = 0; !end_detected && idx < bit_file->length; ++idx) { + size_t read_count = fread(buffer, sizeof(char), 3, input_file); + end_detected = feof(input_file); + if ((read_count == 3 && buffer[2] != '\n') || + (read_count != 3 && !end_detected) || + (read_count != 2 && end_detected)) { + fclose(input_file); + free(bit_file->data); + bit_file->data = NULL; + LOG_ERROR("unexpected line length"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (!isxdigit(buffer[0]) || !isxdigit(buffer[1])) { + fclose(input_file); + free(bit_file->data); + bit_file->data = NULL; + LOG_ERROR("unexpected char in hex string"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + unhexify(&bit_file->data[idx], buffer, 2); + } + + fclose(input_file); + + return ERROR_OK; +} + +static int efinix_read_file(struct raw_bit_file *bit_file, const char *filename) +{ + if (!filename || !bit_file) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* check if binary .bin or ascii .bit/.hex */ + const char *file_ending_pos = strrchr(filename, '.'); + if (!file_ending_pos) { + LOG_ERROR("Unable to detect filename suffix"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (strcasecmp(file_ending_pos, ".bin") == 0) { + return cpld_read_raw_bit_file(bit_file, filename); + } else if ((strcasecmp(file_ending_pos, ".bit") == 0) || + (strcasecmp(file_ending_pos, ".hex") == 0)) { + return efinix_read_bit_file(bit_file, filename); + } + + LOG_ERROR("Unable to detect filetype"); + return ERROR_PLD_FILE_LOAD_FAILED; +} + +static int efinix_set_instr(struct jtag_tap *tap, uint8_t new_instr) +{ + struct scan_field field; + field.num_bits = tap->ir_length; + void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + field.out_value = t; + buf_set_u32(t, 0, field.num_bits, new_instr); + field.in_value = NULL; + jtag_add_ir_scan(tap, &field, TAP_IDLE); + free(t); + return ERROR_OK; +} + +static int efinix_load(struct pld_device *pld_device, const char *filename) +{ + struct raw_bit_file bit_file; + struct scan_field field[2]; + + if (!pld_device || !pld_device->driver_priv) + return ERROR_FAIL; + + struct efinix_pld_device *efinix_info = pld_device->driver_priv; + if (!efinix_info || !efinix_info->tap) + return ERROR_FAIL; + struct jtag_tap *tap = efinix_info->tap; + + jtag_add_tlr(); + + int retval = efinix_set_instr(tap, PROGRAM); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(RUNTEST_START_CYCLES, TAP_IDLE); + retval = efinix_set_instr(tap, PROGRAM); /* fix for T20 */ + if (retval != ERROR_OK) + return retval; + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + retval = efinix_read_file(&bit_file, filename); + if (retval != ERROR_OK) + return retval; + + for (size_t i = 0; i < bit_file.length; i++) + bit_file.data[i] = flip_u32(bit_file.data[i], 8); + + /* shift in the bitstream */ + field[0].num_bits = bit_file.length * 8; + field[0].out_value = bit_file.data; + field[0].in_value = NULL; + + /* followed by zeros */ + field[1].num_bits = TRAILING_ZEROS; + uint8_t *buf = calloc(TRAILING_ZEROS / 8, 1); + if (!buf) { + free(bit_file.data); + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + field[1].out_value = buf; + field[1].in_value = NULL; + + jtag_add_dr_scan(tap, 2, field, TAP_DRPAUSE); + retval = jtag_execute_queue(); + free(bit_file.data); + free(buf); + if (retval != ERROR_OK) + return retval; + + retval = efinix_set_instr(tap, ENTERUSER); + if (retval != ERROR_OK) + return retval; + + /* entering RUN/TEST for 100 cycles */ + jtag_add_runtest(RUNTEST_FINISH_CYCLES, TAP_IDLE); + retval = jtag_execute_queue(); + + return retval; +} + +static int efinix_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +{ + if (!pld_device) + return ERROR_FAIL; + + struct efinix_pld_device *pld_device_info = pld_device->driver_priv; + + if (!pld_device_info || !pld_device_info->tap) + return ERROR_FAIL; + + hub->tap = pld_device_info->tap; + + if (pld_device_info->family == EFINIX_UNKNOWN) { + LOG_ERROR("family unknown, please specify for 'pld create'"); + return ERROR_FAIL; + } + int num_user = 2; /* trion */ + if (pld_device_info->family == EFINIX_TITANIUM) + num_user = 4; + + if (user_num > num_user) { + LOG_ERROR("Devices has only user register 1 to %d", num_user); + return ERROR_FAIL; + } + + switch (user_num) { + case 1: + hub->user_ir_code = USER1; + break; + case 2: + hub->user_ir_code = USER2; + break; + case 3: + hub->user_ir_code = USER3; + break; + case 4: + hub->user_ir_code = USER4; + break; + default: + LOG_ERROR("efinix devices only have user register 1 to %d", num_user); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int efinix_get_jtagspi_userircode(struct pld_device *pld_device, unsigned int *ir) +{ + *ir = USER1; + return ERROR_OK; +} + +PLD_CREATE_COMMAND_HANDLER(efinix_pld_create_command) +{ + if (CMD_ARGC != 4 && CMD_ARGC != 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcmp(CMD_ARGV[2], "-chain-position") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); + if (!tap) { + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); + return ERROR_FAIL; + } + + enum efinix_family_e family = EFINIX_UNKNOWN; + if (CMD_ARGC == 6) { + if (strcmp(CMD_ARGV[4], "-family") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcmp(CMD_ARGV[5], "trion") == 0) { + family = EFINIX_TRION; + } else if (strcmp(CMD_ARGV[5], "titanium") == 0) { + family = EFINIX_TITANIUM; + } else { + command_print(CMD, "unknown family"); + return ERROR_FAIL; + } + } + + struct efinix_pld_device *efinix_info = malloc(sizeof(struct efinix_pld_device)); + if (!efinix_info) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + efinix_info->tap = tap; + efinix_info->family = family; + + pld->driver_priv = efinix_info; + + return ERROR_OK; +} + +struct pld_driver efinix_pld = { + .name = "efinix", + .pld_create_command = &efinix_pld_create_command, + .load = &efinix_load, + .get_ipdbg_hub = efinix_get_ipdbg_hub, + .get_jtagspi_userircode = efinix_get_jtagspi_userircode, +}; diff --git a/src/pld/gatemate.c b/src/pld/gatemate.c new file mode 100644 index 0000000000..f35b39ad21 --- /dev/null +++ b/src/pld/gatemate.c @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <jtag/jtag.h> +#include <jtag/adapter.h> +#include "pld.h" +#include "raw_bit.h" + +#define JTAG_CONFIGURE 0x06 +#define JTAG_SPI_BYPASS 0x05 +#define BYPASS 0x3F + +struct gatemate_pld_device { + struct jtag_tap *tap; +}; + +struct gatemate_bit_file { + struct raw_bit_file raw_file; + size_t capacity; +}; + +static int gatemate_add_byte_to_bitfile(struct gatemate_bit_file *bit_file, uint8_t byte) +{ + const size_t chunk_size = 8192; + if (bit_file->raw_file.length + 1 > bit_file->capacity) { + uint8_t *buffer; + if (bit_file->raw_file.data) + buffer = realloc(bit_file->raw_file.data, bit_file->capacity + chunk_size); + else + buffer = malloc(chunk_size); + if (!buffer) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + bit_file->raw_file.data = buffer; + bit_file->capacity += chunk_size; + } + + bit_file->raw_file.data[bit_file->raw_file.length++] = byte; + + return ERROR_OK; +} + +static int gatemate_read_cfg_line(struct gatemate_bit_file *bit_file, const char *line_buffer, size_t nread) +{ + for (size_t idx = 0; idx < nread; ++idx) { + if (line_buffer[idx] == ' ') { + continue; + } else if (line_buffer[idx] == 0) { + break; + } else if (idx + 1 < nread) { + if (isxdigit(line_buffer[idx]) && isxdigit(line_buffer[idx + 1])) { + uint8_t byte; + unhexify(&byte, line_buffer + idx, 2); + int retval = gatemate_add_byte_to_bitfile(bit_file, byte); + if (retval != ERROR_OK) + return retval; + } else if (line_buffer[idx] == '/' && line_buffer[idx + 1] == '/') { + break; + } + ++idx; + } else { + LOG_ERROR("parsing failed"); + return ERROR_FAIL; + } + } + return ERROR_OK; +} + +static int gatemate_getline(char **buffer, size_t *buf_size, FILE *input_file) +{ + const size_t chunk_size = 32; + if (!*buffer) + *buf_size = 0; + + size_t read = 0; + do { + if (read + 1 > *buf_size) { + char *new_buffer; + if (*buffer) + new_buffer = realloc(*buffer, *buf_size + chunk_size); + else + new_buffer = malloc(chunk_size); + if (!new_buffer) { + LOG_ERROR("Out of memory"); + return -1; + } + *buffer = new_buffer; + *buf_size += chunk_size; + } + + int c = fgetc(input_file); + if ((c == EOF && read) || (char)c == '\n') { + (*buffer)[read++] = 0; + return read; + } else if (c == EOF) { + return -1; + } + + (*buffer)[read++] = (char)c; + } while (1); + + return -1; +} + +static int gatemate_read_cfg_file(struct gatemate_bit_file *bit_file, const char *filename) +{ + FILE *input_file = fopen(filename, "r"); + + if (!input_file) { + LOG_ERROR("Couldn't open %s: %s", filename, strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + int retval = ERROR_OK; + char *line_buffer = NULL; + size_t buffer_length = 0; + int nread; + while (((nread = gatemate_getline(&line_buffer, &buffer_length, input_file)) != -1) && (retval == ERROR_OK)) + retval = gatemate_read_cfg_line(bit_file, line_buffer, (size_t)nread); + + if (line_buffer) + free(line_buffer); + + fclose(input_file); + if (retval != ERROR_OK) + free(bit_file->raw_file.data); + return retval; +} + +static int gatemate_read_file(struct gatemate_bit_file *bit_file, const char *filename) +{ + memset(bit_file, 0, sizeof(struct gatemate_bit_file)); + + if (!filename || !bit_file) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* check if binary .bit or ascii .cfg */ + const char *file_suffix_pos = strrchr(filename, '.'); + if (!file_suffix_pos) { + LOG_ERROR("Unable to detect filename suffix"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (strcasecmp(file_suffix_pos, ".bit") == 0) + return cpld_read_raw_bit_file(&bit_file->raw_file, filename); + else if (strcasecmp(file_suffix_pos, ".cfg") == 0) + return gatemate_read_cfg_file(bit_file, filename); + + LOG_ERROR("Filetype not supported, expecting .bit or .cfg file"); + return ERROR_PLD_FILE_LOAD_FAILED; +} + +static int gatemate_set_instr(struct jtag_tap *tap, uint8_t new_instr) +{ + struct scan_field field; + field.num_bits = tap->ir_length; + void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + field.out_value = t; + buf_set_u32(t, 0, field.num_bits, new_instr); + field.in_value = NULL; + jtag_add_ir_scan(tap, &field, TAP_IDLE); + jtag_add_runtest(3, TAP_IDLE); + free(t); + return ERROR_OK; +} + +static int gatemate_load(struct pld_device *pld_device, const char *filename) +{ + if (!pld_device) + return ERROR_FAIL; + + struct gatemate_pld_device *gatemate_info = pld_device->driver_priv; + + if (!gatemate_info || !gatemate_info->tap) + return ERROR_FAIL; + struct jtag_tap *tap = gatemate_info->tap; + + struct gatemate_bit_file bit_file; + int retval = gatemate_read_file(&bit_file, filename); + if (retval != ERROR_OK) + return retval; + + retval = gatemate_set_instr(tap, JTAG_CONFIGURE); + if (retval != ERROR_OK) { + free(bit_file.raw_file.data); + return retval; + } + + struct scan_field field; + field.num_bits = bit_file.raw_file.length * 8; + field.out_value = bit_file.raw_file.data; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + + retval = jtag_execute_queue(); + free(bit_file.raw_file.data); + + return retval; +} + +static int gatemate_has_jtagspi_instruction(struct pld_device *device, bool *has_instruction) +{ + *has_instruction = true; + return ERROR_OK; +} + +static int gatemate_connect_spi_to_jtag(struct pld_device *pld_device) +{ + if (!pld_device) + return ERROR_FAIL; + + struct gatemate_pld_device *pld_device_info = pld_device->driver_priv; + if (!pld_device_info) + return ERROR_FAIL; + + struct jtag_tap *tap = pld_device_info->tap; + if (!tap) + return ERROR_FAIL; + + if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) == JTAG_SPI_BYPASS) + return ERROR_OK; + + gatemate_set_instr(tap, JTAG_SPI_BYPASS); + + return jtag_execute_queue(); +} + +static int gatemate_disconnect_spi_from_jtag(struct pld_device *pld_device) +{ + if (!pld_device) + return ERROR_FAIL; + + struct gatemate_pld_device *pld_device_info = pld_device->driver_priv; + if (!pld_device_info) + return ERROR_FAIL; + + struct jtag_tap *tap = pld_device_info->tap; + if (!tap) + return ERROR_FAIL; + + if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != JTAG_SPI_BYPASS) + return ERROR_OK; + + gatemate_set_instr(tap, BYPASS); + + return jtag_execute_queue(); +} + +static int gatemate_get_stuff_bits(struct pld_device *pld_device, unsigned int *facing_read_bits, + unsigned int *trailing_write_bits) +{ + if (!pld_device) + return ERROR_FAIL; + + *facing_read_bits = 1; + *trailing_write_bits = 1; + + return ERROR_OK; +} + +PLD_CREATE_COMMAND_HANDLER(gatemate_pld_create_command) +{ + if (CMD_ARGC != 4) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcmp(CMD_ARGV[2], "-chain-position") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); + if (!tap) { + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); + return ERROR_FAIL; + } + + struct gatemate_pld_device *gatemate_info = malloc(sizeof(struct gatemate_pld_device)); + if (!gatemate_info) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + gatemate_info->tap = tap; + + pld->driver_priv = gatemate_info; + + return ERROR_OK; +} + +struct pld_driver gatemate_pld = { + .name = "gatemate", + .pld_create_command = &gatemate_pld_create_command, + .load = &gatemate_load, + .has_jtagspi_instruction = gatemate_has_jtagspi_instruction, + .connect_spi_to_jtag = gatemate_connect_spi_to_jtag, + .disconnect_spi_from_jtag = gatemate_disconnect_spi_from_jtag, + .get_stuff_bits = gatemate_get_stuff_bits, +}; diff --git a/src/pld/gowin.c b/src/pld/gowin.c new file mode 100644 index 0000000000..bbc2fe15f6 --- /dev/null +++ b/src/pld/gowin.c @@ -0,0 +1,598 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <jtag/jtag.h> +#include <jtag/adapter.h> +#include <helper/bits.h> +#include "pld.h" +#include "raw_bit.h" + +#define NO_OP 0x02 +#define ERASE_SRAM 0x05 +#define SRAM_ERASE_DONE 0x09 +#define IDCODE 0x11 +#define ADDRESS_INITIALIZATION 0x12 +#define READ_USERCODE 0x13 +#define CONFIG_ENABLE 0x15 +#define TRANSFER_CONFIGURATION_DATA 0x17 +#define CONFIG_DISABLE 0x3A +#define RELOAD 0x3C +#define STATUS_REGISTER 0x41 +#define ERASE_FLASH 0x75 +#define ENABLE_2ND_FLASH 0x78 + +#define USER1 0x42 +#define USER2 0x43 + +#define STAUS_MASK_MEMORY_ERASE BIT(5) +#define STAUS_MASK_SYSTEM_EDIT_MODE BIT(7) + +struct gowin_pld_device { + struct jtag_tap *tap; +}; + +struct gowin_bit_file { + struct raw_bit_file raw_file; + size_t capacity; + uint32_t id; + uint16_t stored_checksum; + int compressed; + int crc_en; + uint16_t checksum; + uint8_t replace8x; + uint8_t replace4x; + uint8_t replace2x; +}; + +static uint64_t gowin_read_fs_file_bitsequence(const char *bits, int length) +{ + uint64_t res = 0; + for (int i = 0; i < length; i++) + res = (res << 1) | (*bits++ == '1' ? 1 : 0); + return res; +} + +static int gowin_add_byte_to_bit_file(struct gowin_bit_file *bit_file, uint8_t byte) +{ + if (bit_file->raw_file.length + 1 > bit_file->capacity) { + uint8_t *buffer; + if (bit_file->raw_file.data) + buffer = realloc(bit_file->raw_file.data, bit_file->capacity + 8192); + else + buffer = malloc(8192); + if (!buffer) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + bit_file->raw_file.data = buffer; + bit_file->capacity += 8192; + } + + bit_file->raw_file.data[bit_file->raw_file.length++] = byte; + + return ERROR_OK; +} + +static int gowin_read_fs_file_header(struct gowin_bit_file *bit_file, FILE *stream) +{ + if (!bit_file) + return ERROR_FAIL; + + int end_of_header = 0; + while (!end_of_header) { + char buffer[256]; + char *line = fgets(buffer, 256, stream); + if (!line || feof(stream) || ferror(stream)) + return ERROR_FAIL; + + if (line[0] == '/') + continue; + + size_t line_length = strlen(line); + if (line[line_length - 1] != '\n') + return ERROR_FAIL; + line_length--; + + for (unsigned int i = 0; i < line_length; i += 8) { + uint8_t byte = gowin_read_fs_file_bitsequence(line + i, 8); + int retval = gowin_add_byte_to_bit_file(bit_file, byte); + if (retval != ERROR_OK) + return retval; + } + + uint8_t key = gowin_read_fs_file_bitsequence(line, 8); + line += 8; + uint64_t value = gowin_read_fs_file_bitsequence(line, line_length - 8); + + if (key == 0x06) { + bit_file->id = value & 0xffffffff; + } else if (key == 0x3B) { + end_of_header = 1; + bit_file->crc_en = (value & BIT(23)) ? 1 : 0; + } + } + + return ERROR_OK; +} + +static int gowin_read_fs_file(struct gowin_bit_file *bit_file, const char *filename) +{ + FILE *input_file = fopen(filename, "r"); + + if (!input_file) { + LOG_ERROR("Couldn't open %s: %s", filename, strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + int retval = gowin_read_fs_file_header(bit_file, input_file); + if (retval != ERROR_OK) { + free(bit_file->raw_file.data); + fclose(input_file); + return retval; + } + + char digits_buffer[9]; /* 8 + 1 trailing zero */ + do { + char *digits = fgets(digits_buffer, 9, input_file); + if (feof(input_file)) + break; + if (!digits || ferror(input_file)) { + free(bit_file->raw_file.data); + fclose(input_file); + return ERROR_FAIL; + } + if (digits[0] == '\n') + continue; + + if (strlen(digits) != 8) { + free(bit_file->raw_file.data); + fclose(input_file); + return ERROR_FAIL; + } + uint8_t byte = gowin_read_fs_file_bitsequence(digits, 8); + retval = gowin_add_byte_to_bit_file(bit_file, byte); + if (retval != ERROR_OK) { + free(bit_file->raw_file.data); + fclose(input_file); + return ERROR_FAIL; + } + } while (1); + + fclose(input_file); + return ERROR_OK; +} + +static int gowin_read_file(struct gowin_bit_file *bit_file, const char *filename, bool *is_fs) +{ + memset(bit_file, 0, sizeof(struct gowin_bit_file)); + + if (!filename || !bit_file) + return ERROR_COMMAND_SYNTAX_ERROR; + + const char *file_suffix_pos = strrchr(filename, '.'); + if (!file_suffix_pos) { + LOG_ERROR("Unable to detect filename suffix"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + /* check if binary .bin or ascii .fs */ + if (strcasecmp(file_suffix_pos, ".bin") == 0) { + *is_fs = false; + return cpld_read_raw_bit_file(&bit_file->raw_file, filename); + } else if (strcasecmp(file_suffix_pos, ".fs") == 0) { + *is_fs = true; + return gowin_read_fs_file(bit_file, filename); + } + + LOG_ERROR("Filetype not supported, expecting .fs or .bin file"); + return ERROR_PLD_FILE_LOAD_FAILED; +} + +static int gowin_set_instr(struct jtag_tap *tap, uint8_t new_instr) +{ + struct scan_field field; + field.num_bits = tap->ir_length; + void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + field.out_value = t; + buf_set_u32(t, 0, field.num_bits, new_instr); + field.in_value = NULL; + jtag_add_ir_scan(tap, &field, TAP_IDLE); + jtag_add_runtest(3, TAP_IDLE); + free(t); + return ERROR_OK; +} + +static int gowin_read_register(struct jtag_tap *tap, uint32_t reg, uint32_t *result) +{ + struct scan_field field; + + int retval = gowin_set_instr(tap, reg); + if (retval != ERROR_OK) + return retval; + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + uint8_t buf[4] = {0}; + field.check_mask = NULL; + field.check_value = NULL; + field.num_bits = 32; + field.out_value = buf; + field.in_value = buf; + + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + retval = jtag_execute_queue(); + *result = le_to_h_u32(buf); + return retval; +} + +static int gowin_check_status_flag(struct jtag_tap *tap, uint32_t mask, uint32_t flag) +{ + uint32_t status = 0; + + int retries = 0; + do { + int retval = gowin_read_register(tap, STATUS_REGISTER, &status); + if (retval != ERROR_OK) + return retval; + if (retries++ == 100000) + return ERROR_FAIL; + } while ((status & mask) != flag); + + return ERROR_OK; +} + +static int gowin_enable_config(struct jtag_tap *tap) +{ + int retval = gowin_set_instr(tap, CONFIG_ENABLE); + if (retval != ERROR_OK) + return retval; + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + return gowin_check_status_flag(tap, STAUS_MASK_SYSTEM_EDIT_MODE, STAUS_MASK_SYSTEM_EDIT_MODE); +} + +static int gowin_disable_config(struct jtag_tap *tap) +{ + int retval = gowin_set_instr(tap, CONFIG_DISABLE); + if (retval != ERROR_OK) + return retval; + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + return gowin_check_status_flag(tap, STAUS_MASK_SYSTEM_EDIT_MODE, 0); +} + +static int gowin_reload(struct jtag_tap *tap) +{ + int retval = gowin_set_instr(tap, RELOAD); + if (retval != ERROR_OK) + return retval; + retval = gowin_set_instr(tap, NO_OP); + if (retval != ERROR_OK) + return retval; + return jtag_execute_queue(); +} + +static int gowin_runtest_idle(struct jtag_tap *tap, unsigned int frac_sec) +{ + int speed = adapter_get_speed_khz() * 1000; + int cycles = DIV_ROUND_UP(speed, frac_sec); + jtag_add_runtest(cycles, TAP_IDLE); + return jtag_execute_queue(); +} + +static int gowin_erase_sram(struct jtag_tap *tap, bool tx_erase_done) +{ + /* config is already enabled */ + int retval = gowin_set_instr(tap, ERASE_SRAM); + if (retval != ERROR_OK) + return retval; + retval = gowin_set_instr(tap, NO_OP); + if (retval != ERROR_OK) + return retval; + + /* Delay or Run Test 2~10ms */ + /* 10 ms is worst case for GW2A-55 */ + jtag_add_sleep(10000); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + retval = gowin_check_status_flag(tap, STAUS_MASK_MEMORY_ERASE, + STAUS_MASK_MEMORY_ERASE); + if (retval != ERROR_OK) + return retval; + + if (tx_erase_done) { + retval = gowin_set_instr(tap, SRAM_ERASE_DONE); + if (retval != ERROR_OK) + return retval; + retval = gowin_set_instr(tap, NO_OP); + if (retval != ERROR_OK) + return retval; + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + /* gen clock cycles in RUN/IDLE for 500us -> 1/500us = 2000/s */ + retval = gowin_runtest_idle(tap, 2000); + if (retval != ERROR_OK) + return retval; + } + + retval = gowin_set_instr(tap, NO_OP); + if (retval != ERROR_OK) + return retval; + return jtag_execute_queue(); +} + +static int gowin_load_to_sram(struct pld_device *pld_device, const char *filename) +{ + if (!pld_device) + return ERROR_FAIL; + + struct gowin_pld_device *gowin_info = pld_device->driver_priv; + + if (!gowin_info || !gowin_info->tap) + return ERROR_FAIL; + struct jtag_tap *tap = gowin_info->tap; + + bool is_fs = false; + struct gowin_bit_file bit_file; + int retval = gowin_read_file(&bit_file, filename, &is_fs); + if (retval != ERROR_OK) + return retval; + + for (unsigned int i = 0; i < bit_file.raw_file.length; i++) + bit_file.raw_file.data[i] = flip_u32(bit_file.raw_file.data[i], 8); + + uint32_t id; + retval = gowin_read_register(tap, IDCODE, &id); + if (retval != ERROR_OK) { + free(bit_file.raw_file.data); + return retval; + } + + if (is_fs && id != bit_file.id) { + free(bit_file.raw_file.data); + LOG_ERROR("Id on device (0x%8.8" PRIx32 ") and id in bit-stream (0x%8.8" PRIx32 ") don't match.", + id, bit_file.id); + return ERROR_FAIL; + } + + retval = gowin_enable_config(tap); + if (retval != ERROR_OK) { + free(bit_file.raw_file.data); + return retval; + } + + retval = gowin_erase_sram(tap, false); + if (retval != ERROR_OK) { + free(bit_file.raw_file.data); + return retval; + } + + retval = gowin_set_instr(tap, ADDRESS_INITIALIZATION); + if (retval != ERROR_OK) { + free(bit_file.raw_file.data); + return retval; + } + retval = gowin_set_instr(tap, TRANSFER_CONFIGURATION_DATA); + if (retval != ERROR_OK) { + free(bit_file.raw_file.data); + return retval; + } + + /* scan out the bitstream */ + struct scan_field field; + field.num_bits = bit_file.raw_file.length * 8; + field.out_value = bit_file.raw_file.data; + field.in_value = bit_file.raw_file.data; + jtag_add_dr_scan(gowin_info->tap, 1, &field, TAP_IDLE); + jtag_add_runtest(3, TAP_IDLE); + + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + free(bit_file.raw_file.data); + return retval; + } + + retval = gowin_disable_config(tap); + free(bit_file.raw_file.data); + if (retval != ERROR_OK) + return retval; + + retval = gowin_set_instr(gowin_info->tap, NO_OP); + if (retval != ERROR_OK) + return retval; + + retval = jtag_execute_queue(); + + return retval; +} + +static int gowin_read_register_command(struct pld_device *pld_device, uint32_t cmd, uint32_t *value) +{ + if (!pld_device) + return ERROR_FAIL; + + struct gowin_pld_device *gowin_info = pld_device->driver_priv; + + if (!gowin_info || !gowin_info->tap) + return ERROR_FAIL; + + return gowin_read_register(gowin_info->tap, cmd, value); +} + +static int gowin_reload_command(struct pld_device *pld_device) +{ + if (!pld_device) + return ERROR_FAIL; + + struct gowin_pld_device *gowin_info = pld_device->driver_priv; + + if (!gowin_info || !gowin_info->tap) + return ERROR_FAIL; + + return gowin_reload(gowin_info->tap); +} + +static int gowin_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +{ + if (!pld_device) + return ERROR_FAIL; + + struct gowin_pld_device *pld_device_info = pld_device->driver_priv; + + if (!pld_device_info || !pld_device_info->tap) + return ERROR_FAIL; + + hub->tap = pld_device_info->tap; + + if (user_num == 1) { + hub->user_ir_code = USER1; + } else if (user_num == 2) { + hub->user_ir_code = USER2; + } else { + LOG_ERROR("gowin devices only have user register 1 & 2"); + return ERROR_FAIL; + } + return ERROR_OK; +} + +COMMAND_HANDLER(gowin_read_status_command_handler) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + uint32_t status = 0; + int retval = gowin_read_register_command(device, STATUS_REGISTER, &status); + + if (retval == ERROR_OK) + command_print(CMD, "0x%8.8" PRIx32, status); + + return retval; +} + +COMMAND_HANDLER(gowin_read_user_register_command_handler) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + uint32_t user_reg = 0; + int retval = gowin_read_register_command(device, READ_USERCODE, &user_reg); + + if (retval == ERROR_OK) + command_print(CMD, "0x%8.8" PRIx32, user_reg); + + return retval; +} + +COMMAND_HANDLER(gowin_reload_command_handler) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + return gowin_reload_command(device); +} + +static const struct command_registration gowin_exec_command_handlers[] = { + { + .name = "read_status", + .mode = COMMAND_EXEC, + .handler = gowin_read_status_command_handler, + .help = "reading status register from FPGA", + .usage = "pld_name", + }, { + .name = "read_user", + .mode = COMMAND_EXEC, + .handler = gowin_read_user_register_command_handler, + .help = "reading user register from FPGA", + .usage = "pld_name", + }, { + .name = "refresh", + .mode = COMMAND_EXEC, + .handler = gowin_reload_command_handler, + .help = "reload bitstream from flash to SRAM", + .usage = "pld_name", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration gowin_command_handler[] = { + { + .name = "gowin", + .mode = COMMAND_ANY, + .help = "gowin specific commands", + .usage = "", + .chain = gowin_exec_command_handlers + }, + COMMAND_REGISTRATION_DONE +}; + +PLD_CREATE_COMMAND_HANDLER(gowin_pld_create_command) +{ + if (CMD_ARGC != 4) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcmp(CMD_ARGV[2], "-chain-position") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); + if (!tap) { + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); + return ERROR_FAIL; + } + + struct gowin_pld_device *gowin_info = malloc(sizeof(struct gowin_pld_device)); + if (!gowin_info) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + gowin_info->tap = tap; + + pld->driver_priv = gowin_info; + + return ERROR_OK; +} + +struct pld_driver gowin_pld = { + .name = "gowin", + .commands = gowin_command_handler, + .pld_create_command = &gowin_pld_create_command, + .load = &gowin_load_to_sram, + .get_ipdbg_hub = gowin_get_ipdbg_hub, +}; diff --git a/src/pld/intel.c b/src/pld/intel.c new file mode 100644 index 0000000000..a39e16c212 --- /dev/null +++ b/src/pld/intel.c @@ -0,0 +1,507 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <jtag/jtag.h> +#include <jtag/adapter.h> +#include <helper/system.h> +#include <helper/log.h> + +#include "pld.h" +#include "raw_bit.h" + +#define BYPASS 0x3FF +#define USER0 0x00C +#define USER1 0x00E + +enum intel_family_e { + INTEL_CYCLONEIII, + INTEL_CYCLONEIV, + INTEL_CYCLONEV, + INTEL_CYCLONE10, + INTEL_ARRIAII, + INTEL_UNKNOWN +}; + +struct intel_pld_device { + struct jtag_tap *tap; + unsigned int boundary_scan_length; + int checkpos; + enum intel_family_e family; +}; + +struct intel_device_parameters_elem { + uint32_t id; + unsigned int boundary_scan_length; + int checkpos; + enum intel_family_e family; +}; + +static const struct intel_device_parameters_elem intel_device_parameters[] = { + {0x020f10dd, 603, 226, INTEL_CYCLONEIII}, /* EP3C5 EP3C10 */ + {0x020f20dd, 1080, 409, INTEL_CYCLONEIII}, /* EP3C16 */ + {0x020f30dd, 732, 286, INTEL_CYCLONEIII}, /* EP3C25 */ + {0x020f40dd, 1632, 604, INTEL_CYCLONEIII}, /* EP3C40 */ + {0x020f50dd, 1164, 442, INTEL_CYCLONEIII}, /* EP3C55 */ + {0x020f60dd, 1314, 502, INTEL_CYCLONEIII}, /* EP3C80 */ + {0x020f70dd, 1620, 613, INTEL_CYCLONEIII}, /* EP3C120*/ + {0x027010dd, 1314, 226, INTEL_CYCLONEIII}, /* EP3CLS70 */ + {0x027000dd, 1314, 226, INTEL_CYCLONEIII}, /* EP3CLS100 */ + {0x027030dd, 1314, 409, INTEL_CYCLONEIII}, /* EP3CLS150 */ + {0x027020dd, 1314, 409, INTEL_CYCLONEIII}, /* EP3CLS200 */ + + {0x020f10dd, 603, 226, INTEL_CYCLONEIV}, /* EP4CE6 EP4CE10 */ + {0x020f20dd, 1080, 409, INTEL_CYCLONEIV}, /* EP4CE15 */ + {0x020f30dd, 732, 286, INTEL_CYCLONEIV}, /* EP4CE22 */ + {0x020f40dd, 1632, 604, INTEL_CYCLONEIV}, /* EP4CE30 EP4CE40 */ + {0x020f50dd, 1164, 442, INTEL_CYCLONEIV}, /* EP4CE55 */ + {0x020f60dd, 1314, 502, INTEL_CYCLONEIV}, /* EP4CE75 */ + {0x020f70dd, 1620, 613, INTEL_CYCLONEIV}, /* EP4CE115 */ + {0x028010dd, 260, 229, INTEL_CYCLONEIV}, /* EP4CGX15 */ + {0x028120dd, 494, 463, INTEL_CYCLONEIV}, /* EP4CGX22 */ + {0x028020dd, 494, 463, INTEL_CYCLONEIV}, /* EP4CGX30 */ + {0x028230dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX30 */ + {0x028130dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX50 */ + {0x028030dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX75 */ + {0x028140dd, 1495, 1438, INTEL_CYCLONEIV}, /* EP4CGX110 */ + {0x028040dd, 1495, 1438, INTEL_CYCLONEIV}, /* EP4CGX150 */ + + {0x02b150dd, 864, 163, INTEL_CYCLONEV}, /* 5CEBA2F23 5CEBA2F17 5CEFA2M13 5CEFA2F23 5CEBA2U15 5CEFA2U19 5CEBA2U19 */ + {0x02d020dd, 1485, 19, INTEL_CYCLONEV}, /* 5CSXFC6D6F31 5CSTFD6D5F31 5CSEBA6U23 5CSEMA6U23 5CSEBA6U19 5CSEBA6U23 + 5CSEBA6U19 5CSEMA6F31 5CSXFC6C6U23 */ + {0x02b040dd, 1728, -1, INTEL_CYCLONEV}, /* 5CGXFC9EF35 5CGXBC9AU19 5CGXBC9CF23 5CGTFD9CF23 5CGXFC9AU19 5CGXFC9CF23 + 5CGXFC9EF31 5CGXFC9DF27 5CGXBC9DF27 5CGXBC9EF31 5CGTFD9EF31 5CGTFD9EF35 + 5CGTFD9AU19 5CGXBC9EF35 5CGTFD9DF27 */ + {0x02b050dd, 864, 163, INTEL_CYCLONEV}, /* 5CEFA4U19 5CEFA4F23 5CEFA4M13 5CEBA4F17 5CEBA4U15 5CEBA4U19 5CEBA4F23 */ + {0x02b030dd, 1488, 19, INTEL_CYCLONEV}, /* 5CGXBC7CU19 5CGTFD7CU19 5CGTFD7DF27 5CGXFC7BM15 5CGXFC7DF27 5CGXFC7DF31 + 5CGTFD7CF23 5CGXBC7CF23 5CGXBC7DF31 5CGTFD7BM15 5CGXFC7CU19 5CGTFD7DF31 + 5CGXBC7BM15 5CGXFC7CF23 5CGXBC7DF27 */ + {0x02d120dd, 1485, -1, INTEL_CYCLONEV}, /* 5CSEBA5U23 5CSEBA5U23 5CSTFD5D5F31 5CSEBA5U19 5CSXFC5D6F31 5CSEMA5U23 + 5CSEMA5F31 5CSXFC5C6U23 5CSEBA5U19 */ + {0x02b220dd, 1104, 19, INTEL_CYCLONEV}, /* 5CEBA5U19 5CEFA5U19 5CEFA5M13 5CEBA5F23 5CEFA5F23 */ + {0x02b020dd, 1104, 19, INTEL_CYCLONEV}, /* 5CGXBC5CU19 5CGXFC5F6M11 5CGXFC5CM13 5CGTFD5CF23 5CGXBC5CF23 5CGTFD5CF27 + 5CGTFD5F5M11 5CGXFC5CF27 5CGXFC5CU19 5CGTFD5CM13 5CGXFC5CF23 5CGXBC5CF27 + 5CGTFD5CU19 */ + {0x02d010dd, 1197, -1, INTEL_CYCLONEV}, /* 5CSEBA4U23 5CSXFC4C6U23 5CSEMA4U23 5CSEBA4U23 5CSEBA4U19 5CSEBA4U19 + 5CSXFC2C6U23 */ + {0x02b120dd, 1104, 19, INTEL_CYCLONEV}, /* 5CGXFC4CM13 5CGXFC4CU19 5CGXFC4F6M11 5CGXBC4CU19 5CGXFC4CF27 5CGXBC4CF23 + 5CGXBC4CF27 5CGXFC4CF23 */ + {0x02b140dd, 1728, -1, INTEL_CYCLONEV}, /* 5CEFA9F31 5CEBA9F31 5CEFA9F27 5CEBA9U19 5CEBA9F27 5CEFA9U19 5CEBA9F23 + 5CEFA9F23 */ + {0x02b010dd, 720, 19, INTEL_CYCLONEV}, /* 5CGXFC3U15 5CGXBC3U15 5CGXFC3F23 5CGXFC3U19 5CGXBC3U19 5CGXBC3F23 */ + {0x02b130dd, 1488, 19, INTEL_CYCLONEV}, /* 5CEFA7F31 5CEBA7F27 5CEBA7M15 5CEFA7U19 5CEBA7F23 5CEFA7F23 5CEFA7F27 + 5CEFA7M15 5CEBA7U19 5CEBA7F31 */ + {0x02d110dd, 1197, -1, INTEL_CYCLONEV}, /* 5CSEBA2U23 5CSEMA2U23 5CSEBA2U23 5CSEBA2U19 5CSEBA2U19 */ + + {0x020f10dd, 603, 226, INTEL_CYCLONE10}, /* 10CL006E144 10CL006U256 10CL010M164 10CL010U256 10CL010E144 */ + {0x020f20dd, 1080, 409, INTEL_CYCLONE10}, /* 10CL016U256 10CL016E144 10CL016U484 10CL016F484 10CL016M164 */ + {0x020f30dd, 732, 286, INTEL_CYCLONE10}, /* 10CL025U256 10CL025E144 */ + {0x020f40dd, 1632, 604, INTEL_CYCLONE10}, /* 10CL040F484 10CL040U484 */ + {0x020f50dd, 1164, 442, INTEL_CYCLONE10}, /* 10CL055F484 10CL055U484 */ + {0x020f60dd, 1314, 502, INTEL_CYCLONE10}, /* 10CL080F484 10CL080F780 10CL080U484 */ + {0x020f70dd, 1620, 613, INTEL_CYCLONE10}, /* 10CL120F484 10CL120F780 */ + + {0x02e120dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX085U484 10CX085F672 */ + {0x02e320dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX105F780 10CX105U484 10CX105F672 */ + {0x02e720dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX150F672 10CX150F780 10CX150U484 */ + {0x02ef20dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX220F672 10CX220F780 10CX220U484 */ + + {0x025120dd, 1227, 1174, INTEL_ARRIAII}, /* EP2AGX45 */ + {0x025020dd, 1227, -1, INTEL_ARRIAII}, /* EP2AGX65 */ + {0x025130dd, 1467, -1, INTEL_ARRIAII}, /* EP2AGX95 */ + {0x025030dd, 1467, -1, INTEL_ARRIAII}, /* EP2AGX125 */ + {0x025140dd, 1971, -1, INTEL_ARRIAII}, /* EP2AGX190 */ + {0x025040dd, 1971, -1, INTEL_ARRIAII}, /* EP2AGX260 */ + {0x024810dd, 2274, -1, INTEL_ARRIAII}, /* EP2AGZ225 */ + {0x0240a0dd, 2682, -1, INTEL_ARRIAII}, /* EP2AGZ300 */ + {0x024820dd, 2682, -1, INTEL_ARRIAII}, /* EP2AGZ350 */ +}; + +static int intel_fill_device_parameters(struct intel_pld_device *intel_info) +{ + for (size_t i = 0; i < ARRAY_SIZE(intel_device_parameters); ++i) { + if (intel_device_parameters[i].id == intel_info->tap->idcode && + intel_info->family == intel_device_parameters[i].family) { + if (intel_info->boundary_scan_length == 0) + intel_info->boundary_scan_length = intel_device_parameters[i].boundary_scan_length; + + if (intel_info->checkpos == -1) + intel_info->checkpos = intel_device_parameters[i].checkpos; + + return ERROR_OK; + } + } + + return ERROR_FAIL; +} + +static int intel_check_for_unique_id(struct intel_pld_device *intel_info) +{ + int found = 0; + for (size_t i = 0; i < ARRAY_SIZE(intel_device_parameters); ++i) { + if (intel_device_parameters[i].id == intel_info->tap->idcode) { + ++found; + intel_info->family = intel_device_parameters[i].family; + } + } + + return (found == 1) ? ERROR_OK : ERROR_FAIL; +} + +static int intel_check_config(struct intel_pld_device *intel_info) +{ + if (!intel_info->tap->has_idcode) { + LOG_ERROR("no IDCODE"); + return ERROR_FAIL; + } + + if (intel_info->family == INTEL_UNKNOWN) { + if (intel_check_for_unique_id(intel_info) != ERROR_OK) { + LOG_ERROR("id is ambiguous, please specify family"); + return ERROR_FAIL; + } + } + + if (intel_info->boundary_scan_length == 0 || intel_info->checkpos == -1) { + int ret = intel_fill_device_parameters(intel_info); + if (ret != ERROR_OK) + return ret; + } + + if (intel_info->checkpos >= 0 && (unsigned int)intel_info->checkpos >= intel_info->boundary_scan_length) { + LOG_ERROR("checkpos has to be smaller than scan length %d < %u", + intel_info->checkpos, intel_info->boundary_scan_length); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int intel_read_file(struct raw_bit_file *bit_file, const char *filename) +{ + if (!filename || !bit_file) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* check if binary .bin or ascii .bit/.hex */ + const char *file_ending_pos = strrchr(filename, '.'); + if (!file_ending_pos) { + LOG_ERROR("Unable to detect filename suffix"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (strcasecmp(file_ending_pos, ".rbf") == 0) + return cpld_read_raw_bit_file(bit_file, filename); + + LOG_ERROR("Unable to detect filetype"); + return ERROR_PLD_FILE_LOAD_FAILED; +} + +static int intel_set_instr(struct jtag_tap *tap, uint16_t new_instr) +{ + struct scan_field field; + field.num_bits = tap->ir_length; + void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + field.out_value = t; + buf_set_u32(t, 0, field.num_bits, new_instr); + field.in_value = NULL; + jtag_add_ir_scan(tap, &field, TAP_IDLE); + free(t); + return ERROR_OK; +} + + +static int intel_load(struct pld_device *pld_device, const char *filename) +{ + unsigned int speed = adapter_get_speed_khz(); + if (speed < 1) + speed = 1; + + unsigned int cycles = DIV_ROUND_UP(speed, 200); + if (cycles < 1) + cycles = 1; + + if (!pld_device || !pld_device->driver_priv) + return ERROR_FAIL; + + struct intel_pld_device *intel_info = pld_device->driver_priv; + if (!intel_info || !intel_info->tap) + return ERROR_FAIL; + struct jtag_tap *tap = intel_info->tap; + + int retval = intel_check_config(intel_info); + if (retval != ERROR_OK) + return retval; + + struct raw_bit_file bit_file; + retval = intel_read_file(&bit_file, filename); + if (retval != ERROR_OK) + return retval; + + if (retval != ERROR_OK) + return retval; + + retval = intel_set_instr(tap, 0x002); + if (retval != ERROR_OK) { + free(bit_file.data); + return retval; + } + jtag_add_runtest(speed, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + free(bit_file.data); + return retval; + } + + /* shift in the bitstream */ + struct scan_field field; + field.num_bits = bit_file.length * 8; + field.out_value = bit_file.data; + field.in_value = NULL; + + jtag_add_dr_scan(tap, 1, &field, TAP_DRPAUSE); + retval = jtag_execute_queue(); + free(bit_file.data); + if (retval != ERROR_OK) + return retval; + + retval = intel_set_instr(tap, 0x004); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(cycles, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + if (intel_info->boundary_scan_length != 0) { + uint8_t *buf = calloc(DIV_ROUND_UP(intel_info->boundary_scan_length, 8), 1); + if (!buf) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + field.num_bits = intel_info->boundary_scan_length; + field.out_value = buf; + field.in_value = buf; + jtag_add_dr_scan(tap, 1, &field, TAP_DRPAUSE); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + free(buf); + return retval; + } + + if (intel_info->checkpos != -1) + retval = ((buf[intel_info->checkpos / 8] & (1 << (intel_info->checkpos % 8)))) ? + ERROR_OK : ERROR_FAIL; + free(buf); + if (retval != ERROR_OK) { + LOG_ERROR("Check failed"); + return ERROR_FAIL; + } + } + + retval = intel_set_instr(tap, 0x003); + if (retval != ERROR_OK) + return retval; + switch (intel_info->family) { + case INTEL_CYCLONEIII: + case INTEL_CYCLONEIV: + jtag_add_runtest(5 * speed + 512, TAP_IDLE); + break; + case INTEL_CYCLONEV: + jtag_add_runtest(5 * speed + 512, TAP_IDLE); + break; + case INTEL_CYCLONE10: + jtag_add_runtest(DIV_ROUND_UP(512ul * speed, 125ul) + 512, TAP_IDLE); + break; + case INTEL_ARRIAII: + jtag_add_runtest(DIV_ROUND_UP(64ul * speed, 125ul) + 512, TAP_IDLE); + break; + case INTEL_UNKNOWN: + LOG_ERROR("unknown family"); + return ERROR_FAIL; + } + + retval = intel_set_instr(tap, BYPASS); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(speed, TAP_IDLE); + return jtag_execute_queue(); +} + +static int intel_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +{ + if (!pld_device) + return ERROR_FAIL; + + struct intel_pld_device *pld_device_info = pld_device->driver_priv; + + if (!pld_device_info || !pld_device_info->tap) + return ERROR_FAIL; + + hub->tap = pld_device_info->tap; + + if (user_num == 0) { + hub->user_ir_code = USER0; + } else if (user_num == 1) { + hub->user_ir_code = USER1; + } else { + LOG_ERROR("intel devices only have user register 0 & 1"); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int intel_get_jtagspi_userircode(struct pld_device *pld_device, unsigned int *ir) +{ + *ir = USER1; + return ERROR_OK; +} + +COMMAND_HANDLER(intel_set_bscan_command_handler) +{ + unsigned int boundary_scan_length; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct pld_device *pld_device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); + if (!pld_device) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], boundary_scan_length); + + struct intel_pld_device *intel_info = pld_device->driver_priv; + + if (!intel_info) + return ERROR_FAIL; + + intel_info->boundary_scan_length = boundary_scan_length; + + return ERROR_OK; +} + +COMMAND_HANDLER(intel_set_check_pos_command_handler) +{ + int checkpos; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct pld_device *pld_device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); + if (!pld_device) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], checkpos); + + struct intel_pld_device *intel_info = pld_device->driver_priv; + + if (!intel_info) + return ERROR_FAIL; + + intel_info->checkpos = checkpos; + + return ERROR_OK; +} + +PLD_CREATE_COMMAND_HANDLER(intel_pld_create_command) +{ + if (CMD_ARGC != 4 && CMD_ARGC != 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcmp(CMD_ARGV[2], "-chain-position") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); + if (!tap) { + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); + return ERROR_FAIL; + } + + enum intel_family_e family = INTEL_UNKNOWN; + if (CMD_ARGC == 6) { + if (strcmp(CMD_ARGV[4], "-family") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcmp(CMD_ARGV[5], "cycloneiii") == 0) { + family = INTEL_CYCLONEIII; + } else if (strcmp(CMD_ARGV[5], "cycloneiv") == 0) { + family = INTEL_CYCLONEIV; + } else if (strcmp(CMD_ARGV[5], "cyclonev") == 0) { + family = INTEL_CYCLONEV; + } else if (strcmp(CMD_ARGV[5], "cyclone10") == 0) { + family = INTEL_CYCLONE10; + } else if (strcmp(CMD_ARGV[5], "arriaii") == 0) { + family = INTEL_ARRIAII; + } else { + command_print(CMD, "unknown family"); + return ERROR_FAIL; + } + } + + struct intel_pld_device *intel_info = malloc(sizeof(struct intel_pld_device)); + if (!intel_info) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + intel_info->tap = tap; + intel_info->boundary_scan_length = 0; + intel_info->checkpos = -1; + intel_info->family = family; + + pld->driver_priv = intel_info; + + return ERROR_OK; +} + +static const struct command_registration intel_exec_command_handlers[] = { + { + .name = "set_bscan", + .mode = COMMAND_ANY, + .handler = intel_set_bscan_command_handler, + .help = "set boundary scan register length of FPGA", + .usage = "pld_name len", + }, { + .name = "set_check_pos", + .mode = COMMAND_ANY, + .handler = intel_set_check_pos_command_handler, + .help = "set check_pos of FPGA", + .usage = "pld_name pos", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration intel_command_handler[] = { + { + .name = "intel", + .mode = COMMAND_ANY, + .help = "intel specific commands", + .usage = "", + .chain = intel_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct pld_driver intel_pld = { + .name = "intel", + .commands = intel_command_handler, + .pld_create_command = &intel_pld_create_command, + .load = &intel_load, + .get_ipdbg_hub = intel_get_ipdbg_hub, + .get_jtagspi_userircode = intel_get_jtagspi_userircode, +}; diff --git a/src/pld/lattice.c b/src/pld/lattice.c new file mode 100644 index 0000000000..2997cdc39f --- /dev/null +++ b/src/pld/lattice.c @@ -0,0 +1,663 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "lattice.h" +#include <jtag/jtag.h> +#include "pld.h" +#include "lattice_bit.h" +#include "ecp2_3.h" +#include "ecp5.h" +#include "certus.h" + +#define PRELOAD 0x1C +#define USER1 0x32 +#define USER2 0x38 + + +struct lattice_devices_elem { + uint32_t id; + size_t preload_length; + enum lattice_family_e family; +}; + +static const struct lattice_devices_elem lattice_devices[] = { + {0x01270043, 654, LATTICE_ECP2 /* ecp2-6e */}, + {0x01271043, 643, LATTICE_ECP2 /* ecp2-12e */}, + {0x01272043, 827, LATTICE_ECP2 /* ecp2-20e */}, + {0x01274043, 1011, LATTICE_ECP2 /* ecp2-35e */}, + {0x01273043, 1219, LATTICE_ECP2 /* ecp2-50e */}, + {0x01275043, 654, LATTICE_ECP2 /* ecp2-70e */}, + {0x01279043, 680, LATTICE_ECP2 /* ecp2m20e */}, + {0x0127A043, 936, LATTICE_ECP2 /* ecp2m35e */}, + {0x0127B043, 1056, LATTICE_ECP2 /* ecp2m50e */}, + {0x0127C043, 1039, LATTICE_ECP2 /* ecp2m70e */}, + {0x0127D043, 1311, LATTICE_ECP2 /* ecp2m100e */}, + {0x01010043, 467, LATTICE_ECP3 /* ecp3 lae3-17ea & lfe3-17ea*/}, + {0x01012043, 675, LATTICE_ECP3 /* ecp3 lae3-35ea & lfe3-35ea*/}, + {0x01014043, 1077, LATTICE_ECP3 /* ecp3 lfe3-70ea & lfe3-70e & lfe3-95ea && lfe3-95e*/}, + {0x01015043, 1326, LATTICE_ECP3 /* ecp3 lfe3-150e*/}, + {0x21111043, 409, LATTICE_ECP5 /* "LAE5U-12F & LFE5U-12F" */}, + {0x41111043, 409, LATTICE_ECP5 /* "LFE5U-25F" */}, + {0x41112043, 510, LATTICE_ECP5 /* "LFE5U-45F" */}, + {0x41113043, 750, LATTICE_ECP5 /* "LFE5U-85F" */}, + {0x81111043, 409, LATTICE_ECP5 /* "LFE5UM5G-25F" */}, + {0x81112043, 510, LATTICE_ECP5 /* "LFE5UM5G-45F" */}, + {0x81113043, 750, LATTICE_ECP5 /* "LFE5UM5G-85F" */}, + {0x01111043, 409, LATTICE_ECP5 /* "LAE5UM-25F" */}, + {0x01112043, 510, LATTICE_ECP5 /* "LAE5UM-45F" */}, + {0x01113043, 750, LATTICE_ECP5 /* "LAE5UM-85F" */}, + {0x310f0043, 362, LATTICE_CERTUS /* LFD2NX-17 */}, + {0x310f1043, 362, LATTICE_CERTUS /* LFD2NX-40 */}, + {0x010f4043, 362, LATTICE_CERTUS /* LFCPNX-100 */}, +}; + +int lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate) +{ + struct scan_field field; + field.num_bits = tap->ir_length; + void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + field.out_value = t; + buf_set_u32(t, 0, field.num_bits, new_instr); + field.in_value = NULL; + jtag_add_ir_scan(tap, &field, endstate); + free(t); + return ERROR_OK; +} + +static int lattice_check_device_family(struct lattice_pld_device *lattice_device) +{ + if (lattice_device->family != LATTICE_UNKNOWN && lattice_device->preload_length != 0) + return ERROR_OK; + + if (!lattice_device->tap || !lattice_device->tap->has_idcode) + return ERROR_FAIL; + + for (size_t i = 0; i < ARRAY_SIZE(lattice_devices); ++i) { + if (lattice_devices[i].id == lattice_device->tap->idcode) { + if (lattice_device->family == LATTICE_UNKNOWN) + lattice_device->family = lattice_devices[i].family; + if (lattice_device->preload_length == 0) + lattice_device->preload_length = lattice_devices[i].preload_length; + return ERROR_OK; + } + } + LOG_ERROR("Unknown id! Specify family and preload-length manually."); + return ERROR_FAIL; +} + +int lattice_read_u32_register(struct jtag_tap *tap, uint8_t cmd, uint32_t *in_val, + uint32_t out_val, bool do_idle) +{ + struct scan_field field; + uint8_t buffer[4]; + + int retval = lattice_set_instr(tap, cmd, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + if (do_idle) { + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(1000); + } + + h_u32_to_le(buffer, out_val); + field.num_bits = 32; + field.out_value = buffer; + field.in_value = buffer; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval == ERROR_OK) + *in_val = le_to_h_u32(buffer); + + return retval; +} + +int lattice_read_u64_register(struct jtag_tap *tap, uint8_t cmd, uint64_t *in_val, + uint64_t out_val) +{ + struct scan_field field; + uint8_t buffer[8]; + + int retval = lattice_set_instr(tap, cmd, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + h_u64_to_le(buffer, out_val); + field.num_bits = 64; + field.out_value = buffer; + field.in_value = buffer; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval == ERROR_OK) + *in_val = le_to_h_u64(buffer); + + return retval; +} + +int lattice_preload(struct lattice_pld_device *lattice_device) +{ + struct scan_field field; + size_t sz_bytes = DIV_ROUND_UP(lattice_device->preload_length, 8); + + int retval = lattice_set_instr(lattice_device->tap, PRELOAD, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + uint8_t *buffer = malloc(sz_bytes); + if (!buffer) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + memset(buffer, 0xff, sz_bytes); + + field.num_bits = lattice_device->preload_length; + field.out_value = buffer; + field.in_value = NULL; + jtag_add_dr_scan(lattice_device->tap, 1, &field, TAP_IDLE); + retval = jtag_execute_queue(); + free(buffer); + return retval; +} + +static int lattice_read_usercode(struct lattice_pld_device *lattice_device, uint32_t *usercode, uint32_t out) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3) + return lattice_ecp2_3_read_usercode(tap, usercode, out); + else if (lattice_device->family == LATTICE_ECP5) + return lattice_ecp5_read_usercode(tap, usercode, out); + else if (lattice_device->family == LATTICE_CERTUS) + return lattice_certus_read_usercode(tap, usercode, out); + + return ERROR_FAIL; +} + +int lattice_verify_usercode(struct lattice_pld_device *lattice_device, uint32_t out, + uint32_t expected, uint32_t mask) +{ + uint32_t usercode; + + int retval = lattice_read_usercode(lattice_device, &usercode, out); + if (retval != ERROR_OK) + return retval; + + if ((usercode & mask) != expected) { + LOG_ERROR("verifying user code register failed got: 0x%08" PRIx32 " expected: 0x%08" PRIx32, + usercode & mask, expected); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int lattice_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode) +{ + if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3) + return lattice_ecp2_3_write_usercode(lattice_device, usercode); + else if (lattice_device->family == LATTICE_ECP5) + return lattice_ecp5_write_usercode(lattice_device, usercode); + else if (lattice_device->family == LATTICE_CERTUS) + return lattice_certus_write_usercode(lattice_device, usercode); + + return ERROR_FAIL; +} + +static int lattice_read_status_u32(struct lattice_pld_device *lattice_device, uint32_t *status, + uint32_t out, bool do_idle) +{ + if (!lattice_device->tap) + return ERROR_FAIL; + + if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3) + return lattice_ecp2_3_read_status(lattice_device->tap, status, out, do_idle); + else if (lattice_device->family == LATTICE_ECP5) + return lattice_ecp5_read_status(lattice_device->tap, status, out, do_idle); + + return ERROR_FAIL; +} +static int lattice_read_status_u64(struct lattice_pld_device *lattice_device, uint64_t *status, + uint64_t out) +{ + if (!lattice_device->tap) + return ERROR_FAIL; + + if (lattice_device->family == LATTICE_CERTUS) + return lattice_certus_read_status(lattice_device->tap, status, out); + + return ERROR_FAIL; +} + +int lattice_verify_status_register_u32(struct lattice_pld_device *lattice_device, uint32_t out, + uint32_t expected, uint32_t mask, bool do_idle) +{ + uint32_t status; + int retval = lattice_read_status_u32(lattice_device, &status, out, do_idle); + if (retval != ERROR_OK) + return retval; + + if ((status & mask) != expected) { + LOG_ERROR("verifying status register failed got: 0x%08" PRIx32 " expected: 0x%08" PRIx32, + status & mask, expected); + return ERROR_FAIL; + } + return ERROR_OK; +} + +int lattice_verify_status_register_u64(struct lattice_pld_device *lattice_device, uint64_t out, + uint64_t expected, uint64_t mask) +{ + uint64_t status; + int retval = lattice_read_status_u64(lattice_device, &status, out); + if (retval != ERROR_OK) + return retval; + + if ((status & mask) != expected) { + LOG_ERROR("verifying status register failed got: 0x%08" PRIx64 " expected: 0x%08" PRIx64, + status & mask, expected); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int lattice_load_command(struct pld_device *pld_device, const char *filename) +{ + if (!pld_device) + return ERROR_FAIL; + + struct lattice_pld_device *lattice_device = pld_device->driver_priv; + if (!lattice_device || !lattice_device->tap) + return ERROR_FAIL; + struct jtag_tap *tap = lattice_device->tap; + + if (!tap || !tap->has_idcode) + return ERROR_FAIL; + + int retval = lattice_check_device_family(lattice_device); + if (retval != ERROR_OK) + return retval; + + struct lattice_bit_file bit_file; + retval = lattice_read_file(&bit_file, filename, lattice_device->family); + if (retval != ERROR_OK) + return retval; + + uint32_t id = tap->idcode; + retval = ERROR_FAIL; + switch (lattice_device->family) { + case LATTICE_ECP2: + retval = lattice_ecp2_load(lattice_device, &bit_file); + break; + case LATTICE_ECP3: + retval = lattice_ecp3_load(lattice_device, &bit_file); + break; + case LATTICE_ECP5: + case LATTICE_CERTUS: + if (bit_file.has_id && id != bit_file.idcode) + LOG_WARNING("Id on device (0x%8.8" PRIx32 ") and id in bit-stream (0x%8.8" PRIx32 ") don't match.", + id, bit_file.idcode); + if (lattice_device->family == LATTICE_ECP5) + retval = lattice_ecp5_load(lattice_device, &bit_file); + else + retval = lattice_certus_load(lattice_device, &bit_file); + break; + default: + LOG_ERROR("loading unknown device family"); + break; + } + free(bit_file.raw_bit.data); + return retval; +} + +static int lattice_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +{ + if (!pld_device) + return ERROR_FAIL; + + struct lattice_pld_device *pld_device_info = pld_device->driver_priv; + + if (!pld_device_info || !pld_device_info->tap) + return ERROR_FAIL; + + hub->tap = pld_device_info->tap; + + if (user_num == 1) { + hub->user_ir_code = USER1; + } else if (user_num == 2) { + hub->user_ir_code = USER2; + } else { + LOG_ERROR("lattice devices only have user register 1 & 2"); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int lattice_connect_spi_to_jtag(struct pld_device *pld_device) +{ + if (!pld_device) + return ERROR_FAIL; + + struct lattice_pld_device *pld_device_info = pld_device->driver_priv; + + int retval = lattice_check_device_family(pld_device_info); + if (retval != ERROR_OK) + return retval; + + if (pld_device_info->family == LATTICE_ECP2 || pld_device_info->family == LATTICE_ECP3) + return lattice_ecp2_3_connect_spi_to_jtag(pld_device_info); + else if (pld_device_info->family == LATTICE_ECP5) + return lattice_ecp5_connect_spi_to_jtag(pld_device_info); + else if (pld_device_info->family == LATTICE_CERTUS) + return lattice_certus_connect_spi_to_jtag(pld_device_info); + + return ERROR_FAIL; +} + +static int lattice_disconnect_spi_from_jtag(struct pld_device *pld_device) +{ + if (!pld_device) + return ERROR_FAIL; + + struct lattice_pld_device *pld_device_info = pld_device->driver_priv; + + int retval = lattice_check_device_family(pld_device_info); + if (retval != ERROR_OK) + return retval; + + if (pld_device_info->family == LATTICE_ECP2 || pld_device_info->family == LATTICE_ECP3) + return lattice_ecp2_3_disconnect_spi_from_jtag(pld_device_info); + else if (pld_device_info->family == LATTICE_ECP5) + return lattice_ecp5_disconnect_spi_from_jtag(pld_device_info); + else if (pld_device_info->family == LATTICE_CERTUS) + return lattice_certus_disconnect_spi_from_jtag(pld_device_info); + + return ERROR_FAIL; +} + +static int lattice_get_stuff_bits(struct pld_device *pld_device, unsigned int *facing_read_bits, + unsigned int *trailing_write_bits) +{ + if (!pld_device) + return ERROR_FAIL; + + struct lattice_pld_device *pld_device_info = pld_device->driver_priv; + + int retval = lattice_check_device_family(pld_device_info); + if (retval != ERROR_OK) + return retval; + + if (pld_device_info->family == LATTICE_ECP2 || pld_device_info->family == LATTICE_ECP3) + return lattice_ecp2_3_get_facing_read_bits(pld_device_info, facing_read_bits); + else if (pld_device_info->family == LATTICE_ECP5) + return lattice_ecp5_get_facing_read_bits(pld_device_info, facing_read_bits); + else if (pld_device_info->family == LATTICE_CERTUS) + return lattice_certus_get_facing_read_bits(pld_device_info, facing_read_bits); + + return ERROR_FAIL; +} + +static int lattice_has_jtagspi_instruction(struct pld_device *device, bool *has_instruction) +{ + *has_instruction = true; + return ERROR_OK; +} + +PLD_CREATE_COMMAND_HANDLER(lattice_pld_create_command) +{ + if (CMD_ARGC != 4 && CMD_ARGC != 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcmp(CMD_ARGV[2], "-chain-position") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); + if (!tap) { + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); + return ERROR_FAIL; + } + + /* id is not known yet -> postpone lattice_check_device_family() */ + enum lattice_family_e family = LATTICE_UNKNOWN; + if (CMD_ARGC == 6) { + if (strcmp(CMD_ARGV[4], "-family") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcasecmp(CMD_ARGV[5], "ecp2") == 0) { + family = LATTICE_ECP2; + } else if (strcasecmp(CMD_ARGV[5], "ecp3") == 0) { + family = LATTICE_ECP3; + } else if (strcasecmp(CMD_ARGV[5], "ecp5") == 0) { + family = LATTICE_ECP5; + } else if (strcasecmp(CMD_ARGV[5], "certus") == 0) { + family = LATTICE_CERTUS; + } else { + command_print(CMD, "unknown family"); + return ERROR_FAIL; + } + } + + struct lattice_pld_device *lattice_device = malloc(sizeof(struct lattice_pld_device)); + if (!lattice_device) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + lattice_device->tap = tap; + lattice_device->family = family; + lattice_device->preload_length = 0; + + pld->driver_priv = lattice_device; + + return ERROR_OK; +} + +COMMAND_HANDLER(lattice_read_usercode_register_command_handler) +{ + uint32_t usercode; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + struct lattice_pld_device *lattice_device = device->driver_priv; + if (!lattice_device) + return ERROR_FAIL; + + int retval = lattice_check_device_family(lattice_device); + if (retval != ERROR_OK) + return retval; + + retval = lattice_read_usercode(lattice_device, &usercode, 0x0); + if (retval == ERROR_OK) + command_print(CMD, "0x%8.8" PRIx32, usercode); + + return retval; +} + +COMMAND_HANDLER(lattice_set_preload_command_handler) +{ + unsigned int preload_length; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], preload_length); + + struct lattice_pld_device *lattice_device = device->driver_priv; + + if (!lattice_device) + return ERROR_FAIL; + + lattice_device->preload_length = preload_length; + + return ERROR_OK; +} + +COMMAND_HANDLER(lattice_write_usercode_register_command_handler) +{ + uint32_t usercode; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], usercode); + + struct lattice_pld_device *lattice_device = device->driver_priv; + if (!lattice_device) + return ERROR_FAIL; + + int retval = lattice_check_device_family(lattice_device); + if (retval != ERROR_OK) + return retval; + + return lattice_write_usercode(lattice_device, usercode); +} + +COMMAND_HANDLER(lattice_read_status_command_handler) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + struct lattice_pld_device *lattice_device = device->driver_priv; + if (!lattice_device) + return ERROR_FAIL; + + int retval = lattice_check_device_family(lattice_device); + if (retval != ERROR_OK) + return retval; + + if (lattice_device->family == LATTICE_CERTUS) { + uint64_t status; + retval = lattice_read_status_u64(lattice_device, &status, 0x0); + if (retval == ERROR_OK) + command_print(CMD, "0x%016" PRIx64, status); + } else { + uint32_t status; + const bool do_idle = lattice_device->family == LATTICE_ECP5; + retval = lattice_read_status_u32(lattice_device, &status, 0x0, do_idle); + if (retval == ERROR_OK) + command_print(CMD, "0x%8.8" PRIx32, status); + } + + return retval; +} + +COMMAND_HANDLER(lattice_refresh_command_handler) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + struct lattice_pld_device *lattice_device = device->driver_priv; + if (!lattice_device) + return ERROR_FAIL; + + int retval = lattice_check_device_family(lattice_device); + if (retval != ERROR_OK) + return retval; + + if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3) + return lattice_ecp2_3_refresh(lattice_device); + else if (lattice_device->family == LATTICE_ECP5) + return lattice_ecp5_refresh(lattice_device); + else if (lattice_device->family == LATTICE_CERTUS) + return lattice_certus_refresh(lattice_device); + + return ERROR_FAIL; +} + +static const struct command_registration lattice_exec_command_handlers[] = { + { + .name = "read_status", + .mode = COMMAND_EXEC, + .handler = lattice_read_status_command_handler, + .help = "reading status register from FPGA", + .usage = "pld_name", + }, { + .name = "read_user", + .mode = COMMAND_EXEC, + .handler = lattice_read_usercode_register_command_handler, + .help = "reading usercode register from FPGA", + .usage = "pld_name", + }, { + .name = "write_user", + .mode = COMMAND_EXEC, + .handler = lattice_write_usercode_register_command_handler, + .help = "writing usercode register to FPGA", + .usage = "pld_name value", + }, { + .name = "set_preload", + .mode = COMMAND_ANY, + .handler = lattice_set_preload_command_handler, + .help = "set length for preload (device specific)", + .usage = "pld_name value", + }, { + .name = "refresh", + .mode = COMMAND_EXEC, + .handler = lattice_refresh_command_handler, + .help = "refresh from configuration memory", + .usage = "pld_name", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration lattice_command_handler[] = { + { + .name = "lattice", + .mode = COMMAND_ANY, + .help = "lattice specific commands", + .usage = "", + .chain = lattice_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct pld_driver lattice_pld = { + .name = "lattice", + .commands = lattice_command_handler, + .pld_create_command = &lattice_pld_create_command, + .load = &lattice_load_command, + .get_ipdbg_hub = lattice_get_ipdbg_hub, + .has_jtagspi_instruction = lattice_has_jtagspi_instruction, + .connect_spi_to_jtag = lattice_connect_spi_to_jtag, + .disconnect_spi_from_jtag = lattice_disconnect_spi_from_jtag, + .get_stuff_bits = lattice_get_stuff_bits, +}; diff --git a/src/pld/lattice.h b/src/pld/lattice.h new file mode 100644 index 0000000000..9a76a4ec37 --- /dev/null +++ b/src/pld/lattice.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifndef OPENOCD_PLD_LATTICE_H +#define OPENOCD_PLD_LATTICE_H + +#include <jtag/jtag.h> +#include "pld.h" +#include "lattice_bit.h" + +#define BYPASS 0xFF + +struct lattice_pld_device { + struct jtag_tap *tap; + size_t preload_length; + enum lattice_family_e family; +}; + +int lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate); +int lattice_read_u32_register(struct jtag_tap *tap, uint8_t cmd, uint32_t *in_val, + uint32_t out_val, bool do_idle); +int lattice_read_u64_register(struct jtag_tap *tap, uint8_t cmd, uint64_t *in_val, + uint64_t out_val); +int lattice_verify_usercode(struct lattice_pld_device *lattice_device, uint32_t out, + uint32_t expected, uint32_t mask); +int lattice_verify_status_register_u32(struct lattice_pld_device *lattice_device, uint32_t out, + uint32_t expected, uint32_t mask, bool do_idle); +int lattice_verify_status_register_u64(struct lattice_pld_device *lattice_device, uint64_t out, + uint64_t expected, uint64_t mask); +int lattice_preload(struct lattice_pld_device *lattice_device); + +#endif /* OPENOCD_PLD_LATTICE_H */ diff --git a/src/pld/lattice_bit.c b/src/pld/lattice_bit.c new file mode 100644 index 0000000000..796adce975 --- /dev/null +++ b/src/pld/lattice_bit.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "lattice_bit.h" +#include "raw_bit.h" +#include "pld.h" +#include <helper/system.h> +#include <helper/log.h> +#include <helper/binarybuffer.h> + +enum read_bit_state { + SEEK_HEADER_START, + SEEK_HEADER_END, + SEEK_PREAMBLE, + SEEK_ID, + DONE, +}; + +static int lattice_read_bit_file(struct lattice_bit_file *bit_file, const char *filename, enum lattice_family_e family) +{ + int retval = cpld_read_raw_bit_file(&bit_file->raw_bit, filename); + if (retval != ERROR_OK) + return retval; + + bit_file->part = NULL; + bit_file->has_id = false; + enum read_bit_state state = SEEK_HEADER_START; + for (size_t pos = 1; pos < bit_file->raw_bit.length && state != DONE; ++pos) { + switch (state) { + case SEEK_HEADER_START: + if (bit_file->raw_bit.data[pos] == 0 && bit_file->raw_bit.data[pos - 1] == 0xff) + state = SEEK_HEADER_END; + break; + case SEEK_HEADER_END: + if (pos + 6 < bit_file->raw_bit.length && + strncmp((const char *)(bit_file->raw_bit.data + pos), "Part: ", 6) == 0) { + bit_file->part = (const char *)bit_file->raw_bit.data + pos + 6; + LOG_INFO("part found: %s\n", bit_file->part); + } else if (bit_file->raw_bit.data[pos] == 0xff && bit_file->raw_bit.data[pos - 1] == 0) { + bit_file->offset = pos; + state = (family != LATTICE_ECP2 && family != LATTICE_ECP3) ? SEEK_PREAMBLE : DONE; + } + break; + case SEEK_PREAMBLE: + if (pos >= 4) { + uint32_t preamble = be_to_h_u32(bit_file->raw_bit.data + pos - 3); + switch (preamble) { + case 0xffffbdb3: + state = SEEK_ID; + break; + case 0xffffbfb3: + case 0xffffbeb3: + state = DONE; + break; + } + } + break; + case SEEK_ID: + if (pos + 7 < bit_file->raw_bit.length && bit_file->raw_bit.data[pos] == 0xe2) { + bit_file->idcode = be_to_h_u32(&bit_file->raw_bit.data[pos + 4]); + bit_file->has_id = true; + state = DONE; + } + break; + default: + break; + } + } + + if (state != DONE) { + LOG_ERROR("parsing bitstream failed"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + for (size_t i = bit_file->offset; i < bit_file->raw_bit.length; i++) + bit_file->raw_bit.data[i] = flip_u32(bit_file->raw_bit.data[i], 8); + + return ERROR_OK; +} + +int lattice_read_file(struct lattice_bit_file *bit_file, const char *filename, enum lattice_family_e family) +{ + if (!filename || !bit_file) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* check if binary .bin or ascii .bit/.hex */ + const char *file_suffix_pos = strrchr(filename, '.'); + if (!file_suffix_pos) { + LOG_ERROR("Unable to detect filename suffix"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (strcasecmp(file_suffix_pos, ".bit") == 0) + return lattice_read_bit_file(bit_file, filename, family); + + LOG_ERROR("Filetype not supported"); + return ERROR_PLD_FILE_LOAD_FAILED; +} diff --git a/src/pld/lattice_bit.h b/src/pld/lattice_bit.h new file mode 100644 index 0000000000..33f1b347f1 --- /dev/null +++ b/src/pld/lattice_bit.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifndef OPENOCD_PLD_LATTICE_BIT_H +#define OPENOCD_PLD_LATTICE_BIT_H + +#include "helper/types.h" +#include "raw_bit.h" + + +struct lattice_bit_file { + struct raw_bit_file raw_bit; + size_t offset; + uint32_t idcode; + const char *part; /* reuses memory in raw_bit_file */ + bool has_id; +}; + +enum lattice_family_e { + LATTICE_ECP2, + LATTICE_ECP3, + LATTICE_ECP5, + LATTICE_CERTUS, + LATTICE_UNKNOWN, +}; + +int lattice_read_file(struct lattice_bit_file *bit_file, const char *filename, enum lattice_family_e family); + +#endif /* OPENOCD_PLD_LATTICE_BIT_H */ diff --git a/src/pld/lattice_cmd.h b/src/pld/lattice_cmd.h new file mode 100644 index 0000000000..0c10625832 --- /dev/null +++ b/src/pld/lattice_cmd.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifndef OPENOCD_PLD_LATTICE_CMD_H +#define OPENOCD_PLD_LATTICE_CMD_H + +#define ISC_ERASE 0x0E +#define ISC_DISABLE 0x26 +#define PROGRAM_SPI 0x3A +#define LSC_READ_STATUS 0x3C +#define LSC_INIT_ADDRESS 0x46 +#define LSC_REFRESH 0x79 +#define LSC_BITSTREAM_BURST 0x7A +#define READ_USERCODE 0xC0 +#define ISC_ENABLE 0xC6 + +#endif /* OPENOCD_PLD_LATTICE_CMD_H */ diff --git a/src/pld/pld.c b/src/pld/pld.c index fe21f6c85b..81fb0c4632 100644 --- a/src/pld/pld.c +++ b/src/pld/pld.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -21,16 +10,18 @@ #endif #include "pld.h" +#include <sys/stat.h> #include <helper/log.h> #include <helper/replacements.h> #include <helper/time_support.h> -/* pld drivers - */ -extern struct pld_driver virtex2_pld; - static struct pld_driver *pld_drivers[] = { + &efinix_pld, + &gatemate_pld, + &gowin_pld, + &intel_pld, + &lattice_pld, &virtex2_pld, NULL, }; @@ -43,68 +34,197 @@ struct pld_device *get_pld_device_by_num(int num) int i = 0; for (p = pld_devices; p; p = p->next) { - if (i++ == num) + if (i++ == num) { + LOG_WARNING("DEPRECATED: use pld name \"%s\" instead of number %d", p->name, num); + return p; + } + } + + return NULL; +} + +struct pld_device *get_pld_device_by_name(const char *name) +{ + for (struct pld_device *p = pld_devices; p; p = p->next) { + if (strcmp(p->name, name) == 0) return p; } return NULL; } -/* pld device <driver> [driver_options ...] - */ -COMMAND_HANDLER(handle_pld_device_command) +struct pld_device *get_pld_device_by_name_or_numstr(const char *str) +{ + struct pld_device *dev = get_pld_device_by_name(str); + if (dev) + return dev; + + char *end; + unsigned long dev_num = strtoul(str, &end, 0); + if (*end || dev_num > INT_MAX) { + LOG_ERROR("Invalid argument"); + return NULL; + } + + return get_pld_device_by_num(dev_num); +} + + +int pld_has_jtagspi_instruction(struct pld_device *pld_device, bool *has_instruction) +{ + *has_instruction = false; /* default is using a proxy bitstream */ + + if (!pld_device) + return ERROR_FAIL; + + struct pld_driver *pld_driver = pld_device->driver; + if (!pld_driver) { + LOG_ERROR("pld device has no associated driver"); + return ERROR_FAIL; + } + + if (pld_driver->has_jtagspi_instruction) + return pld_driver->has_jtagspi_instruction(pld_device, has_instruction); + /* else, take the default (proxy bitstream) */ + return ERROR_OK; +} + +int pld_get_jtagspi_userircode(struct pld_device *pld_device, unsigned int *ir) +{ + if (!pld_device) + return ERROR_FAIL; + + struct pld_driver *pld_driver = pld_device->driver; + if (!pld_driver) { + LOG_ERROR("pld device has no associated driver"); + return ERROR_FAIL; + } + + if (pld_driver->get_jtagspi_userircode) + return pld_driver->get_jtagspi_userircode(pld_device, ir); + + return ERROR_FAIL; +} + +int pld_get_jtagspi_stuff_bits(struct pld_device *pld_device, unsigned int *facing_read_bits, + unsigned int *trailing_write_bits) +{ + if (!pld_device) + return ERROR_FAIL; + + struct pld_driver *pld_driver = pld_device->driver; + if (!pld_driver) { + LOG_ERROR("pld device has no associated driver"); + return ERROR_FAIL; + } + + if (pld_driver->get_stuff_bits) + return pld_driver->get_stuff_bits(pld_device, facing_read_bits, trailing_write_bits); + + return ERROR_OK; +} + +int pld_connect_spi_to_jtag(struct pld_device *pld_device) { - int i; - int found = 0; + if (!pld_device) + return ERROR_FAIL; - if (CMD_ARGC < 1) + struct pld_driver *pld_driver = pld_device->driver; + if (!pld_driver) { + LOG_ERROR("pld device has no associated driver"); + return ERROR_FAIL; + } + + if (pld_driver->connect_spi_to_jtag) + return pld_driver->connect_spi_to_jtag(pld_device); + + return ERROR_FAIL; +} + +int pld_disconnect_spi_from_jtag(struct pld_device *pld_device) +{ + if (!pld_device) + return ERROR_FAIL; + + struct pld_driver *pld_driver = pld_device->driver; + if (!pld_driver) { + LOG_ERROR("pld device has no associated driver"); + return ERROR_FAIL; + } + + if (pld_driver->disconnect_spi_from_jtag) + return pld_driver->disconnect_spi_from_jtag(pld_device); + + return ERROR_FAIL; +} + +COMMAND_HANDLER(handle_pld_create_command) +{ + if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; - for (i = 0; pld_drivers[i]; i++) { - if (strcmp(CMD_ARGV[0], pld_drivers[i]->name) == 0) { - struct pld_device *p, *c; - - /* register pld specific commands */ - int retval; - if (pld_drivers[i]->commands) { - retval = register_commands(CMD_CTX, NULL, pld_drivers[i]->commands); - if (retval != ERROR_OK) { - LOG_ERROR("couldn't register '%s' commands", CMD_ARGV[0]); - return ERROR_FAIL; - } - } - - c = malloc(sizeof(struct pld_device)); - c->driver = pld_drivers[i]; - c->next = NULL; - - retval = CALL_COMMAND_HANDLER( - pld_drivers[i]->pld_device_command, c); - if (retval != ERROR_OK) { - LOG_ERROR("'%s' driver rejected pld device", - CMD_ARGV[0]); - free(c); - return ERROR_OK; - } - - /* put pld device in linked list */ - if (pld_devices) { - /* find last pld device */ - for (p = pld_devices; p && p->next; p = p->next) - ; - if (p) - p->next = c; - } else - pld_devices = c; - - found = 1; + struct pld_driver *pld_driver = NULL; + + for (int i = 0; pld_drivers[i]; i++) { + if (strcmp(CMD_ARGV[1], pld_drivers[i]->name) == 0) { + pld_driver = pld_drivers[i]; + break; + } + } + + if (!pld_driver) { + LOG_ERROR("pld driver '%s' not found", CMD_ARGV[1]); + return ERROR_FAIL; /* exit(-1); */ + } + + if (get_pld_device_by_name(CMD_ARGV[0])) { + LOG_ERROR("pld device with name '%s' already exists", CMD_ARGV[0]); + return ERROR_FAIL; + } + + struct pld_device *pld_device = malloc(sizeof(struct pld_device)); + if (!pld_device) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + pld_device->driver = pld_driver; + pld_device->next = NULL; + + int retval = CALL_COMMAND_HANDLER(pld_driver->pld_create_command, pld_device); + if (retval != ERROR_OK) { + LOG_ERROR("'%s' driver rejected pld device", + CMD_ARGV[1]); + free(pld_device); + return ERROR_OK; + } + pld_device->name = strdup(CMD_ARGV[0]); + if (!pld_device->name) { + LOG_ERROR("Out of memory"); + free(pld_device); + return ERROR_FAIL; + } + + /* register pld specific commands */ + if (pld_driver->commands) { + retval = register_commands(CMD_CTX, NULL, pld_driver->commands); + if (retval != ERROR_OK) { + LOG_ERROR("couldn't register '%s' commands", CMD_ARGV[1]); + free(pld_device->name); + free(pld_device); + return ERROR_FAIL; } } - /* no matching pld driver found */ - if (!found) { - LOG_ERROR("pld driver '%s' not found", CMD_ARGV[0]); - exit(-1); + if (pld_devices) { + /* find last pld device */ + struct pld_device *p = pld_devices; + for (; p && p->next; p = p->next) + ; + if (p) + p->next = pld_device; + } else { + pld_devices = pld_device; } return ERROR_OK; @@ -121,7 +241,7 @@ COMMAND_HANDLER(handle_pld_devices_command) } for (p = pld_devices; p; p = p->next) - command_print(CMD, "#%i: %s", i++, p->driver->name); + command_print(CMD, "#%i: %s (driver: %s)", i++, p->name, p->driver->name); return ERROR_OK; } @@ -137,27 +257,39 @@ COMMAND_HANDLER(handle_pld_load_command) if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; - unsigned dev_id; - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], dev_id); - p = get_pld_device_by_num(dev_id); + p = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!p) { - command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); return ERROR_OK; } + struct stat input_stat; + if (stat(CMD_ARGV[1], &input_stat) == -1) { + LOG_ERROR("couldn't stat() %s: %s", CMD_ARGV[1], strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (S_ISDIR(input_stat.st_mode)) { + LOG_ERROR("%s is a directory", CMD_ARGV[1]); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (input_stat.st_size == 0) { + LOG_ERROR("Empty file %s", CMD_ARGV[1]); + return ERROR_PLD_FILE_LOAD_FAILED; + } + retval = p->driver->load(p, CMD_ARGV[1]); if (retval != ERROR_OK) { - command_print(CMD, "failed loading file %s to pld device %u", - CMD_ARGV[1], dev_id); - switch (retval) { - } + command_print(CMD, "failed loading file %s to pld device %s", + CMD_ARGV[1], CMD_ARGV[0]); return retval; } else { gettimeofday(&end, NULL); timeval_subtract(&duration, &end, &start); - command_print(CMD, "loaded file %s to pld device %u in %jis %jius", - CMD_ARGV[1], dev_id, + command_print(CMD, "loaded file %s to pld device %s in %jis %jius", + CMD_ARGV[1], CMD_ARGV[0], (intmax_t)duration.tv_sec, (intmax_t)duration.tv_usec); } @@ -177,7 +309,7 @@ static const struct command_registration pld_exec_command_handlers[] = { .handler = handle_pld_load_command, .mode = COMMAND_EXEC, .help = "load configuration file into PLD", - .usage = "pld_num filename", + .usage = "pld_name filename", }, COMMAND_REGISTRATION_DONE }; @@ -208,11 +340,11 @@ COMMAND_HANDLER(handle_pld_init_command) static const struct command_registration pld_config_command_handlers[] = { { - .name = "device", + .name = "create", .mode = COMMAND_CONFIG, - .handler = handle_pld_device_command, - .help = "configure a PLD device", - .usage = "driver_name [driver_args ... ]", + .handler = handle_pld_create_command, + .help = "create a PLD device", + .usage = "name.pld driver_name [driver_args ... ]", }, { .name = "init", diff --git a/src/pld/pld.h b/src/pld/pld.h index 3178fd4597..5e2fcd20cc 100644 --- a/src/pld/pld.h +++ b/src/pld/pld.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_PLD_PLD_H @@ -23,30 +12,60 @@ struct pld_device; -#define __PLD_DEVICE_COMMAND(name) \ +#define __PLD_CREATE_COMMAND(name) \ COMMAND_HELPER(name, struct pld_device *pld) +struct pld_ipdbg_hub { + struct jtag_tap *tap; + unsigned int user_ir_code; +}; + +int pld_has_jtagspi_instruction(struct pld_device *device, bool *has_instruction); +int pld_get_jtagspi_userircode(struct pld_device *pld_device, unsigned int *ir); + +int pld_get_jtagspi_stuff_bits(struct pld_device *pld_device, unsigned int *facing_read_bits, + unsigned int *trailing_write_bits); +int pld_connect_spi_to_jtag(struct pld_device *pld_device); +int pld_disconnect_spi_from_jtag(struct pld_device *pld_device); + struct pld_driver { const char *name; - __PLD_DEVICE_COMMAND((*pld_device_command)); + __PLD_CREATE_COMMAND((*pld_create_command)); const struct command_registration *commands; int (*load)(struct pld_device *pld_device, const char *filename); + int (*get_ipdbg_hub)(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub); + int (*has_jtagspi_instruction)(struct pld_device *device, bool *has_instruction); + int (*get_jtagspi_userircode)(struct pld_device *pld_device, unsigned int *ir); + int (*connect_spi_to_jtag)(struct pld_device *pld_device); + int (*disconnect_spi_from_jtag)(struct pld_device *pld_device); + int (*get_stuff_bits)(struct pld_device *pld_device, unsigned int *facing_read_bits, + unsigned int *trailing_write_bits); }; -#define PLD_DEVICE_COMMAND_HANDLER(name) \ - static __PLD_DEVICE_COMMAND(name) +#define PLD_CREATE_COMMAND_HANDLER(name) \ + static __PLD_CREATE_COMMAND(name) struct pld_device { struct pld_driver *driver; void *driver_priv; struct pld_device *next; + char *name; }; int pld_register_commands(struct command_context *cmd_ctx); struct pld_device *get_pld_device_by_num(int num); +struct pld_device *get_pld_device_by_name(const char *name); +struct pld_device *get_pld_device_by_name_or_numstr(const char *str); #define ERROR_PLD_DEVICE_INVALID (-1000) #define ERROR_PLD_FILE_LOAD_FAILED (-1001) +extern struct pld_driver efinix_pld; +extern struct pld_driver gatemate_pld; +extern struct pld_driver gowin_pld; +extern struct pld_driver intel_pld; +extern struct pld_driver lattice_pld; +extern struct pld_driver virtex2_pld; + #endif /* OPENOCD_PLD_PLD_H */ diff --git a/src/pld/raw_bit.c b/src/pld/raw_bit.c new file mode 100644 index 0000000000..0c3b92e7e9 --- /dev/null +++ b/src/pld/raw_bit.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "raw_bit.h" +#include "pld.h" + +#include <helper/system.h> +#include <helper/log.h> + + +int cpld_read_raw_bit_file(struct raw_bit_file *bit_file, const char *filename) +{ + FILE *input_file = fopen(filename, "rb"); + + if (!input_file) { + LOG_ERROR("Couldn't open %s: %s", filename, strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + fseek(input_file, 0, SEEK_END); + long length = ftell(input_file); + fseek(input_file, 0, SEEK_SET); + + if (length < 0) { + fclose(input_file); + LOG_ERROR("Failed to get length of file %s: %s", filename, strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + bit_file->length = (size_t)length; + + bit_file->data = malloc(bit_file->length); + if (!bit_file->data) { + fclose(input_file); + LOG_ERROR("Out of memory"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + size_t read_count = fread(bit_file->data, sizeof(char), bit_file->length, input_file); + fclose(input_file); + if (read_count != bit_file->length) { + free(bit_file->data); + bit_file->data = NULL; + return ERROR_PLD_FILE_LOAD_FAILED; + } + + return ERROR_OK; +} diff --git a/src/pld/raw_bit.h b/src/pld/raw_bit.h new file mode 100644 index 0000000000..583ff76e99 --- /dev/null +++ b/src/pld/raw_bit.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifndef OPENOCD_PLD_RAW_BIN_H +#define OPENOCD_PLD_RAW_BIN_H + +#include <stddef.h> +#include <stdint.h> + +struct raw_bit_file { + size_t length; + uint8_t *data; +}; + +int cpld_read_raw_bit_file(struct raw_bit_file *bit_file, const char *filename); + +#endif /* OPENOCD_PLD_RAW_BIN_H */ diff --git a/src/pld/virtex2.c b/src/pld/virtex2.c index a2de8ccf55..3dff90621a 100644 --- a/src/pld/virtex2.c +++ b/src/pld/virtex2.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -24,18 +13,33 @@ #include "xilinx_bit.h" #include "pld.h" -static int virtex2_set_instr(struct jtag_tap *tap, uint32_t new_instr) +static const struct virtex2_command_set virtex2_default_commands = { + .cfg_out = 0x04, + .cfg_in = 0x05, + .jprog_b = 0x0b, + .jstart = 0x0c, + .jshutdown = 0x0d, + .bypass = 0x3f, + .user = {0x02, 0x03}, + .num_user = 2, /* virtex II has only 2 user instructions */ +}; + +static int virtex2_set_instr(struct jtag_tap *tap, uint64_t new_instr) { if (!tap) return ERROR_FAIL; - if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { + if (buf_get_u64(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; field.num_bits = tap->ir_length; void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } field.out_value = t; - buf_set_u32(t, 0, field.num_bits, new_instr); + buf_set_u64(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); @@ -55,6 +59,10 @@ static int virtex2_send_32(struct pld_device *pld_device, int i; values = malloc(num_words * 4); + if (!values) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } scan_field.num_bits = num_words * 32; scan_field.out_value = values; @@ -63,7 +71,11 @@ static int virtex2_send_32(struct pld_device *pld_device, for (i = 0; i < num_words; i++) buf_set_u32(values + 4 * i, 0, 32, flip_u32(*words++, 32)); - virtex2_set_instr(virtex2_info->tap, 0x5); /* CFG_IN */ + int retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.cfg_in); + if (retval != ERROR_OK) { + free(values); + return retval; + } jtag_add_dr_scan(virtex2_info->tap, 1, &scan_field, TAP_DRPAUSE); @@ -88,7 +100,9 @@ static int virtex2_receive_32(struct pld_device *pld_device, scan_field.out_value = NULL; scan_field.in_value = NULL; - virtex2_set_instr(virtex2_info->tap, 0x4); /* CFG_OUT */ + int retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.cfg_out); + if (retval != ERROR_OK) + return retval; while (num_words--) { scan_field.in_value = (uint8_t *)words; @@ -114,15 +128,101 @@ static int virtex2_read_stat(struct pld_device *pld_device, uint32_t *status) data[2] = 0x20000000; /* NOOP (Type 1, read, address 0, 0 words */ data[3] = 0x20000000; /* NOOP */ data[4] = 0x20000000; /* NOOP */ - virtex2_send_32(pld_device, 5, data); + int retval = virtex2_send_32(pld_device, 5, data); + if (retval != ERROR_OK) + return retval; - virtex2_receive_32(pld_device, 1, status); + retval = virtex2_receive_32(pld_device, 1, status); + if (retval != ERROR_OK) + return retval; - jtag_execute_queue(); + retval = jtag_execute_queue(); + if (retval == ERROR_OK) + LOG_DEBUG("status: 0x%8.8" PRIx32, *status); - LOG_DEBUG("status: 0x%8.8" PRIx32 "", *status); + return retval; +} - return ERROR_OK; +static int virtex2_program(struct pld_device *pld_device) +{ + struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; + if (!virtex2_info) + return ERROR_FAIL; + + int retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jshutdown); + if (retval != ERROR_OK) + return retval; + + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jprog_b); + if (retval != ERROR_OK) + return retval; + + jtag_add_runtest(62000, TAP_IDLE); + if (!(virtex2_info->no_jstart)) { + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jstart); + if (retval != ERROR_OK) + return retval; + } + + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.bypass); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2000, TAP_IDLE); + + return jtag_execute_queue(); +} + +static int virtex2_load_prepare(struct pld_device *pld_device) +{ + struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; + int retval; + + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jprog_b); + if (retval != ERROR_OK) + return retval; + + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + jtag_add_sleep(1000); + + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.cfg_in); + if (retval != ERROR_OK) + return retval; + + return jtag_execute_queue(); +} + +static int virtex2_load_cleanup(struct pld_device *pld_device) +{ + struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; + int retval; + + jtag_add_tlr(); + + if (!(virtex2_info->no_jstart)) { + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jstart); + if (retval != ERROR_OK) + return retval; + } + jtag_add_runtest(13, TAP_IDLE); + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.bypass); + if (retval != ERROR_OK) + return retval; + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.bypass); + if (retval != ERROR_OK) + return retval; + if (!(virtex2_info->no_jstart)) { + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.jstart); + if (retval != ERROR_OK) + return retval; + } + jtag_add_runtest(13, TAP_IDLE); + retval = virtex2_set_instr(virtex2_info->tap, virtex2_info->command_set.bypass); + if (retval != ERROR_OK) + return retval; + + return jtag_execute_queue(); } static int virtex2_load(struct pld_device *pld_device, const char *filename) @@ -139,12 +239,11 @@ static int virtex2_load(struct pld_device *pld_device, const char *filename) if (retval != ERROR_OK) return retval; - virtex2_set_instr(virtex2_info->tap, 0xb); /* JPROG_B */ - jtag_execute_queue(); - jtag_add_sleep(1000); - - virtex2_set_instr(virtex2_info->tap, 0x5); /* CFG_IN */ - jtag_execute_queue(); + retval = virtex2_load_prepare(pld_device); + if (retval != ERROR_OK) { + xilinx_free_bit_file(&bit_file); + return retval; + } for (i = 0; i < bit_file.length; i++) bit_file.data[i] = flip_u32(bit_file.data[i], 8); @@ -153,22 +252,33 @@ static int virtex2_load(struct pld_device *pld_device, const char *filename) field.out_value = bit_file.data; jtag_add_dr_scan(virtex2_info->tap, 1, &field, TAP_DRPAUSE); - jtag_execute_queue(); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + xilinx_free_bit_file(&bit_file); + return retval; + } - jtag_add_tlr(); + retval = virtex2_load_cleanup(pld_device); - if (!(virtex2_info->no_jstart)) - virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */ - jtag_add_runtest(13, TAP_IDLE); - virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ - virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ - if (!(virtex2_info->no_jstart)) - virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */ - jtag_add_runtest(13, TAP_IDLE); - virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ - jtag_execute_queue(); + xilinx_free_bit_file(&bit_file); - return ERROR_OK; + return retval; +} + +COMMAND_HANDLER(virtex2_handle_refresh_command) +{ + struct pld_device *device; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + return virtex2_program(device); } COMMAND_HANDLER(virtex2_handle_read_stat_command) @@ -179,42 +289,139 @@ COMMAND_HANDLER(virtex2_handle_read_stat_command) if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; - unsigned dev_id; - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], dev_id); - device = get_pld_device_by_num(dev_id); + device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]); if (!device) { - command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); - return ERROR_OK; + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + int retval = virtex2_read_stat(device, &status); + if (retval != ERROR_OK) { + command_print(CMD, "cannot read virtex2 status register"); + return retval; } - virtex2_read_stat(device, &status); + command_print(CMD, "virtex2 status register: 0x%8.8" PRIx32, status); - command_print(CMD, "virtex2 status register: 0x%8.8" PRIx32 "", status); + return ERROR_OK; +} + +static int xilinx_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub) +{ + if (!pld_device) + return ERROR_FAIL; + + struct virtex2_pld_device *pld_device_info = pld_device->driver_priv; + + if (!pld_device_info || !pld_device_info->tap) + return ERROR_FAIL; + + hub->tap = pld_device_info->tap; + if (user_num < 1 || (unsigned int)user_num > pld_device_info->command_set.num_user) { + LOG_ERROR("device has only user register 1 to %d", pld_device_info->command_set.num_user); + return ERROR_FAIL; + } + hub->user_ir_code = pld_device_info->command_set.user[user_num - 1]; return ERROR_OK; } -PLD_DEVICE_COMMAND_HANDLER(virtex2_pld_device_command) +static int xilinx_get_jtagspi_userircode(struct pld_device *pld_device, unsigned int *ir) { - struct jtag_tap *tap; + if (!pld_device || !pld_device->driver_priv) + return ERROR_FAIL; + struct virtex2_pld_device *pld_device_info = pld_device->driver_priv; - struct virtex2_pld_device *virtex2_info; + if (pld_device_info->command_set.num_user < 1) { + LOG_ERROR("code for command 'select user1' is unknown"); + return ERROR_FAIL; + } - if (CMD_ARGC < 2) + *ir = pld_device_info->command_set.user[0]; + return ERROR_OK; +} + +COMMAND_HANDLER(virtex2_handle_set_instuction_codes_command) +{ + if (CMD_ARGC < 6 || CMD_ARGC > (6 + VIRTEX2_MAX_USER_INSTRUCTIONS)) return ERROR_COMMAND_SYNTAX_ERROR; - tap = jtag_tap_by_string(CMD_ARGV[1]); + struct pld_device *device = get_pld_device_by_name(CMD_ARGV[0]); + if (!device) { + command_print(CMD, "pld device '#%s' is unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + struct virtex2_pld_device *virtex2_info = device->driver_priv; + if (!virtex2_info) + return ERROR_FAIL; + + struct virtex2_command_set instr_codes; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], instr_codes.cfg_out); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[2], instr_codes.cfg_in); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[3], instr_codes.jprog_b); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[4], instr_codes.jstart); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[5], instr_codes.jshutdown); + instr_codes.bypass = 0xffffffffffffffffULL; + + unsigned int num_user = CMD_ARGC - 6; + for (unsigned int i = 0; i < num_user; ++i) + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[6 + i], instr_codes.user[i]); + instr_codes.num_user = num_user; + + virtex2_info->command_set = instr_codes; + return ERROR_OK; +} + +COMMAND_HANDLER(virtex2_handle_set_user_codes_command) +{ + if (CMD_ARGC < 2 || CMD_ARGC > (1 + VIRTEX2_MAX_USER_INSTRUCTIONS)) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct pld_device *device = get_pld_device_by_name(CMD_ARGV[0]); + if (!device) { + command_print(CMD, "pld device '#%s' is unknown", CMD_ARGV[0]); + return ERROR_FAIL; + } + + struct virtex2_pld_device *virtex2_info = device->driver_priv; + if (!virtex2_info) + return ERROR_FAIL; + + uint64_t user[VIRTEX2_MAX_USER_INSTRUCTIONS]; + unsigned int num_user = CMD_ARGC - 1; + for (unsigned int i = 0; i < num_user; ++i) + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1 + i], user[i]); + virtex2_info->command_set.num_user = num_user; + memcpy(virtex2_info->command_set.user, user, num_user * sizeof(uint64_t)); + return ERROR_OK; +} + +PLD_CREATE_COMMAND_HANDLER(virtex2_pld_create_command) +{ + if (CMD_ARGC < 4) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcmp(CMD_ARGV[2], "-chain-position") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]); if (!tap) { - command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]); - return ERROR_OK; + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]); + return ERROR_FAIL; } - virtex2_info = malloc(sizeof(struct virtex2_pld_device)); + struct virtex2_pld_device *virtex2_info = malloc(sizeof(struct virtex2_pld_device)); + if (!virtex2_info) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } virtex2_info->tap = tap; + virtex2_info->command_set = virtex2_default_commands; virtex2_info->no_jstart = 0; - if (CMD_ARGC >= 3) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], virtex2_info->no_jstart); + if (CMD_ARGC >= 5 && strcmp(CMD_ARGV[4], "-no_jstart") == 0) + virtex2_info->no_jstart = 1; pld->driver_priv = virtex2_info; @@ -227,10 +434,30 @@ static const struct command_registration virtex2_exec_command_handlers[] = { .mode = COMMAND_EXEC, .handler = virtex2_handle_read_stat_command, .help = "read status register", - .usage = "pld_num", + .usage = "pld_name", + }, { + .name = "set_instr_codes", + .mode = COMMAND_ANY, + .handler = virtex2_handle_set_instuction_codes_command, + .help = "set instructions codes used for loading the bitstream/refreshing/jtag-hub", + .usage = "pld_name cfg_out cfg_in jprogb jstart jshutdown" + " [user1 [user2 [user3 [user4]]]]", + }, { + .name = "set_user_codes", + .mode = COMMAND_ANY, + .handler = virtex2_handle_set_user_codes_command, + .help = "set instructions codes used for jtag-hub", + .usage = "pld_name user1 [user2 [user3 [user4]]]", + }, { + .name = "refresh", + .mode = COMMAND_EXEC, + .handler = virtex2_handle_refresh_command, + .help = "start loading of configuration (program)", + .usage = "pld_name", }, COMMAND_REGISTRATION_DONE }; + static const struct command_registration virtex2_command_handler[] = { { .name = "virtex2", @@ -245,6 +472,8 @@ static const struct command_registration virtex2_command_handler[] = { struct pld_driver virtex2_pld = { .name = "virtex2", .commands = virtex2_command_handler, - .pld_device_command = &virtex2_pld_device_command, + .pld_create_command = &virtex2_pld_create_command, .load = &virtex2_load, + .get_ipdbg_hub = xilinx_get_ipdbg_hub, + .get_jtagspi_userircode = xilinx_get_jtagspi_userircode, }; diff --git a/src/pld/virtex2.h b/src/pld/virtex2.h index d6d922e79d..b69e3c97a9 100644 --- a/src/pld/virtex2.h +++ b/src/pld/virtex2.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_PLD_VIRTEX2_H @@ -21,9 +10,23 @@ #include <jtag/jtag.h> +#define VIRTEX2_MAX_USER_INSTRUCTIONS 4 + +struct virtex2_command_set { + uint64_t cfg_out; + uint64_t cfg_in; + uint64_t jprog_b; + uint64_t jstart; + uint64_t jshutdown; + uint64_t bypass; + uint64_t user[VIRTEX2_MAX_USER_INSTRUCTIONS]; + unsigned int num_user; +}; + struct virtex2_pld_device { struct jtag_tap *tap; int no_jstart; + struct virtex2_command_set command_set; }; #endif /* OPENOCD_PLD_VIRTEX2_H */ diff --git a/src/pld/xilinx_bit.c b/src/pld/xilinx_bit.c index fe3faefc9e..e4cc52ef97 100644 --- a/src/pld/xilinx_bit.c +++ b/src/pld/xilinx_bit.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -24,7 +13,6 @@ #include "pld.h" #include <helper/log.h> -#include <sys/stat.h> #include <helper/system.h> static int read_section(FILE *input_file, int length_size, char section, @@ -71,53 +59,59 @@ static int read_section(FILE *input_file, int length_size, char section, int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char *filename) { FILE *input_file; - struct stat input_stat; int read_count; if (!filename || !bit_file) return ERROR_COMMAND_SYNTAX_ERROR; - if (stat(filename, &input_stat) == -1) { - LOG_ERROR("couldn't stat() %s: %s", filename, strerror(errno)); - return ERROR_PLD_FILE_LOAD_FAILED; - } - - if (S_ISDIR(input_stat.st_mode)) { - LOG_ERROR("%s is a directory", filename); - return ERROR_PLD_FILE_LOAD_FAILED; - } - - if (input_stat.st_size == 0) { - LOG_ERROR("Empty file %s", filename); - return ERROR_PLD_FILE_LOAD_FAILED; - } - input_file = fopen(filename, "rb"); if (!input_file) { LOG_ERROR("couldn't open %s: %s", filename, strerror(errno)); return ERROR_PLD_FILE_LOAD_FAILED; } + bit_file->source_file = NULL; + bit_file->part_name = NULL; + bit_file->date = NULL; + bit_file->time = NULL; + bit_file->data = NULL; + read_count = fread(bit_file->unknown_header, 1, 13, input_file); if (read_count != 13) { LOG_ERROR("couldn't read unknown_header from file '%s'", filename); + fclose(input_file); return ERROR_PLD_FILE_LOAD_FAILED; } - if (read_section(input_file, 2, 'a', NULL, &bit_file->source_file) != ERROR_OK) + if (read_section(input_file, 2, 'a', NULL, &bit_file->source_file) != ERROR_OK) { + xilinx_free_bit_file(bit_file); + fclose(input_file); return ERROR_PLD_FILE_LOAD_FAILED; + } - if (read_section(input_file, 2, 'b', NULL, &bit_file->part_name) != ERROR_OK) + if (read_section(input_file, 2, 'b', NULL, &bit_file->part_name) != ERROR_OK) { + xilinx_free_bit_file(bit_file); + fclose(input_file); return ERROR_PLD_FILE_LOAD_FAILED; + } - if (read_section(input_file, 2, 'c', NULL, &bit_file->date) != ERROR_OK) + if (read_section(input_file, 2, 'c', NULL, &bit_file->date) != ERROR_OK) { + xilinx_free_bit_file(bit_file); + fclose(input_file); return ERROR_PLD_FILE_LOAD_FAILED; + } - if (read_section(input_file, 2, 'd', NULL, &bit_file->time) != ERROR_OK) + if (read_section(input_file, 2, 'd', NULL, &bit_file->time) != ERROR_OK) { + xilinx_free_bit_file(bit_file); + fclose(input_file); return ERROR_PLD_FILE_LOAD_FAILED; + } - if (read_section(input_file, 4, 'e', &bit_file->length, &bit_file->data) != ERROR_OK) + if (read_section(input_file, 4, 'e', &bit_file->length, &bit_file->data) != ERROR_OK) { + xilinx_free_bit_file(bit_file); + fclose(input_file); return ERROR_PLD_FILE_LOAD_FAILED; + } LOG_DEBUG("bit_file: %s %s %s,%s %" PRIu32 "", bit_file->source_file, bit_file->part_name, bit_file->date, bit_file->time, bit_file->length); @@ -126,3 +120,12 @@ int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char *filename) return ERROR_OK; } + +void xilinx_free_bit_file(struct xilinx_bit_file *bit_file) +{ + free(bit_file->source_file); + free(bit_file->part_name); + free(bit_file->date); + free(bit_file->time); + free(bit_file->data); +} diff --git a/src/pld/xilinx_bit.h b/src/pld/xilinx_bit.h index 625a9d35e9..f443bf70eb 100644 --- a/src/pld/xilinx_bit.h +++ b/src/pld/xilinx_bit.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_PLD_XILINX_BIT_H @@ -33,4 +22,6 @@ struct xilinx_bit_file { int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char *filename); +void xilinx_free_bit_file(struct xilinx_bit_file *bit_file); + #endif /* OPENOCD_PLD_XILINX_BIT_H */ diff --git a/src/rtos/FreeRTOS.c b/src/rtos/FreeRTOS.c index ee6bdb3227..ea37f7fe7d 100644 --- a/src/rtos/FreeRTOS.c +++ b/src/rtos/FreeRTOS.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -33,6 +22,7 @@ #define FREERTOS_MAX_PRIORITIES 63 #define FREERTOS_THREAD_NAME_STR_SIZE 200 +#define FREERTOS_CURRENT_EXECUTION_ID 1 struct freertos_params { const char *target_name; @@ -59,6 +49,8 @@ struct FreeRTOS { unsigned ubasetype_size; /* sizeof(void *) */ unsigned pointer_size; + /* sizeof(TickType_t) */ + unsigned ticktype_size; unsigned list_width; unsigned list_item_width; unsigned list_elem_next_offset; @@ -81,7 +73,8 @@ static int cortex_m_stacking(struct rtos *rtos, const struct rtos_register_stack int cm4_fpu_enabled = 0; struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); if (is_armv7m(armv7m_target)) { - if (armv7m_target->fp_feature == FPV4_SP) { + if ((armv7m_target->fp_feature == FPV4_SP) || (armv7m_target->fp_feature == FPV5_SP) || + (armv7m_target->fp_feature == FPV5_DP)) { /* Found ARM v7m target which includes a FPU */ uint32_t cpacr; @@ -120,13 +113,45 @@ static int cortex_m_stacking(struct rtos *rtos, const struct rtos_register_stack return ERROR_OK; } -static int nds32_stacking(struct rtos *rtos, const struct rtos_register_stacking **stacking, - target_addr_t stack_ptr) +/* take 4 bytes (32 bits) as the default size, + * which is suitable for most 32-bit targets and + * configuration of configUSE_16_BIT_TICKS = 0. */ +static unsigned int freertos_ticktype_size = 4; +COMMAND_HANDLER(handle_freertos_ticktype_size) { - *stacking = &rtos_standard_nds32_n1068_stacking; + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + unsigned int size; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], size); + switch (size) { + case 2: + case 4: + case 8: + freertos_ticktype_size = size; + break; + default: + LOG_ERROR("Invalid ticktype size. Should be 2, 4 or 8."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + return ERROR_OK; } +static const struct command_registration freertos_commands[] = { + { + .name = "freertos_ticktype_size", + .handler = handle_freertos_ticktype_size, + .mode = COMMAND_ANY, + .usage = "(2|4|8)", + .help = "Pass the size (in bytes) of TickType_t to OpenOCD. To make sure the " + "calculation of offsets and sizes is correct. Defaults to 4." + }, + COMMAND_REGISTRATION_DONE +}; + static enum { STACKING_MAINLINE, STACKING_METAL @@ -195,10 +220,6 @@ static const struct freertos_params freertos_params_list[] = { .stacking = cortex_m_stacking }, { - .target_name = "nds32_v3", - .stacking = nds32_stacking, - }, - { .target_name = "riscv", .stacking = riscv_stacking, .commands = riscv_commands, @@ -215,7 +236,7 @@ static int freertos_get_thread_reg_value(struct rtos *rtos, threadid_t thread_id static int freertos_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value); static int freertos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); -struct rtos_type freertos_rtos = { +const struct rtos_type freertos_rtos = { .name = "FreeRTOS", .detect_rtos = freertos_detect_rtos, @@ -239,6 +260,7 @@ enum freertos_symbol_values { FREERTOS_VAL_X_SUSPENDED_TASK_LIST = 8, FREERTOS_VAL_UX_CURRENT_NUMBER_OF_TASKS = 9, FREERTOS_VAL_UX_TOP_USED_PRIORITY = 10, + FREERTOS_VAL_X_SCHEDULER_RUNNING = 11, }; struct symbols { @@ -258,6 +280,7 @@ static const struct symbols freertos_symbol_list[] = { { "xSuspendedTaskList", true }, /* Only if INCLUDE_vTaskSuspend */ { "uxCurrentNumberOfTasks", false }, { "uxTopUsedPriority", true }, /* Unavailable since v7.5.3 */ + { "xSchedulerRunning", false }, { NULL, false } }; @@ -305,13 +328,12 @@ static unsigned populate_offset_size(struct FreeRTOS *freertos, align = freertos->pointer_size; break; case TYPE_TICKTYPE: - /* Could be either 16 or 32 bits, depending on configUSE_16_BIT_TICKS. */ - info[i].size = 4; - align = 4; + info[i].size = freertos->ticktype_size; + align = freertos->ticktype_size; break; case TYPE_LIST_ITEM: info[i].size = freertos->list_item_width; - align = MAX(freertos->ubasetype_size, freertos->pointer_size); + align = MAX(freertos->ticktype_size, freertos->pointer_size); break; case TYPE_CHAR_ARRAY: /* size is set by the caller. */ @@ -347,11 +369,12 @@ static void freertos_compute_offsets(struct rtos *rtos) { struct FreeRTOS *freertos = (struct FreeRTOS *) rtos->rtos_specific_params; - if (freertos->pointer_size != 0) + if (freertos->ticktype_size == freertos_ticktype_size) return; freertos->pointer_size = DIV_ROUND_UP(target_address_bits(rtos->target), 8); freertos->ubasetype_size = DIV_ROUND_UP(target_data_bits(rtos->target), 8); + freertos->ticktype_size = freertos_ticktype_size; /* * FreeRTOS can be compiled with configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES @@ -474,21 +497,36 @@ static int freertos_update_threads(struct rtos *rtos) rtos_free_threadlist(rtos); /* read the current thread */ - target_addr_t pxCurrentTCB; + target_addr_t px_current_tcb; retval = freertos_read_struct_value(rtos->target, rtos->symbols[FREERTOS_VAL_PX_CURRENT_TCB].address, 0, freertos->pointer_size, - &pxCurrentTCB); + &px_current_tcb); if (retval != ERROR_OK) { LOG_ERROR("Error reading current thread in FreeRTOS thread list"); return retval; } LOG_DEBUG("FreeRTOS: Read pxCurrentTCB at 0x%" PRIx64 ", value 0x%" PRIx64, rtos->symbols[FREERTOS_VAL_PX_CURRENT_TCB].address, - pxCurrentTCB); + px_current_tcb); + + /* read scheduler running */ + uint64_t scheduler_running; + retval = freertos_read_struct_value(rtos->target, + rtos->symbols[FREERTOS_VAL_X_SCHEDULER_RUNNING].address, + 0, + freertos->ubasetype_size, + &scheduler_running); + if (retval != ERROR_OK) { + LOG_ERROR("Error reading FreeRTOS scheduler state"); + return retval; + } + LOG_DEBUG("FreeRTOS: Read xSchedulerRunning at 0x%" PRIx64 ", value 0x%" PRIx64, + rtos->symbols[FREERTOS_VAL_X_SCHEDULER_RUNNING].address, + scheduler_running); - if ((thread_list_size == 0) || (pxCurrentTCB == 0)) { + if (thread_list_size == 0 || px_current_tcb == 0 || scheduler_running != 1) { /* Either : No RTOS threads - there is always at least the current execution though */ /* OR : No current thread - all threads suspended - show the current execution * of idling */ @@ -501,7 +539,8 @@ static int freertos_update_threads(struct rtos *rtos) LOG_ERROR("Error allocating memory for %" PRIu64 " threads", thread_list_size); return ERROR_FAIL; } - rtos->thread_details->threadid = 1; + rtos->current_thread = FREERTOS_CURRENT_EXECUTION_ID; + rtos->thread_details->threadid = rtos->current_thread; rtos->thread_details->exists = true; rtos->thread_details->extra_info_str = NULL; rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str)); @@ -572,7 +611,6 @@ static int freertos_update_threads(struct rtos *rtos) list_of_lists[num_lists++] = rtos->symbols[FREERTOS_VAL_X_SUSPENDED_TASK_LIST].address; list_of_lists[num_lists++] = rtos->symbols[FREERTOS_VAL_X_TASKS_WAITING_TERMINATION].address; - rtos->current_thread = 0; for (unsigned int i = 0; i < num_lists; i++) { if (list_of_lists[i] == 0) continue; @@ -590,7 +628,7 @@ static int freertos_update_threads(struct rtos *rtos) return retval; } LOG_DEBUG("FreeRTOS: Read thread count for list %u at 0x%" PRIx64 ", value %" PRIu64, - i, list_of_lists[i], list_thread_count); + i, list_of_lists[i] + freertos->list_uxNumberOfItems_offset, list_thread_count); if (list_thread_count == 0) continue; @@ -634,8 +672,12 @@ static int freertos_update_threads(struct rtos *rtos) if (!value) { struct freertos_thread_entry *new_value = calloc(1, sizeof(struct freertos_thread_entry)); new_value->tcb = tcb; - /* threadid can't be 0. */ - new_value->threadid = ++freertos->last_threadid; + /* threadid can't be 0. + * plus 1 to avoid duplication with "Current Execution" */ + new_value->threadid = ++freertos->last_threadid + FREERTOS_CURRENT_EXECUTION_ID; + + LOG_DEBUG("FreeRTOS: new thread created, tcb=0x%" PRIx64 ", threadid=0x%" PRIx64, + new_value->tcb, new_value->threadid); list_add_tail(&new_value->list, &freertos->thread_entry_list); value = new_value; @@ -675,7 +717,7 @@ static int freertos_update_threads(struct rtos *rtos) strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str); rtos->thread_details[tasks_found].exists = true; - if (value->tcb == pxCurrentTCB) { + if (value->tcb == px_current_tcb && rtos->current_thread != FREERTOS_CURRENT_EXECUTION_ID) { char running_str[] = "State: Running"; rtos->current_thread = value->threadid; rtos->thread_details[tasks_found].extra_info_str = malloc( @@ -687,6 +729,7 @@ static int freertos_update_threads(struct rtos *rtos) tasks_found++; list_thread_count--; + rtos->thread_count = tasks_found; prev_list_elem_ptr = list_elem_ptr; list_elem_ptr = 0; @@ -708,7 +751,6 @@ static int freertos_update_threads(struct rtos *rtos) } free(list_of_lists); - rtos->thread_count = tasks_found; return 0; } @@ -914,5 +956,5 @@ static int freertos_create(struct target *target) return ERROR_FAIL; } - return ERROR_OK; + return register_commands(target->rtos->cmd_ctx, NULL, freertos_commands); } diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am index f09ac21a2e..0796910de8 100644 --- a/src/rtos/Makefile.am +++ b/src/rtos/Makefile.am @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/librtos.la %C%_librtos_la_SOURCES = \ %D%/rtos.c \ @@ -8,6 +10,7 @@ noinst_LTLIBRARIES += %D%/librtos.la %D%/rtos_mqx_stackings.c \ %D%/rtos_ucos_iii_stackings.c \ %D%/rtos_riot_stackings.c \ + %D%/rtos_nuttx_stackings.c \ %D%/FreeRTOS.c \ %D%/ThreadX.c \ %D%/eCos.c \ @@ -18,6 +21,7 @@ noinst_LTLIBRARIES += %D%/librtos.la %D%/mqx.c \ %D%/uCOS-III.c \ %D%/nuttx.c \ + %D%/rtkernel.c \ %D%/hwthread.c \ %D%/zephyr.c \ %D%/riot.c \ @@ -30,4 +34,4 @@ noinst_LTLIBRARIES += %D%/librtos.la %D%/rtos_mqx_stackings.h \ %D%/rtos_riot_stackings.h \ %D%/rtos_ucos_iii_stackings.h \ - %D%/nuttx_header.h + %D%/rtos_nuttx_stackings.h diff --git a/src/rtos/ThreadX.c b/src/rtos/ThreadX.c index 4161e63fa1..5bdd007d42 100644 --- a/src/rtos/ThreadX.c +++ b/src/rtos/ThreadX.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -331,6 +320,12 @@ static int threadx_update_threads(struct rtos *rtos) rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str)); strcpy(rtos->thread_details->thread_name_str, tmp_str); + /* If we just invented thread 1 to represent the current execution, we + * need to make sure the RTOS object also claims it's the current thread + * so that threadx_get_thread_reg_list() doesn't attempt to read a + * thread control block at 0x00000001. */ + rtos->current_thread = 1; + if (thread_list_size == 0) { rtos->thread_count = 1; return ERROR_OK; @@ -375,16 +370,21 @@ static int threadx_update_threads(struct rtos *rtos) } /* Read the thread name */ - retval = - target_read_buffer(rtos->target, - name_ptr, - THREADX_THREAD_NAME_STR_SIZE, - (uint8_t *)&tmp_str); - if (retval != ERROR_OK) { - LOG_ERROR("Error reading thread name from ThreadX target"); - return retval; + tmp_str[0] = '\x00'; + + /* Check if thread has a valid name */ + if (name_ptr != 0) { + retval = + target_read_buffer(rtos->target, + name_ptr, + THREADX_THREAD_NAME_STR_SIZE, + (uint8_t *)&tmp_str); + if (retval != ERROR_OK) { + LOG_ERROR("Error reading thread name from ThreadX target"); + return retval; + } + tmp_str[THREADX_THREAD_NAME_STR_SIZE - 1] = '\x00'; } - tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00'; if (tmp_str[0] == '\x00') strcpy(tmp_str, "No Name"); diff --git a/src/rtos/chibios.c b/src/rtos/chibios.c index ef1f34d514..20378274ec 100644 --- a/src/rtos/chibios.c +++ b/src/rtos/chibios.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2012 by Matthias Blaicher * * Matthias Blaicher - matthias@blaicher.com * * * * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -91,12 +80,12 @@ struct chibios_params { static struct chibios_params chibios_params_list[] = { { "cortex_m", /* target_name */ - 0, + NULL, NULL, /* stacking_info */ }, { "hla_target", /* target_name */ - 0, + NULL, NULL, /* stacking_info */ } }; @@ -108,7 +97,7 @@ static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); -struct rtos_type chibios_rtos = { +const struct rtos_type chibios_rtos = { .name = "chibios", .detect_rtos = chibios_detect_rtos, @@ -209,7 +198,7 @@ static int chibios_update_memory_signature(struct rtos *rtos) errfree: /* Error reading the ChibiOS memory structure */ free(signature); - param->signature = 0; + param->signature = NULL; return -1; } @@ -479,7 +468,7 @@ static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, return -1; /* Update stacking if it can only be determined from runtime information */ - if ((param->stacking_info == 0) && + if (!param->stacking_info && (chibios_update_stacking(rtos) != ERROR_OK)) { LOG_ERROR("Failed to determine exact stacking for the target type %s", rtos->target->type->name); return -1; diff --git a/src/rtos/chromium-ec.c b/src/rtos/chromium-ec.c index 95a228d0d3..a95969e345 100644 --- a/src/rtos/chromium-ec.c +++ b/src/rtos/chromium-ec.c @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only + /* - * SPDX-License-Identifier: GPL-2.0 - * * Copyright (c) 2018 National Instruments Corp * Author: Moritz Fischer <moritz.fischer@ettus.com> * diff --git a/src/rtos/eCos.c b/src/rtos/eCos.c index a81d7b9932..10ed12809f 100644 --- a/src/rtos/eCos.c +++ b/src/rtos/eCos.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -22,66 +11,446 @@ #include <jtag/jtag.h> #include "target/target.h" #include "target/target_type.h" +#include "target/armv7m.h" #include "rtos.h" #include "helper/log.h" #include "helper/types.h" +#include "helper/bits.h" +#include "rtos_standard_stackings.h" #include "rtos_ecos_stackings.h" +#include "server/gdb_server.h" + +/* Unfortunately for the moment we are limited to returning the hardwired + * register count (ARMV7M_NUM_CORE_REGS for Cortex-M) since the openocd RTOS + * support does not yet support accessing all per-thread "stacked" + * registers. e.g. For Cortex-M under eCos we have a per-thread BASEPRI, and for + * all eCos targets we may have per-thread VFP/FPU register state. + * + * So, for the moment, we continue to use the hardwired limit for the depth of + * the returned register description vector. The current openocd + * rtos_standard_stackings.c just provides the main core regs for the Cortex_M* + * targets regardless of whether FPU is present/enabled. + * + * However, this code is written with the expectation that we may eventually be + * able to provide more register information ("m-system" and "vfp" for example) + * and also with the expectation of supporting different register sets being + * returned depending on the per-thread Cortex-M eCos contex_m for + * example. Hence the fact that the eCos_stack_layout_*() functions below allow + * for the stack context descriptor vector to be returned by those calls + * allowing for eventual support where this code will potentially cache + * different sets of register descriptors for the different shapes of contexts + * in a *single* application/binary run-time. + * + * TODO: Extend openocd generic RTOS support to allow thread-specific system and + * FPU register state to be returned. */ + +struct ecos_params; static bool ecos_detect_rtos(struct target *target); static int ecos_create(struct target *target); static int ecos_update_threads(struct rtos *rtos); static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int ecos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); +static int ecos_stack_layout_cortexm(struct rtos *rtos, struct ecos_params *param, + int64_t stack_ptr, const struct rtos_register_stacking **si); +static int ecos_stack_layout_arm(struct rtos *rtos, struct ecos_params *param, + int64_t stack_ptr, const struct rtos_register_stacking **si); + +/* The current eCos thread IDentifier uses 0 as an unused (not a valid thread + * ID) value. Currently the unique_id field is 16-bits, but the eCos SMP support + * convention is that only 12-bits of the ID will be used. This + * ECOS_MAX_THREAD_COUNT manifest is provided to limit the potential for + * interpreting stale/inconsistent thread list state when the debug host scans + * the thread list before the target RTOS has completed its initialisation. This + * support will need to revisited when eCos is re-engineered to support more + * than 16 CPU SMP setups. */ +#define ECOS_MAX_THREAD_COUNT (4095) struct ecos_thread_state { int value; const char *desc; }; -static const struct ecos_thread_state ecos_thread_states[] = { - { 0, "Ready" }, - { 1, "Sleeping" }, - { 2, "Countsleep" }, - { 4, "Suspended" }, - { 8, "Creating" }, - { 16, "Exited" } +/* The status is actually a logical-OR bitmask of states: */ +enum ecos_thread_state_flags { + RUNNING = 0, /* explicit no-bits-set value */ + SLEEPING = BIT(0), + COUNTSLEEP = BIT(1), + SUSPENDED = BIT(2), + CREATING = BIT(3), + EXITED = BIT(4), + SLEEPSET = (SLEEPING | COUNTSLEEP) +}; + +/* Cyg_Thread:: reason codes for wake and sleep fields: */ +static const struct ecos_thread_state ecos_thread_reasons[] = { + { 0, "NONE" }, /* normally indicates "not yet started" */ + { 1, "WAIT" }, /* wait with no timeout */ + { 2, "DELAY" }, /* simple time delay */ + { 3, "TIMEOUT" }, /* wait with timeout *or* timeout expired */ + { 4, "BREAK" }, /* forced break out of sleep */ + { 5, "DESTRUCT" }, /* wait on object being destroyed */ + { 6, "EXIT" }, /* forced termination */ + { 7, "DONE" } /* wait/delay completed */ +}; + +static const char * const target_cortex_m[] = { + "cortex_m", + "hla_target", + NULL +}; + +static const char * const target_arm[] = { + "cortex_a", + "arm7tdmi", + "arm720t", + "arm9tdmi", + "arm920t", + "arm926ejs", + "arm946e", + "arm966e", + "arm11", + NULL }; -#define ECOS_NUM_STATES ARRAY_SIZE(ecos_thread_states) +/* Since individual eCos application configurations may have different thread + * object structure layouts depending on the actual build-time enabled features + * we provide support for applications built containing the relevant symbolic + * support to match the actual application binary being debugged, rather than + * relying on a set of default/fixed (and potentially incorrect) + * offsets. However, for backwards compatibility, we do *NOT* enforce the + * requirement for the common extra helper symbols to be present to allow the + * fallback to the simple fixed CM3 model to avoid affecting existing users of + * older eCos worlds. Similarly we need to provide support for per-thread + * register context offsets, as well as for per-application-configurations, + * since some targets can have different stacked state on a per-thread basis + * (e.g. "cortex_m"). This is why the stacking_info is now set at run-time + * rather than being fixed. */ struct ecos_params { - const char *target_name; + const char * const *target_names; /* NULL terminated list of targets */ + int (*target_stack_layout)(struct rtos *rtos, struct ecos_params *param, + int64_t stack_ptr, const struct rtos_register_stacking **si); + bool flush_common; unsigned char pointer_width; - unsigned char thread_stack_offset; - unsigned char thread_name_offset; - unsigned char thread_state_offset; - unsigned char thread_next_offset; - unsigned char thread_uniqueid_offset; + unsigned char uid_width; + unsigned char state_width; + unsigned int thread_stack_offset; + unsigned int thread_name_offset; + unsigned int thread_state_offset; + unsigned int thread_next_offset; + unsigned int thread_uniqueid_offset; const struct rtos_register_stacking *stacking_info; }; -static const struct ecos_params ecos_params_list[] = { +/* As mentioned above we provide default offset values for the "cortex_m" + * targets for backwards compatibility with older eCos application builds and + * previous users of this RTOS specific support that do not have the + * configuration specific offsets provided in the symbol table. The support for + * other targets (e.g. "cortex_a") we do expect the application to provide the + * required symbolic information. We do not populate the stacking_info reference + * until we have had a chance to interrogate the symbol table. */ + +static struct ecos_params ecos_params_list[] = { { - "cortex_m", /* target_name */ - 4, /* pointer_width; */ - 0x0c, /* thread_stack_offset; */ - 0x9c, /* thread_name_offset; */ - 0x3c, /* thread_state_offset; */ - 0xa0, /* thread_next_offset */ - 0x4c, /* thread_uniqueid_offset */ - &rtos_ecos_cortex_m3_stacking /* stacking_info */ + .target_names = target_cortex_m, + .pointer_width = 4, + .uid_width = 2, + .state_width = 4, + .thread_stack_offset = 0x0c, + .thread_name_offset = 0x9c, + .thread_state_offset = 0x3c, + .thread_next_offset = 0xa0, + .thread_uniqueid_offset = 0x4c, + .target_stack_layout = ecos_stack_layout_cortexm, + .stacking_info = NULL + }, + { + .target_names = target_arm, + .pointer_width = 0, + .uid_width = 0, + .state_width = 0, + .thread_stack_offset = 0, + .thread_name_offset = 0, + .thread_state_offset = 0, + .thread_next_offset = 0, + .thread_uniqueid_offset = 0, + .target_stack_layout = ecos_stack_layout_arm, + .stacking_info = NULL } }; +#define ECOS_NUM_PARAMS ARRAY_SIZE(ecos_params_list) + +/* To eventually allow for more than just the ARMV7M_NUM_CORE_REGS to be + * returned by the Cortex-M support, and to avoid run-time lookups we manually + * maintain our own mapping for the supplied stack register vector entries. This + * enum needs to match the rtos_ecos_regoff_cortexm[] vector. Admittedly the + * initial indices just match the corresponding ARMV7M_R* definitions, but after + * the base registers the ARMV7M_* number space does not match the vector we + * wish to populate in this eCos support code. */ +enum ecos_reglist_cortexm { + ECOS_REGLIST_R0 = 0, + ECOS_REGLIST_R1, + ECOS_REGLIST_R2, + ECOS_REGLIST_R3, + ECOS_REGLIST_R4, + ECOS_REGLIST_R5, + ECOS_REGLIST_R6, + ECOS_REGLIST_R7, + ECOS_REGLIST_R8, + ECOS_REGLIST_R9, + ECOS_REGLIST_R10, + ECOS_REGLIST_R11, + ECOS_REGLIST_R12, + ECOS_REGLIST_R13, + ECOS_REGLIST_R14, + ECOS_REGLIST_PC, + ECOS_REGLIST_XPSR, /* ARMV7M_NUM_CORE_REGS */ + ECOS_REGLIST_BASEPRI, + ECOS_REGLIST_FPSCR, /* Following for FPU contexts */ + ECOS_REGLIST_D0, + ECOS_REGLIST_D1, + ECOS_REGLIST_D2, + ECOS_REGLIST_D3, + ECOS_REGLIST_D4, + ECOS_REGLIST_D5, + ECOS_REGLIST_D6, + ECOS_REGLIST_D7, + ECOS_REGLIST_D8, + ECOS_REGLIST_D9, + ECOS_REGLIST_D10, + ECOS_REGLIST_D11, + ECOS_REGLIST_D12, + ECOS_REGLIST_D13, + ECOS_REGLIST_D14, + ECOS_REGLIST_D15 +}; + +#define ECOS_CORTEXM_BASE_NUMREGS (ARMV7M_NUM_CORE_REGS) + +/* NOTE: The offsets in this vector are overwritten by the architecture specific + * layout functions depending on the specific application configuration. The + * ordering of this vector MUST match eCos_reglist. */ +static struct stack_register_offset rtos_ecos_regoff_cortexm[] = { + { ARMV7M_R0, -1, 32 }, /* r0 */ + { ARMV7M_R1, -1, 32 }, /* r1 */ + { ARMV7M_R2, -1, 32 }, /* r2 */ + { ARMV7M_R3, -1, 32 }, /* r3 */ + { ARMV7M_R4, -1, 32 }, /* r4 */ + { ARMV7M_R5, -1, 32 }, /* r5 */ + { ARMV7M_R6, -1, 32 }, /* r6 */ + { ARMV7M_R7, -1, 32 }, /* r7 */ + { ARMV7M_R8, -1, 32 }, /* r8 */ + { ARMV7M_R9, -1, 32 }, /* r9 */ + { ARMV7M_R10, -1, 32 }, /* r10 */ + { ARMV7M_R11, -1, 32 }, /* r11 */ + { ARMV7M_R12, -1, 32 }, /* r12 */ + { ARMV7M_R13, -1, 32 }, /* sp */ + { ARMV7M_R14, -1, 32 }, /* lr */ + { ARMV7M_PC, -1, 32 }, /* pc */ + { ARMV7M_XPSR, -1, 32 }, /* xPSR */ + { ARMV7M_BASEPRI, -1, 32 }, /* BASEPRI */ + { ARMV7M_FPSCR, -1, 32 }, /* FPSCR */ + { ARMV7M_D0, -1, 64 }, /* D0 (S0/S1) */ + { ARMV7M_D1, -1, 64 }, /* D1 (S2/S3) */ + { ARMV7M_D2, -1, 64 }, /* D2 (S4/S5) */ + { ARMV7M_D3, -1, 64 }, /* D3 (S6/S7) */ + { ARMV7M_D4, -1, 64 }, /* D4 (S8/S9) */ + { ARMV7M_D5, -1, 64 }, /* D5 (S10/S11) */ + { ARMV7M_D6, -1, 64 }, /* D6 (S12/S13) */ + { ARMV7M_D7, -1, 64 }, /* D7 (S14/S15) */ + { ARMV7M_D8, -1, 64 }, /* D8 (S16/S17) */ + { ARMV7M_D9, -1, 64 }, /* D9 (S18/S19) */ + { ARMV7M_D10, -1, 64 }, /* D10 (S20/S21) */ + { ARMV7M_D11, -1, 64 }, /* D11 (S22/S23) */ + { ARMV7M_D12, -1, 64 }, /* D12 (S24/S25) */ + { ARMV7M_D13, -1, 64 }, /* D13 (S26/S27) */ + { ARMV7M_D14, -1, 64 }, /* D14 (S28/S29) */ + { ARMV7M_D15, -1, 64 }, /* D15 (S30/S31) */ +}; + +static struct stack_register_offset rtos_ecos_regoff_arm[] = { + { 0, -1, 32 }, /* r0 */ + { 1, -1, 32 }, /* r1 */ + { 2, -1, 32 }, /* r2 */ + { 3, -1, 32 }, /* r3 */ + { 4, -1, 32 }, /* r4 */ + { 5, -1, 32 }, /* r5 */ + { 6, -1, 32 }, /* r6 */ + { 7, -1, 32 }, /* r7 */ + { 8, -1, 32 }, /* r8 */ + { 9, -1, 32 }, /* r9 */ + { 10, -1, 32 }, /* r10 */ + { 11, -1, 32 }, /* r11 (fp) */ + { 12, -1, 32 }, /* r12 (ip) */ + { 13, -1, 32 }, /* sp (r13) */ + { 14, -1, 32 }, /* lr (r14) */ + { 15, -1, 32 }, /* pc (r15) */ + { 16, -1, 32 }, /* xPSR */ +}; + +static struct rtos_register_stacking rtos_ecos_stacking = { + .stack_registers_size = 0, + .stack_growth_direction = -1, + .num_output_registers = 0, + .calculate_process_stack = NULL, /* stack_alignment */ + .register_offsets = NULL +}; + +/* To avoid the run-time cost of matching explicit symbol names we push the + * lookup offsets to this *manually* maintained enumeration which must match the + * ecos_symbol_list[] order below. */ enum ecos_symbol_values { ECOS_VAL_THREAD_LIST = 0, - ECOS_VAL_CURRENT_THREAD_PTR = 1 + ECOS_VAL_CURRENT_THREAD_PTR, + ECOS_VAL_COMMON_THREAD_NEXT_OFF, + ECOS_VAL_COMMON_THREAD_NEXT_SIZE, + ECOS_VAL_COMMON_THREAD_STATE_OFF, + ECOS_VAL_COMMON_THREAD_STATE_SIZE, + ECOS_VAL_COMMON_THREAD_SLEEP_OFF, + ECOS_VAL_COMMON_THREAD_SLEEP_SIZE, + ECOS_VAL_COMMON_THREAD_WAKE_OFF, + ECOS_VAL_COMMON_THREAD_WAKE_SIZE, + ECOS_VAL_COMMON_THREAD_ID_OFF, + ECOS_VAL_COMMON_THREAD_ID_SIZE, + ECOS_VAL_COMMON_THREAD_NAME_OFF, + ECOS_VAL_COMMON_THREAD_NAME_SIZE, + ECOS_VAL_COMMON_THREAD_PRI_OFF, + ECOS_VAL_COMMON_THREAD_PRI_SIZE, + ECOS_VAL_COMMON_THREAD_STACK_OFF, + ECOS_VAL_COMMON_THREAD_STACK_SIZE, + ECOS_VAL_CORTEXM_THREAD_SAVED, + ECOS_VAL_CORTEXM_CTX_THREAD_SIZE, + ECOS_VAL_CORTEXM_CTX_TYPE_OFF, + ECOS_VAL_CORTEXM_CTX_TYPE_SIZE, + ECOS_VAL_CORTEXM_CTX_BASEPRI_OFF, + ECOS_VAL_CORTEXM_CTX_BASEPRI_SIZE, + ECOS_VAL_CORTEXM_CTX_SP_OFF, + ECOS_VAL_CORTEXM_CTX_SP_SIZE, + ECOS_VAL_CORTEXM_CTX_REG_OFF, + ECOS_VAL_CORTEXM_CTX_REG_SIZE, + ECOS_VAL_CORTEXM_CTX_PC_OFF, + ECOS_VAL_CORTEXM_CTX_PC_SIZE, + ECOS_VAL_CORTEXM_VAL_EXCEPTION, + ECOS_VAL_CORTEXM_VAL_THREAD, + ECOS_VAL_CORTEXM_VAL_INTERRUPT, + ECOS_VAL_CORTEXM_VAL_FPU, + ECOS_VAL_CORTEXM_CTX_FPSCR_OFF, + ECOS_VAL_CORTEXM_CTX_FPSCR_SIZE, + ECOS_VAL_CORTEXM_CTX_S_OFF, + ECOS_VAL_CORTEXM_CTX_S_SIZE, + ECOS_VAL_ARM_REGSIZE, + ECOS_VAL_ARM_CTX_R0_OFF, + ECOS_VAL_ARM_CTX_R1_OFF, + ECOS_VAL_ARM_CTX_R2_OFF, + ECOS_VAL_ARM_CTX_R3_OFF, + ECOS_VAL_ARM_CTX_R4_OFF, + ECOS_VAL_ARM_CTX_R5_OFF, + ECOS_VAL_ARM_CTX_R6_OFF, + ECOS_VAL_ARM_CTX_R7_OFF, + ECOS_VAL_ARM_CTX_R8_OFF, + ECOS_VAL_ARM_CTX_R9_OFF, + ECOS_VAL_ARM_CTX_R10_OFF, + ECOS_VAL_ARM_CTX_FP_OFF, + ECOS_VAL_ARM_CTX_IP_OFF, + ECOS_VAL_ARM_CTX_SP_OFF, + ECOS_VAL_ARM_CTX_LR_OFF, + ECOS_VAL_ARM_CTX_PC_OFF, + ECOS_VAL_ARM_CTX_CPSR_OFF, + ECOS_VAL_ARM_FPUSIZE, + ECOS_VAL_ARM_CTX_FPSCR_OFF, + ECOS_VAL_ARM_SCOUNT, + ECOS_VAL_ARM_CTX_SVEC_OFF, + ECOS_VAL_ARM_VFPCOUNT, + ECOS_VAL_ARM_CTX_VFPVEC_OFF }; -static const char * const ecos_symbol_list[] = { - "Cyg_Thread::thread_list", - "Cyg_Scheduler_Base::current_thread", - NULL +struct symbols { + const char *name; + const char * const *target_names; /* non-NULL when for a specific architecture */ + bool optional; +}; + +#define ECOSSYM(_n, _o, _t) { .name = _n, .optional = (_o), .target_names = _t } + +/* Some of offset/size helper symbols are common to all eCos + * targets. Unfortunately, for historical reasons, some information is in + * architecture specific namespaces leading to some duplication and a larger + * vector below. */ +static const struct symbols ecos_symbol_list[] = { + ECOSSYM("Cyg_Thread::thread_list", false, NULL), + ECOSSYM("Cyg_Scheduler_Base::current_thread", false, NULL), + /* Following symbols *are* required for generic application-specific + * configuration support, but we mark as optional for backwards + * compatibility with the previous fixed Cortex-M3 only RTOS plugin + * implementation. */ + ECOSSYM("__ecospro_syminfo.off.cyg_thread.list_next", true, NULL), + ECOSSYM("__ecospro_syminfo.size.cyg_thread.list_next", true, NULL), + ECOSSYM("__ecospro_syminfo.off.cyg_thread.state", true, NULL), + ECOSSYM("__ecospro_syminfo.size.cyg_thread.state", true, NULL), + ECOSSYM("__ecospro_syminfo.off.cyg_thread.sleep_reason", true, NULL), + ECOSSYM("__ecospro_syminfo.size.cyg_thread.sleep_reason", true, NULL), + ECOSSYM("__ecospro_syminfo.off.cyg_thread.wake_reason", true, NULL), + ECOSSYM("__ecospro_syminfo.size.cyg_thread.wake_reason", true, NULL), + ECOSSYM("__ecospro_syminfo.off.cyg_thread.unique_id", true, NULL), + ECOSSYM("__ecospro_syminfo.size.cyg_thread.unique_id", true, NULL), + ECOSSYM("__ecospro_syminfo.off.cyg_thread.name", true, NULL), + ECOSSYM("__ecospro_syminfo.size.cyg_thread.name", true, NULL), + ECOSSYM("__ecospro_syminfo.off.cyg_thread.priority", true, NULL), + ECOSSYM("__ecospro_syminfo.size.cyg_thread.priority", true, NULL), + ECOSSYM("__ecospro_syminfo.off.cyg_thread.stack_ptr", true, NULL), + ECOSSYM("__ecospro_syminfo.size.cyg_thread.stack_ptr", true, NULL), + /* optional Cortex-M: */ + ECOSSYM("__ecospro_syminfo.cortexm.thread.saved", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.Thread", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.type", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.type", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.basepri", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.basepri", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.sp", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.sp", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.r", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.r", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.pc", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.pc", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.value.HAL_SAVEDREGISTERS.EXCEPTION", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.value.HAL_SAVEDREGISTERS.THREAD", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.value.HAL_SAVEDREGISTERS.INTERRUPT", true, target_cortex_m), + /* optional Cortex-M with H/W FPU configured: */ + ECOSSYM("__ecospro_syminfo.value.HAL_SAVEDREGISTERS.WITH_FPU", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.fpscr", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.fpscr", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.off.HAL_SavedRegisters.u.thread.s", true, target_cortex_m), + ECOSSYM("__ecospro_syminfo.size.HAL_SavedRegisters.u.thread.s", true, target_cortex_m), + /* optional ARM: */ + ECOSSYM("ARMREG_SIZE", true, target_arm), + ECOSSYM("armreg_r0", true, target_arm), + ECOSSYM("armreg_r1", true, target_arm), + ECOSSYM("armreg_r2", true, target_arm), + ECOSSYM("armreg_r3", true, target_arm), + ECOSSYM("armreg_r4", true, target_arm), + ECOSSYM("armreg_r5", true, target_arm), + ECOSSYM("armreg_r6", true, target_arm), + ECOSSYM("armreg_r7", true, target_arm), + ECOSSYM("armreg_r8", true, target_arm), + ECOSSYM("armreg_r9", true, target_arm), + ECOSSYM("armreg_r10", true, target_arm), + ECOSSYM("armreg_fp", true, target_arm), + ECOSSYM("armreg_ip", true, target_arm), + ECOSSYM("armreg_sp", true, target_arm), + ECOSSYM("armreg_lr", true, target_arm), + ECOSSYM("armreg_pc", true, target_arm), + ECOSSYM("armreg_cpsr", true, target_arm), + /* optional ARM FPU common: */ + ECOSSYM("ARMREG_FPUCONTEXT_SIZE", true, target_arm), + ECOSSYM("armreg_fpscr", true, target_arm), + /* optional ARM FPU single-precision: */ + ECOSSYM("ARMREG_S_COUNT", true, target_arm), + ECOSSYM("armreg_s_vec", true, target_arm), + /* optional ARM FPU double-precision: */ + ECOSSYM("ARMREG_VFP_COUNT", true, target_arm), + ECOSSYM("armreg_vfp_vec", true, target_arm), }; const struct rtos_type ecos_rtos = { @@ -95,34 +464,280 @@ const struct rtos_type ecos_rtos = { }; +static symbol_address_t ecos_value(struct rtos *rtos, unsigned int idx) +{ + if (idx < ARRAY_SIZE(ecos_symbol_list)) + return rtos->symbols[idx].address; + + /* We do not terminate, just return 0 in this case. */ + LOG_ERROR("eCos: Invalid symbol index %u", idx); + return 0; +} + +#define XMLENTRY(_c, _s) { .xc = (_c), .rs = (_s), .rlen = (sizeof(_s) - 1) } + +static const struct { + char xc; + const char *rs; + size_t rlen; +} xmlchars[] = { + XMLENTRY('<', "<"), + XMLENTRY('&', "&"), + XMLENTRY('>', ">"), + XMLENTRY('\'', "'"), + XMLENTRY('"', """) +}; + +/** Escape any XML reserved characters in a string. */ +static bool ecos_escape_string(const char *raw, char *out, size_t limit) +{ + static const char *tokens = "<&>\'\""; + bool escaped = false; + + if (!out || !limit) + return false; + + (void)memset(out, '\0', limit); + + while (raw && *raw && limit) { + size_t lok = strcspn(raw, tokens); + if (lok) { + size_t tocopy; + tocopy = ((limit < lok) ? limit : lok); + (void)memcpy(out, raw, tocopy); + limit -= tocopy; + out += tocopy; + raw += lok; + continue; + } + + char *fidx = strchr(tokens, *raw); + if (!fidx) { + /* Should never happen assuming xmlchars + * vector and tokens string match. */ + LOG_ERROR("eCos: Unexpected XML char %c", *raw); + continue; + } + + uint32_t cidx = (fidx - tokens); + size_t tocopy = xmlchars[cidx].rlen; + if (limit < tocopy) + break; + + escaped = true; + (void)memcpy(out, xmlchars[cidx].rs, tocopy); + limit -= tocopy; + out += tocopy; + raw++; + } + + return escaped; +} + +static int ecos_check_app_info(struct rtos *rtos, struct ecos_params *param) +{ + if (!rtos || !param) + return -1; + + if (param->flush_common) { + if (debug_level >= LOG_LVL_DEBUG) { + for (unsigned int idx = 0; idx < ARRAY_SIZE(ecos_symbol_list); idx++) { + LOG_DEBUG("eCos: %s 0x%016" PRIX64 " %s", + rtos->symbols[idx].optional ? "OPTIONAL" : " ", + rtos->symbols[idx].address, rtos->symbols[idx].symbol_name); + } + } + + /* If "__ecospro_syminfo.size.cyg_thread.list_next" is non-zero then we + * expect all of the generic thread structure symbols to have been + * provided. */ + symbol_address_t thread_next_size = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_NEXT_SIZE); + if (thread_next_size != 0) { + param->pointer_width = thread_next_size; + param->uid_width = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_ID_SIZE); + param->state_width = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_STATE_SIZE); + param->thread_stack_offset = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_STACK_OFF); + param->thread_name_offset = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_NAME_OFF); + param->thread_state_offset = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_STATE_OFF); + param->thread_next_offset = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_NEXT_OFF); + param->thread_uniqueid_offset = ecos_value(rtos, ECOS_VAL_COMMON_THREAD_ID_OFF); + } + + if (param->uid_width != sizeof(uint16_t)) { + /* Currently all eCos configurations use a 16-bit field to hold the + * unique thread ID. */ + LOG_WARNING("eCos: Unexpected unique_id width %" PRIu8, param->uid_width); + param->uid_width = (unsigned char)sizeof(uint16_t); + } + + param->stacking_info = NULL; + param->flush_common = false; + } + + return ERROR_OK; +} + +/* The Cortex-M eCosPro "thread" contexts have a "type" indicator, which tracks + * the context state of (THREAD | EXCEPTION | INTERRUPT) and whether FPU + * registers are saved. + * + * For thread-aware debugging from GDB we are only interested in THREAD states + * and so do not need to implement support for INTERRUPT or EXCEPTION thread + * contexts since this code does not expose those stack contexts via the + * constructed thread list support. */ +static int ecos_stack_layout_cortexm(struct rtos *rtos, + struct ecos_params *param, int64_t stack_ptr, + const struct rtos_register_stacking **si) +{ + int retval = ERROR_OK; + + /* CONSIDER: We could return + * ecos_value(rtos, ECOS_VAL_CORTEXM_THREAD_SAVED) as the actual PC + * address of a context switch, with the LR being set to the context PC + * field to give a true representation of where the thread switch + * occurs. However that would require extending the common + * rtos_generic_stack_read() code with suitable support for applying a + * supplied value, or just implementing our own version of that code that + * can inject data into what is passed onwards to GDB. */ + + /* UPDATE: When we can return VFP register state then we will NOT be + * basing the cached state on the single param->stacking_info value, + * since we will need a different stacking_info structure returned for + * each thread type when FPU support is enabled. The use of the single + * param->stacking_info is a holder whilst we are limited to the fixed + * ARMV7M_NUM_CORE_REGS set of descriptors. */ + + if (!param->stacking_info && + ecos_value(rtos, ECOS_VAL_CORTEXM_THREAD_SAVED) && + ecos_value(rtos, ECOS_VAL_CORTEXM_VAL_THREAD)) { + unsigned char numoutreg = ECOS_CORTEXM_BASE_NUMREGS; + + rtos_ecos_stacking.stack_registers_size = ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_THREAD_SIZE); + rtos_ecos_stacking.calculate_process_stack = rtos_generic_stack_align8; + rtos_ecos_stacking.register_offsets = rtos_ecos_regoff_cortexm; + + rtos_ecos_regoff_cortexm[ECOS_REGLIST_R0].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x00); + rtos_ecos_regoff_cortexm[ECOS_REGLIST_R1].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x04); + rtos_ecos_regoff_cortexm[ECOS_REGLIST_R2].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x08); + rtos_ecos_regoff_cortexm[ECOS_REGLIST_R3].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x0C); + rtos_ecos_regoff_cortexm[ECOS_REGLIST_R4].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x10); + rtos_ecos_regoff_cortexm[ECOS_REGLIST_R5].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x14); + rtos_ecos_regoff_cortexm[ECOS_REGLIST_R6].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x18); + rtos_ecos_regoff_cortexm[ECOS_REGLIST_R7].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x1C); + rtos_ecos_regoff_cortexm[ECOS_REGLIST_R8].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x20); + rtos_ecos_regoff_cortexm[ECOS_REGLIST_R9].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x24); + rtos_ecos_regoff_cortexm[ECOS_REGLIST_R10].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x28); + rtos_ecos_regoff_cortexm[ECOS_REGLIST_R11].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x2C); + rtos_ecos_regoff_cortexm[ECOS_REGLIST_R12].offset = (ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_REG_OFF) + 0x30); + /* Rather than using the stacked ECOS_VAL_CORTEXM_CTX_SP_OFF + * value we force the reported sp to be after the stacked + * register context. */ + rtos_ecos_regoff_cortexm[ECOS_REGLIST_R13].offset = -2; + rtos_ecos_regoff_cortexm[ECOS_REGLIST_R14].offset = -1; + rtos_ecos_regoff_cortexm[ECOS_REGLIST_PC].offset = ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_PC_OFF); + rtos_ecos_regoff_cortexm[ECOS_REGLIST_XPSR].offset = -1; + + param->stacking_info = &rtos_ecos_stacking; + + /* Common Cortex-M thread register offsets for the current + * symbol table: */ + if (retval == ERROR_OK && param->stacking_info) { + if (numoutreg > ECOS_REGLIST_BASEPRI) { + rtos_ecos_regoff_cortexm[ECOS_REGLIST_BASEPRI].offset = + ecos_value(rtos, ECOS_VAL_CORTEXM_CTX_BASEPRI_OFF); + } + + rtos_ecos_stacking.num_output_registers = numoutreg; + } + } + + if (si) + *si = param->stacking_info; + + return retval; +} + +static int ecos_stack_layout_arm(struct rtos *rtos, struct ecos_params *param, + int64_t stack_ptr, const struct rtos_register_stacking **si) +{ + int retval = ERROR_OK; + + if (!param->stacking_info && ecos_value(rtos, ECOS_VAL_ARM_REGSIZE)) { + /* When OpenOCD is extended to allow FPU registers to be returned from a + * stacked thread context we can check: + * if (0 != ecos_value(rtos, ECOS_VAL_ARM_FPUSIZE)) { FPU } + * for presence of FPU registers in the context. */ + + rtos_ecos_stacking.stack_registers_size = ecos_value(rtos, ECOS_VAL_ARM_REGSIZE); + rtos_ecos_stacking.num_output_registers = ARRAY_SIZE(rtos_ecos_regoff_arm); + rtos_ecos_stacking.register_offsets = rtos_ecos_regoff_arm; + + rtos_ecos_regoff_arm[0].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R0_OFF); + rtos_ecos_regoff_arm[1].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R1_OFF); + rtos_ecos_regoff_arm[2].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R2_OFF); + rtos_ecos_regoff_arm[3].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R3_OFF); + rtos_ecos_regoff_arm[4].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R4_OFF); + rtos_ecos_regoff_arm[5].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R5_OFF); + rtos_ecos_regoff_arm[6].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R6_OFF); + rtos_ecos_regoff_arm[7].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R7_OFF); + rtos_ecos_regoff_arm[8].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R8_OFF); + rtos_ecos_regoff_arm[9].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R9_OFF); + rtos_ecos_regoff_arm[10].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_R10_OFF); + rtos_ecos_regoff_arm[11].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_FP_OFF); + rtos_ecos_regoff_arm[12].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_IP_OFF); + rtos_ecos_regoff_arm[13].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_SP_OFF); + rtos_ecos_regoff_arm[14].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_LR_OFF); + rtos_ecos_regoff_arm[15].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_PC_OFF); + rtos_ecos_regoff_arm[16].offset = ecos_value(rtos, ECOS_VAL_ARM_CTX_CPSR_OFF); + + param->stacking_info = &rtos_ecos_stacking; + } + + if (si) + *si = param->stacking_info; + + return retval; +} + +/* We see this function called on a new connection, it looks like before and + * after the "tar rem"/"tar extended-remote". It might be the only point we can + * decide to cache information (to check if the symbol table has changed). */ static int ecos_update_threads(struct rtos *rtos) { int retval; int tasks_found = 0; int thread_list_size = 0; - const struct ecos_params *param; + struct ecos_params *param; if (!rtos) return -1; + /* wipe out previous thread details if any */ + rtos_free_threadlist(rtos); + if (!rtos->rtos_specific_params) return -3; - param = (const struct ecos_params *) rtos->rtos_specific_params; + param = rtos->rtos_specific_params; if (!rtos->symbols) { + /* NOTE: We only see this when connecting from GDB the first + * time before the application image is loaded. So it is not a + * hook for detecting an application change. */ + param->flush_common = true; LOG_ERROR("No symbols for eCos"); return -4; } + retval = ecos_check_app_info(rtos, param); + if (retval != ERROR_OK) + return retval; + if (rtos->symbols[ECOS_VAL_THREAD_LIST].address == 0) { LOG_ERROR("Don't have the thread list head"); return -2; } - /* wipe out previous thread details if any */ - rtos_free_threadlist(rtos); - /* determine the number of current threads */ uint32_t thread_list_head = rtos->symbols[ECOS_VAL_THREAD_LIST].address; uint32_t thread_index; @@ -131,50 +746,82 @@ static int ecos_update_threads(struct rtos *rtos) param->pointer_width, (uint8_t *) &thread_index); uint32_t first_thread = thread_index; - do { - thread_list_size++; - retval = target_read_buffer(rtos->target, - thread_index + param->thread_next_offset, - param->pointer_width, - (uint8_t *) &thread_index); - if (retval != ERROR_OK) - return retval; - } while (thread_index != first_thread); + + /* Even if 0==first_thread indicates a system with no defined eCos + * threads, instead of early exiting here we fall through the code to + * allow the creation of a faked "Current Execution" descriptor as + * needed. */ + + if (first_thread) { + /* Since the OpenOCD RTOS support can attempt to obtain thread + * information on initial connection when the system *may* have + * undefined memory state it is possible for a simple thread count scan + * to produce invalid results. To avoid blocking indefinitely when + * encountering an invalid closed loop we limit the number of threads to + * the maximum possible, and if we pass that limit then something is + * wrong so treat the system as having no threads defined. */ + do { + thread_list_size++; + if (thread_list_size > ECOS_MAX_THREAD_COUNT) { + /* Treat as "no threads" case: */ + first_thread = 0; + thread_list_size = 0; + break; + } + retval = target_read_buffer(rtos->target, + thread_index + param->thread_next_offset, + param->pointer_width, + (uint8_t *)&thread_index); + if (retval != ERROR_OK) + return retval; + } while (thread_index != first_thread); + } /* read the current thread id */ + rtos->current_thread = 0; + uint32_t current_thread_addr; retval = target_read_buffer(rtos->target, rtos->symbols[ECOS_VAL_CURRENT_THREAD_PTR].address, - 4, + param->pointer_width, (uint8_t *)¤t_thread_addr); - if (retval != ERROR_OK) - return retval; - rtos->current_thread = 0; - retval = target_read_buffer(rtos->target, - current_thread_addr + param->thread_uniqueid_offset, - 2, - (uint8_t *)&rtos->current_thread); if (retval != ERROR_OK) { - LOG_ERROR("Could not read eCos current thread from target"); + LOG_ERROR("Reading active thread address"); return retval; } - if ((thread_list_size == 0) || (rtos->current_thread == 0)) { + if (current_thread_addr) { + uint16_t id = 0; + retval = target_read_buffer(rtos->target, + current_thread_addr + param->thread_uniqueid_offset, + param->uid_width, + (uint8_t *)&id); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read eCos current thread from target"); + return retval; + } + rtos->current_thread = (threadid_t)id; + } + + if (thread_list_size == 0 || rtos->current_thread == 0) { /* Either : No RTOS threads - there is always at least the current execution though */ /* OR : No current thread - all threads suspended - show the current execution * of idling */ - char tmp_str[] = "Current Execution"; + static const char tmp_str[] = "Current Execution"; thread_list_size++; tasks_found++; rtos->thread_details = malloc( sizeof(struct thread_detail) * thread_list_size); - rtos->thread_details->threadid = 1; + /* 1 is a valid eCos thread id, so we return 0 for this faked + * "current" CPU state: */ + rtos->thread_details->threadid = 0; rtos->thread_details->exists = true; rtos->thread_details->extra_info_str = NULL; rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str)); strcpy(rtos->thread_details->thread_name_str, tmp_str); - if (thread_list_size == 0) { + /* Early exit if current CPU state our only "thread": */ + if (thread_list_size == 1) { rtos->thread_count = 1; return ERROR_OK; } @@ -187,18 +834,18 @@ static int ecos_update_threads(struct rtos *rtos) /* loop over all threads */ thread_index = first_thread; do { - #define ECOS_THREAD_NAME_STR_SIZE (200) char tmp_str[ECOS_THREAD_NAME_STR_SIZE]; - unsigned int i = 0; uint32_t name_ptr = 0; uint32_t prev_thread_ptr; - /* Save the thread pointer */ - uint16_t thread_id; + /* Save the thread ID. For eCos the thread has a unique ID distinct from + * the thread_index descriptor pointer. We present this scheduler ID + * instead of the descriptor memory address. */ + uint16_t thread_id = 0; retval = target_read_buffer(rtos->target, thread_index + param->thread_uniqueid_offset, - 2, + param->uid_width, (uint8_t *)&thread_id); if (retval != ERROR_OK) { LOG_ERROR("Could not read eCos thread id from target"); @@ -206,7 +853,7 @@ static int ecos_update_threads(struct rtos *rtos) } rtos->thread_details[tasks_found].threadid = thread_id; - /* read the name pointer */ + /* Read the name pointer */ retval = target_read_buffer(rtos->target, thread_index + param->thread_name_offset, param->pointer_width, @@ -228,8 +875,26 @@ static int ecos_update_threads(struct rtos *rtos) } tmp_str[ECOS_THREAD_NAME_STR_SIZE-1] = '\x00'; - if (tmp_str[0] == '\x00') - strcpy(tmp_str, "No Name"); + /* Since eCos can have arbitrary C string names we can sometimes + * get an internal warning from GDB about "not well-formed + * (invalid token)" since the XML post-processing done by GDB on + * the OpenOCD returned response containing the thread strings + * is not escaped. For example the eCos kernel testsuite + * application tm_basic uses the thread name "<<NULL>>" which + * will trigger this failure unless escaped. */ + if (tmp_str[0] == '\x00') { + snprintf(tmp_str, ECOS_THREAD_NAME_STR_SIZE, "NoName:[0x%08" PRIX32 "]", thread_index); + } else { + /* The following is a workaround to avoid any issues + * from arbitrary eCos thread names causing GDB/OpenOCD + * issues. We limit the escaped thread name passed to + * GDB to the same length as the un-escaped just to + * avoid overly long strings. */ + char esc_str[ECOS_THREAD_NAME_STR_SIZE]; + bool escaped = ecos_escape_string(tmp_str, esc_str, sizeof(esc_str)); + if (escaped) + strcpy(tmp_str, esc_str); + } rtos->thread_details[tasks_found].thread_name_str = malloc(strlen(tmp_str)+1); @@ -239,28 +904,109 @@ static int ecos_update_threads(struct rtos *rtos) int64_t thread_status = 0; retval = target_read_buffer(rtos->target, thread_index + param->thread_state_offset, - 4, + param->state_width, (uint8_t *)&thread_status); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread state from eCos target"); return retval; } - for (i = 0; (i < ECOS_NUM_STATES) && (ecos_thread_states[i].value != thread_status); i++) { - /* - * empty - */ - } + /* The thread_status is a BITMASK */ + char state_desc[21]; /* Enough for "suspended+countsleep\0" maximum */ - const char *state_desc; - if (i < ECOS_NUM_STATES) - state_desc = ecos_thread_states[i].desc; + if (thread_status & SUSPENDED) + strcpy(state_desc, "suspended+"); else - state_desc = "Unknown state"; + state_desc[0] = '\0'; + + switch (thread_status & ~SUSPENDED) { + case RUNNING: + if (thread_index == current_thread_addr) + strcat(state_desc, "running"); + else if (thread_status & SUSPENDED) + state_desc[9] = '\0'; /* Drop '+' from "suspended+" */ + else + strcat(state_desc, "ready"); + break; + case SLEEPING: + strcat(state_desc, "sleeping"); + break; + case SLEEPSET: + case COUNTSLEEP: + strcat(state_desc, "counted sleep"); + break; + case CREATING: + strcpy(state_desc, "creating"); + break; + case EXITED: + strcpy(state_desc, "exited"); + break; + default: + strcpy(state_desc, "unknown state"); + break; + } + + /* For the moment we do not bother decoding the wake reason for the + * active "running" thread, but it is useful providing the sleep reason + * for stacked threads. */ + int64_t sleep_reason = 0; /* sleep reason */ + + if (thread_index != current_thread_addr && + ecos_value(rtos, ECOS_VAL_COMMON_THREAD_SLEEP_SIZE)) { + retval = target_read_buffer(rtos->target, + (thread_index + ecos_value(rtos, ECOS_VAL_COMMON_THREAD_SLEEP_OFF)), + ecos_value(rtos, ECOS_VAL_COMMON_THREAD_SLEEP_SIZE), + (uint8_t *)&sleep_reason); + if (retval != ERROR_OK) { + LOG_ERROR("Error reading thread sleep reason from eCos target"); + return retval; + } + if (sleep_reason < 0 || + sleep_reason > (int64_t)ARRAY_SIZE(ecos_thread_reasons)) { + sleep_reason = 0; + } + } + + /* We do not display anything for the Cyg_Thread::NONE reason */ + size_t tr_extra = 0; + const char *reason_desc = NULL; + if (sleep_reason) + reason_desc = ecos_thread_reasons[sleep_reason].desc; + if (reason_desc) + tr_extra = 2 + strlen(reason_desc) + 1; + + /* Display thread priority if available: */ + int64_t priority = 0; + size_t pri_extra = 0; + if (ecos_value(rtos, ECOS_VAL_COMMON_THREAD_PRI_SIZE)) { + retval = target_read_buffer(rtos->target, + (thread_index + ecos_value(rtos, ECOS_VAL_COMMON_THREAD_PRI_OFF)), + ecos_value(rtos, ECOS_VAL_COMMON_THREAD_PRI_SIZE), + (uint8_t *)&priority); + if (retval != ERROR_OK) { + LOG_ERROR("Error reading thread priority from eCos target"); + return retval; + } + pri_extra = (12 + 20); /* worst-case ", Priority: " */ + } + + size_t eilen = (8 + strlen(state_desc) + tr_extra + pri_extra); + char *eistr = malloc(eilen); + /* We do not need to treat a malloc failure as a fatal error here since + * the code below will just not report extra thread information if NULL, + * thus allowing all of the threads to be enumerated even with reduced + * information when the host is low on memory. However... */ + if (!eistr) { + LOG_ERROR("OOM allocating extra information buffer"); + return ERROR_FAIL; + } - rtos->thread_details[tasks_found].extra_info_str = malloc(strlen( - state_desc)+8); - sprintf(rtos->thread_details[tasks_found].extra_info_str, "State: %s", state_desc); + int soff = snprintf(eistr, eilen, "State: %s", state_desc); + if (tr_extra && reason_desc) + soff += snprintf(&eistr[soff], (eilen - soff), " (%s)", reason_desc); + if (pri_extra) + (void)snprintf(&eistr[soff], (eilen - soff), ", Priority: %" PRId64 "", priority); + rtos->thread_details[tasks_found].extra_info_str = eistr; rtos->thread_details[tasks_found].exists = true; @@ -280,14 +1026,14 @@ static int ecos_update_threads(struct rtos *rtos) } while (thread_index != first_thread); rtos->thread_count = tasks_found; - return 0; + return ERROR_OK; } static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { int retval; - const struct ecos_params *param; + struct ecos_params *param; if (!rtos) return -1; @@ -298,7 +1044,22 @@ static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, if (!rtos->rtos_specific_params) return -3; - param = (const struct ecos_params *) rtos->rtos_specific_params; + param = rtos->rtos_specific_params; + + retval = ecos_check_app_info(rtos, param); + if (retval != ERROR_OK) + return retval; + + /* We can get memory access errors reported by this function on + * re-connecting to a board with stale thread information in memory. The + * initial ecos_update_threads() is called twice and may read + * stale/invalid information depending on the memory state. This happens + * as part of the "target remote" connection so cannot be avoided by GDB + * scripting. It is not critical and allowing the application to run and + * initialise its BSS etc. will allow correct thread and register + * information to be obtained. This really only affects debug sessions + * where "info thr" is used before the initial run-time initialisation + * has occurred. */ /* Find the thread with that thread id */ uint16_t id = 0; @@ -310,10 +1071,10 @@ static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, while (!done) { retval = target_read_buffer(rtos->target, thread_index + param->thread_uniqueid_offset, - 2, + param->uid_width, (uint8_t *)&id); if (retval != ERROR_OK) { - LOG_ERROR("Error reading unique id from eCos thread"); + LOG_ERROR("Error reading unique id from eCos thread 0x%08" PRIX32 "", thread_index); return retval; } @@ -339,8 +1100,24 @@ static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, return retval; } + if (!stack_ptr) { + LOG_ERROR("NULL stack pointer in thread %" PRIu64, thread_id); + return -5; + } + + const struct rtos_register_stacking *stacking_info = NULL; + if (param->target_stack_layout) { + retval = param->target_stack_layout(rtos, param, stack_ptr, &stacking_info); + if (retval != ERROR_OK) { + LOG_ERROR("Error reading stack layout for eCos thread"); + return retval; + } + } + if (!stacking_info) + stacking_info = &rtos_ecos_cortex_m3_stacking; + return rtos_generic_stack_read(rtos->target, - param->stacking_info, + stacking_info, stack_ptr, reg_list, num_regs); @@ -349,18 +1126,31 @@ static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, return -1; } +/* NOTE: This is only called once when the first GDB connection is made to + * OpenOCD and not on subsequent connections (when the application symbol table + * may have changed, affecting the offsets of critical fields and the stacked + * context shape). */ static int ecos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) { unsigned int i; *symbol_list = calloc( ARRAY_SIZE(ecos_symbol_list), sizeof(struct symbol_table_elem)); - for (i = 0; i < ARRAY_SIZE(ecos_symbol_list); i++) - (*symbol_list)[i].symbol_name = ecos_symbol_list[i]; + /* If the target reference was passed into this function we could limit + * the symbols we need to lookup to the target->type->name based + * range. For the moment we need to provide a single vector with all of + * the symbols across all of the supported architectures. */ + for (i = 0; i < ARRAY_SIZE(ecos_symbol_list); i++) { + (*symbol_list)[i].symbol_name = ecos_symbol_list[i].name; + (*symbol_list)[i].optional = ecos_symbol_list[i].optional; + } return 0; } +/* NOTE: Only called by rtos.c:rtos_qsymbol() when auto-detecting the RTOS. If + * the target configuration uses the explicit "-rtos" config option then this + * detection routine is NOT called. */ static bool ecos_detect_rtos(struct target *target) { if ((target->rtos->symbols) && @@ -371,15 +1161,64 @@ static bool ecos_detect_rtos(struct target *target) return false; } +/* Since we should never have 0 as a valid eCos thread ID we use $Hg0 as the + * indicator of a new session as regards flushing any cached state. */ +static int ecos_packet_hook(struct connection *connection, + const char *packet, int packet_size) +{ + int64_t current_threadid; + + if (packet[0] == 'H' && packet[1] == 'g') { + int numscan = sscanf(packet, "Hg%16" SCNx64, ¤t_threadid); + if (numscan == 1 && current_threadid == 0) { + struct target *target = get_target_from_connection(connection); + if (target && target->rtos && target->rtos->rtos_specific_params) { + struct ecos_params *param; + param = target->rtos->rtos_specific_params; + param->flush_common = true; + } + } + } + + return rtos_thread_packet(connection, packet, packet_size); +} + +/* Called at start of day when eCos detected or specified in config file. */ static int ecos_create(struct target *target) { - for (unsigned int i = 0; i < ARRAY_SIZE(ecos_params_list); i++) - if (strcmp(ecos_params_list[i].target_name, target->type->name) == 0) { - target->rtos->rtos_specific_params = (void *)&ecos_params_list[i]; - target->rtos->current_thread = 0; - target->rtos->thread_details = NULL; - return 0; + for (unsigned int i = 0; i < ARRAY_SIZE(ecos_params_list); i++) { + const char * const *tnames = ecos_params_list[i].target_names; + while (*tnames) { + if (strcmp(*tnames, target->type->name) == 0) { + /* LOG_DEBUG("eCos: matched target \"%s\"", target->type->name); */ + target->rtos->rtos_specific_params = (void *)&ecos_params_list[i]; + ecos_params_list[i].flush_common = true; + ecos_params_list[i].stacking_info = NULL; + target->rtos->current_thread = 0; + target->rtos->thread_details = NULL; + + /* We use the $Hg0 packet as a new GDB connection "start-of-day" hook to + * force a re-cache of information. It is possible for a single OpenOCD + * session to be connected to a target with multiple GDB debug sessions + * started/stopped. With eCos it is possible for those GDB sessions to + * present applications with different offsets within a thread + * descriptor for fields used by this module, and for the stacked + * context within the connected target architecture to differ between + * applications and even between threads in a single application. So we + * need to ensure any information we cache is flushed on an application + * change, and GDB referencing an invalid eCos thread ID (0) is a good + * enough point, since we can accept the re-cache hit if that packet + * appears during an established session, whilst benefiting from not + * re-loading information on every update_threads or get_thread_reg_list + * call. */ + target->rtos->gdb_thread_packet = ecos_packet_hook; + /* We do not currently use the target->rtos->gdb_target_for_threadid + * hook. */ + return 0; + } + tnames++; } + } LOG_ERROR("Could not find target in eCos compatibility list"); return -1; diff --git a/src/rtos/embKernel.c b/src/rtos/embKernel.c index d70ae37d94..a03b039e0c 100644 --- a/src/rtos/embKernel.c +++ b/src/rtos/embKernel.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -38,7 +27,7 @@ static int embkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int embkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]); -struct rtos_type embkernel_rtos = { +const struct rtos_type embkernel_rtos = { .name = "embKernel", .detect_rtos = embkernel_detect_rtos, .create = embkernel_create, diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c index b7d5c5f58e..763a97da05 100644 --- a/src/rtos/hwthread.c +++ b/src/rtos/hwthread.c @@ -1,18 +1,4 @@ -/*************************************************************************** - * * - * 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/>. * - ***************************************************************************/ +// SPDX-License-Identifier: GPL-2.0-or-later #ifdef HAVE_CONFIG_H #include "config.h" @@ -49,8 +35,6 @@ struct target *hwthread_swbp_target(struct rtos *rtos, target_addr_t address, #define HW_THREAD_NAME_STR_SIZE (32) -extern int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size); - static inline threadid_t threadid_from_target(const struct target *target) { return target->coreid + 1; @@ -101,6 +85,7 @@ static int hwthread_update_threads(struct rtos *rtos) struct target_list *head; struct target *target; int64_t current_thread = 0; + int64_t current_threadid = rtos->current_threadid; /* thread selected by GDB */ enum target_debug_reason current_reason = DBG_REASON_UNDEFINED; if (!rtos) @@ -108,12 +93,16 @@ static int hwthread_update_threads(struct rtos *rtos) target = rtos->target; + /* wipe out previous thread details if any */ + rtos_free_threadlist(rtos); + /* determine the number of "threads" */ if (target->smp) { foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; - if (!target_was_examined(curr)) + if (!target_was_examined(curr) || + curr->state == TARGET_UNAVAILABLE) continue; ++thread_list_size; @@ -121,10 +110,14 @@ static int hwthread_update_threads(struct rtos *rtos) } else thread_list_size = 1; - /* Wipe out previous thread details if any, but preserve threadid. */ - int64_t current_threadid = rtos->current_threadid; - rtos_free_threadlist(rtos); - rtos->current_threadid = current_threadid; + /* restore the threadid which is currently selected by GDB + * because rtos_free_threadlist() wipes out it + * (GDB thread id is 1-based indexing) */ + if (current_threadid <= thread_list_size) + rtos->current_threadid = current_threadid; + else + LOG_WARNING("SMP node change, disconnect GDB from core/thread %" PRId64, + current_threadid); /* create space for new thread details */ rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size); @@ -134,7 +127,8 @@ static int hwthread_update_threads(struct rtos *rtos) foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; - if (!target_was_examined(curr)) + if (!target_was_examined(curr) || + curr->state == TARGET_UNAVAILABLE) continue; threadid_t tid = threadid_from_target(curr); @@ -211,7 +205,7 @@ static int hwthread_update_threads(struct rtos *rtos) else rtos->current_thread = threadid_from_target(target); - LOG_DEBUG("%s current_thread=%i", __func__, (int)rtos->current_thread); + LOG_DEBUG("current_thread=%i, threads_found=%d", (int)rtos->current_thread, threads_found); return 0; } @@ -276,10 +270,19 @@ static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, for (int i = 0; i < reg_list_size; i++) { if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden) continue; - (*rtos_reg_list)[j].number = (*reg_list)[i].number; - (*rtos_reg_list)[j].size = (*reg_list)[i].size; - memcpy((*rtos_reg_list)[j].value, (*reg_list)[i].value, - ((*reg_list)[i].size + 7) / 8); + if (!reg_list[i]->valid) { + retval = reg_list[i]->type->get(reg_list[i]); + if (retval != ERROR_OK) { + LOG_ERROR("Couldn't get register %s.", reg_list[i]->name); + free(reg_list); + free(*rtos_reg_list); + return retval; + } + } + (*rtos_reg_list)[j].number = reg_list[i]->number; + (*rtos_reg_list)[j].size = reg_list[i]->size; + memcpy((*rtos_reg_list)[j].value, reg_list[i]->value, + DIV_ROUND_UP(reg_list[i]->size, 8)); j++; } free(reg_list); diff --git a/src/rtos/linux.c b/src/rtos/linux.c index d147c1cf0e..7517ec7a9a 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by STEricsson * * Heythem Bouhaja heythem.bouhaja@stericsson.com : creation * * Michel JAOUEN michel.jaouen@stericsson.com : adaptation to rtos * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -134,7 +123,7 @@ static int linux_read_memory(struct target *target, target->rtos->rtos_specific_params; uint32_t pa = (address & linux_os->phys_mask) + linux_os->phys_base; #endif - if (address < 0xc000000) { + if (address < 0xc0000000) { LOG_ERROR("linux awareness : address in user space"); return ERROR_FAIL; } diff --git a/src/rtos/linux_header.h b/src/rtos/linux_header.h index a2b408efd0..79199643c9 100644 --- a/src/rtos/linux_header.h +++ b/src/rtos/linux_header.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + #ifndef OPENOCD_RTOS_LINUX_HEADER_H #define OPENOCD_RTOS_LINUX_HEADER_H diff --git a/src/rtos/mqx.c b/src/rtos/mqx.c index 754470e3c6..d9b694282a 100644 --- a/src/rtos/mqx.c +++ b/src/rtos/mqx.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2014 by Marian Cingel * * cingel.marian@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -509,7 +498,7 @@ static int mqx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[] return ERROR_OK; } -struct rtos_type mqx_rtos = { +const struct rtos_type mqx_rtos = { .name = "mqx", .detect_rtos = mqx_detect_rtos, .create = mqx_create, diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c index f0b3048616..0616af0f4c 100644 --- a/src/rtos/nuttx.c +++ b/src/rtos/nuttx.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright 2016,2017 Sony Video & Sound Products Inc. * * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com * * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -29,53 +18,60 @@ #include "rtos.h" #include "helper/log.h" #include "helper/types.h" -#include "server/gdb_server.h" - -#include "nuttx_header.h" - - -int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size); +#include "target/register.h" +#include "rtos_nuttx_stackings.h" -#ifdef CONFIG_DISABLE_SIGNALS -#define SIG_QUEUE_NUM 0 -#else -#define SIG_QUEUE_NUM 1 -#endif /* CONFIG_DISABLE_SIGNALS */ - -#ifdef CONFIG_DISABLE_MQUEUE -#define M_QUEUE_NUM 0 -#else -#define M_QUEUE_NUM 2 -#endif /* CONFIG_DISABLE_MQUEUE */ - -#ifdef CONFIG_PAGING -#define PAGING_QUEUE_NUM 1 -#else -#define PAGING_QUEUE_NUM 0 -#endif /* CONFIG_PAGING */ +#define NAME_SIZE 32 +#define EXTRAINFO_SIZE 256 +/* Only 32-bit CPUs are supported by the current implementation. Supporting + * other CPUs will require reading this information from the target and + * adapting the code accordingly. + */ +#define PTR_WIDTH 4 -#define TASK_QUEUE_NUM (6 + SIG_QUEUE_NUM + M_QUEUE_NUM + PAGING_QUEUE_NUM) +struct nuttx_params { + const char *target_name; + const struct rtos_register_stacking *stacking; + const struct rtos_register_stacking *(*select_stackinfo)(struct target *target); +}; +/* + * struct tcbinfo_s is located in the sched.h + * https://github.com/apache/nuttx/blob/master/include/nuttx/sched.h + */ +#define TCBINFO_TARGET_SIZE 22 +struct tcbinfo { + uint16_t pid_off; /* Offset of tcb.pid */ + uint16_t state_off; /* Offset of tcb.task_state */ + uint16_t pri_off; /* Offset of tcb.sched_priority */ + uint16_t name_off; /* Offset of tcb.name */ + uint16_t regs_off; /* Offset of tcb.regs */ + uint16_t basic_num; /* Num of genernal regs */ + uint16_t total_num; /* Num of regs in tcbinfo.reg_offs */ + target_addr_t xcpreg_off; /* Offset pointer of xcp.regs */ +}; -/* see nuttx/sched/os_start.c */ -static char *nuttx_symbol_list[] = { - "g_readytorun", /* 0: must be top of this array */ - "g_tasklisttable", - NULL +struct symbols { + const char *name; + bool optional; }; -/* see nuttx/include/nuttx/sched.h */ -struct tcb { - uint32_t flink; - uint32_t blink; - uint8_t dat[512]; +/* Used to index the list of retrieved symbols. See nuttx_symbol_list for the order. */ +enum nuttx_symbol_vals { + NX_SYM_READYTORUN = 0, + NX_SYM_PIDHASH, + NX_SYM_NPIDHASH, + NX_SYM_TCB_INFO, }; -static struct { - uint32_t addr; - uint32_t prio; -} g_tasklist[TASK_QUEUE_NUM]; +static const struct symbols nuttx_symbol_list[] = { + { "g_readytorun", false }, + { "g_pidhash", false }, + { "g_npidhash", false }, + { "g_tcbinfo", false }, + { NULL, false } +}; static char *task_state_str[] = { "INVALID", @@ -84,317 +80,363 @@ static char *task_state_str[] = { "RUNNING", "INACTIVE", "WAIT_SEM", -#ifndef CONFIG_DISABLE_SIGNALS "WAIT_SIG", -#endif /* CONFIG_DISABLE_SIGNALS */ -#ifndef CONFIG_DISABLE_MQUEUE "WAIT_MQNOTEMPTY", "WAIT_MQNOTFULL", -#endif /* CONFIG_DISABLE_MQUEUE */ -#ifdef CONFIG_PAGING "WAIT_PAGEFILL", -#endif /* CONFIG_PAGING */ + "STOPPED", }; -/* see arch/arm/include/armv7-m/irq_cmnvector.h */ -static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = { - { ARMV7M_R0, 0x28, 32 }, /* r0 */ - { ARMV7M_R1, 0x2c, 32 }, /* r1 */ - { ARMV7M_R2, 0x30, 32 }, /* r2 */ - { ARMV7M_R3, 0x34, 32 }, /* r3 */ - { ARMV7M_R4, 0x08, 32 }, /* r4 */ - { ARMV7M_R5, 0x0c, 32 }, /* r5 */ - { ARMV7M_R6, 0x10, 32 }, /* r6 */ - { ARMV7M_R7, 0x14, 32 }, /* r7 */ - { ARMV7M_R8, 0x18, 32 }, /* r8 */ - { ARMV7M_R9, 0x1c, 32 }, /* r9 */ - { ARMV7M_R10, 0x20, 32 }, /* r10 */ - { ARMV7M_R11, 0x24, 32 }, /* r11 */ - { ARMV7M_R12, 0x38, 32 }, /* r12 */ - { ARMV7M_R13, 0, 32 }, /* sp */ - { ARMV7M_R14, 0x3c, 32 }, /* lr */ - { ARMV7M_PC, 0x40, 32 }, /* pc */ - { ARMV7M_xPSR, 0x44, 32 }, /* xPSR */ +static const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target); + +static const struct nuttx_params nuttx_params_list[] = { + { + .target_name = "cortex_m", + .stacking = NULL, + .select_stackinfo = cortexm_select_stackinfo, + }, + { + .target_name = "hla_target", + .stacking = NULL, + .select_stackinfo = cortexm_select_stackinfo, + }, + { + .target_name = "esp32", + .stacking = &nuttx_esp32_stacking, + }, + { + .target_name = "esp32s2", + .stacking = &nuttx_esp32s2_stacking, + }, + { + .target_name = "esp32s3", + .stacking = &nuttx_esp32s3_stacking, + }, + { + .target_name = "esp32c3", + .stacking = &nuttx_riscv_stacking, + }, }; +static bool cortexm_hasfpu(struct target *target) +{ + uint32_t cpacr; + struct armv7m_common *armv7m_target = target_to_armv7m(target); -static const struct rtos_register_stacking nuttx_stacking_cortex_m = { - .stack_registers_size = 0x48, - .stack_growth_direction = -1, - .num_output_registers = 17, - .register_offsets = nuttx_stack_offsets_cortex_m -}; - -static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = { - { ARMV7M_R0, 0x6c, 32 }, /* r0 */ - { ARMV7M_R1, 0x70, 32 }, /* r1 */ - { ARMV7M_R2, 0x74, 32 }, /* r2 */ - { ARMV7M_R3, 0x78, 32 }, /* r3 */ - { ARMV7M_R4, 0x08, 32 }, /* r4 */ - { ARMV7M_R5, 0x0c, 32 }, /* r5 */ - { ARMV7M_R6, 0x10, 32 }, /* r6 */ - { ARMV7M_R7, 0x14, 32 }, /* r7 */ - { ARMV7M_R8, 0x18, 32 }, /* r8 */ - { ARMV7M_R9, 0x1c, 32 }, /* r9 */ - { ARMV7M_R10, 0x20, 32 }, /* r10 */ - { ARMV7M_R11, 0x24, 32 }, /* r11 */ - { ARMV7M_R12, 0x7c, 32 }, /* r12 */ - { ARMV7M_R13, 0, 32 }, /* sp */ - { ARMV7M_R14, 0x80, 32 }, /* lr */ - { ARMV7M_PC, 0x84, 32 }, /* pc */ - { ARMV7M_xPSR, 0x88, 32 }, /* xPSR */ -}; + if (!is_armv7m(armv7m_target) || armv7m_target->fp_feature == FP_NONE) + return false; -static const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = { - .stack_registers_size = 0x8c, - .stack_growth_direction = -1, - .num_output_registers = 17, - .register_offsets = nuttx_stack_offsets_cortex_m_fpu -}; + int retval = target_read_u32(target, FPU_CPACR, &cpacr); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read CPACR register to check FPU state"); + return false; + } -static int pid_offset = PID; -static int state_offset = STATE; -static int name_offset = NAME; -static int xcpreg_offset = XCPREG; -static int name_size = NAME_SIZE; + return cpacr & 0x00F00000; +} -static int rcmd_offset(const char *cmd, const char *name) +static const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target) { - if (strncmp(cmd, name, strlen(name))) - return -1; - - if (strlen(cmd) <= strlen(name) + 1) - return -1; - - return atoi(cmd + strlen(name)); + return cortexm_hasfpu(target) ? &nuttx_stacking_cortex_m_fpu : &nuttx_stacking_cortex_m; } -static int nuttx_thread_packet(struct connection *connection, - char const *packet, int packet_size) +static bool nuttx_detect_rtos(struct target *target) { - char cmd[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for null-termination */ - - if (!strncmp(packet, "qRcmd", 5)) { - size_t len = unhexify((uint8_t *)cmd, packet + 6, sizeof(cmd)); - int offset; - - if (len <= 0) - goto pass; - - offset = rcmd_offset(cmd, "nuttx.pid_offset"); - - if (offset >= 0) { - LOG_INFO("pid_offset: %d", offset); - pid_offset = offset; - goto retok; - } - - offset = rcmd_offset(cmd, "nuttx.state_offset"); - - if (offset >= 0) { - LOG_INFO("state_offset: %d", offset); - state_offset = offset; - goto retok; - } + if (target->rtos->symbols && + target->rtos->symbols[NX_SYM_READYTORUN].address != 0 && + target->rtos->symbols[NX_SYM_PIDHASH].address != 0) + return true; + return false; +} - offset = rcmd_offset(cmd, "nuttx.name_offset"); +static int nuttx_create(struct target *target) +{ + const struct nuttx_params *param; + unsigned int i; - if (offset >= 0) { - LOG_INFO("name_offset: %d", offset); - name_offset = offset; - goto retok; + for (i = 0; i < ARRAY_SIZE(nuttx_params_list); i++) { + param = &nuttx_params_list[i]; + if (strcmp(target_type_name(target), param->target_name) == 0) { + LOG_INFO("Detected target \"%s\"", param->target_name); + break; } + } - offset = rcmd_offset(cmd, "nuttx.xcpreg_offset"); - - if (offset >= 0) { - LOG_INFO("xcpreg_offset: %d", offset); - xcpreg_offset = offset; - goto retok; - } + if (i >= ARRAY_SIZE(nuttx_params_list)) { + LOG_ERROR("Could not find \"%s\" target in NuttX compatibility list", target_type_name(target)); + return JIM_ERR; + } - offset = rcmd_offset(cmd, "nuttx.name_size"); + /* We found a target in our list, copy its reference. */ + target->rtos->rtos_specific_params = (void *)param; - if (offset >= 0) { - LOG_INFO("name_size: %d", offset); - name_size = offset; - goto retok; - } - } -pass: - return rtos_thread_packet(connection, packet, packet_size); -retok: - gdb_put_packet(connection, "OK", 2); - return ERROR_OK; + return JIM_OK; } - -static bool nuttx_detect_rtos(struct target *target) +static int nuttx_smp_init(struct target *target) { - if ((target->rtos->symbols) && - (target->rtos->symbols[0].address != 0) && - (target->rtos->symbols[1].address != 0)) { - return true; - } - return false; + /* Return OK for now so that the initialisation sequence doesn't stop. + * SMP case will be implemented later. */ + return ERROR_OK; } -static int nuttx_create(struct target *target) +static target_addr_t target_buffer_get_addr(struct target *target, const uint8_t *buffer) { - - target->rtos->gdb_thread_packet = nuttx_thread_packet; - LOG_INFO("target type name = %s", target->type->name); - return 0; +#if PTR_WIDTH == 8 + return target_buffer_get_u64(target, buffer); +#else + return target_buffer_get_u32(target, buffer); +#endif } static int nuttx_update_threads(struct rtos *rtos) { - uint32_t thread_count; - struct tcb tcb; - int ret; - uint32_t head; - uint32_t tcb_addr; - uint32_t i; + struct tcbinfo tcbinfo; + uint32_t pidhashaddr, npidhash, tcbaddr; + uint16_t pid; uint8_t state; if (!rtos->symbols) { - LOG_ERROR("No symbols for NuttX"); - return -3; + LOG_ERROR("No symbols for nuttx"); + return ERROR_FAIL; } - /* free previous thread details */ + /* Free previous thread details */ rtos_free_threadlist(rtos); - ret = target_read_buffer(rtos->target, rtos->symbols[1].address, - sizeof(g_tasklist), (uint8_t *)&g_tasklist); - if (ret) { - LOG_ERROR("target_read_buffer : ret = %d\n", ret); + /* NuttX provides a hash table that keeps track of all the TCBs. + * We first read its size from g_npidhash and its address from g_pidhash. + * Its content is then read from these values. + */ + int ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_NPIDHASH].address, &npidhash); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read g_npidhash: ret = %d", ret); + return ERROR_FAIL; + } + + LOG_DEBUG("Hash table size (g_npidhash) = %" PRId32, npidhash); + + ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_PIDHASH].address, &pidhashaddr); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read g_pidhash address: ret = %d", ret); return ERROR_FAIL; } - thread_count = 0; + LOG_DEBUG("Hash table address (g_pidhash) = %" PRIx32, pidhashaddr); + + uint8_t *pidhash = malloc(npidhash * PTR_WIDTH); + if (!pidhash) { + LOG_ERROR("Failed to allocate pidhash"); + return ERROR_FAIL; + } - for (i = 0; i < TASK_QUEUE_NUM; i++) { + ret = target_read_buffer(rtos->target, pidhashaddr, PTR_WIDTH * npidhash, pidhash); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read tcbhash: ret = %d", ret); + goto errout; + } - if (g_tasklist[i].addr == 0) + /* NuttX provides a struct that contains TCB offsets for required members. + * Read its content from g_tcbinfo. + */ + uint8_t buff[TCBINFO_TARGET_SIZE]; + ret = target_read_buffer(rtos->target, rtos->symbols[NX_SYM_TCB_INFO].address, sizeof(buff), buff); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read tcbinfo: ret = %d", ret); + goto errout; + } + tcbinfo.pid_off = target_buffer_get_u16(rtos->target, buff); + tcbinfo.state_off = target_buffer_get_u16(rtos->target, buff + 2); + tcbinfo.pri_off = target_buffer_get_u16(rtos->target, buff + 4); + tcbinfo.name_off = target_buffer_get_u16(rtos->target, buff + 6); + tcbinfo.regs_off = target_buffer_get_u16(rtos->target, buff + 8); + tcbinfo.basic_num = target_buffer_get_u16(rtos->target, buff + 10); + tcbinfo.total_num = target_buffer_get_u16(rtos->target, buff + 12); + tcbinfo.xcpreg_off = target_buffer_get_addr(rtos->target, buff + 14); + + /* The head of the g_readytorun list is the currently running task. + * Reading in a temporary variable first to avoid endianness issues, + * rtos->current_thread is int64_t. */ + uint32_t current_thread; + ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_READYTORUN].address, ¤t_thread); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read g_readytorun: ret = %d", ret); + goto errout; + } + rtos->current_thread = current_thread; + + uint32_t thread_count = 0; + + for (unsigned int i = 0; i < npidhash; i++) { + tcbaddr = target_buffer_get_u32(rtos->target, &pidhash[i * PTR_WIDTH]); + + if (!tcbaddr) continue; - ret = target_read_u32(rtos->target, g_tasklist[i].addr, - &head); + ret = target_read_u16(rtos->target, tcbaddr + tcbinfo.pid_off, &pid); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read PID of TCB@0x%x from pidhash[%d]: ret = %d", + tcbaddr, i, ret); + goto errout; + } - if (ret) { - LOG_ERROR("target_read_u32 : ret = %d\n", ret); - return ERROR_FAIL; + ret = target_read_u8(rtos->target, tcbaddr + tcbinfo.state_off, &state); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read state of TCB@0x%x from pidhash[%d]: ret = %d", + tcbaddr, i, ret); + goto errout; } - /* readytorun head is current thread */ - if (g_tasklist[i].addr == rtos->symbols[0].address) - rtos->current_thread = head; + struct thread_detail *new_thread_details = realloc(rtos->thread_details, + sizeof(struct thread_detail) * (thread_count + 1)); + if (!new_thread_details) { + ret = ERROR_FAIL; + goto errout; + } + struct thread_detail *thread = &new_thread_details[thread_count]; + thread->threadid = tcbaddr; + thread->exists = true; + thread->extra_info_str = NULL; - tcb_addr = head; - while (tcb_addr) { - struct thread_detail *thread; - ret = target_read_buffer(rtos->target, tcb_addr, - sizeof(tcb), (uint8_t *)&tcb); - if (ret) { - LOG_ERROR("target_read_buffer : ret = %d\n", - ret); - return ERROR_FAIL; - } - thread_count++; - - rtos->thread_details = realloc(rtos->thread_details, - sizeof(struct thread_detail) * thread_count); - thread = &rtos->thread_details[thread_count - 1]; - thread->threadid = tcb_addr; - thread->exists = true; - - state = tcb.dat[state_offset - 8]; - thread->extra_info_str = NULL; - if (state < ARRAY_SIZE(task_state_str)) { - thread->extra_info_str = malloc(256); - snprintf(thread->extra_info_str, 256, "pid:%d, %s", - tcb.dat[pid_offset - 8] | - tcb.dat[pid_offset - 8 + 1] << 8, - task_state_str[state]); - } + rtos->thread_details = new_thread_details; + thread_count++; - if (name_offset) { - thread->thread_name_str = malloc(name_size + 1); - snprintf(thread->thread_name_str, name_size, - "%s", (char *)&tcb.dat[name_offset - 8]); - } else { - thread->thread_name_str = malloc(sizeof("None")); - strcpy(thread->thread_name_str, "None"); + if (state < ARRAY_SIZE(task_state_str)) { + thread->extra_info_str = malloc(EXTRAINFO_SIZE); + if (!thread->extra_info_str) { + ret = ERROR_FAIL; + goto errout; } + snprintf(thread->extra_info_str, EXTRAINFO_SIZE, "pid:%d, %s", + pid, + task_state_str[state]); + } - tcb_addr = tcb.flink; + if (tcbinfo.name_off) { + thread->thread_name_str = calloc(NAME_SIZE + 1, sizeof(char)); + if (!thread->thread_name_str) { + ret = ERROR_FAIL; + goto errout; + } + ret = target_read_buffer(rtos->target, tcbaddr + tcbinfo.name_off, + sizeof(char) * NAME_SIZE, (uint8_t *)thread->thread_name_str); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read thread's name: ret = %d", ret); + goto errout; + } + } else { + thread->thread_name_str = strdup("None"); } } - rtos->thread_count = thread_count; - return 0; + ret = ERROR_OK; + rtos->thread_count = thread_count; +errout: + free(pidhash); + return ret; } - -/* - * thread_id = tcb address; - */ -static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, +static int nuttx_getreg_current_thread(struct rtos *rtos, struct rtos_reg **reg_list, int *num_regs) { - int retval; - - /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */ - bool cm4_fpu_enabled = false; - struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); - if (is_armv7m(armv7m_target)) { - if (armv7m_target->fp_feature == FPV4_SP) { - /* Found ARM v7m target which includes a FPU */ - uint32_t cpacr; - - retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr); - if (retval != ERROR_OK) { - LOG_ERROR("Could not read CPACR register to check FPU state"); - return -1; - } + struct reg **gdb_reg_list; + + /* Registers for currently running thread are not on task's stack and + * should be retrieved from reg caches via target_get_gdb_reg_list */ + int ret = target_get_gdb_reg_list(rtos->target, &gdb_reg_list, num_regs, + REG_CLASS_GENERAL); + if (ret != ERROR_OK) { + LOG_ERROR("target_get_gdb_reg_list failed %d", ret); + return ret; + } - /* Check if CP10 and CP11 are set to full access. */ - if (cpacr & 0x00F00000) { - /* Found target with enabled FPU */ - cm4_fpu_enabled = 1; - } + *reg_list = calloc(*num_regs, sizeof(struct rtos_reg)); + if (!(*reg_list)) { + LOG_ERROR("Failed to alloc memory for %d", *num_regs); + free(gdb_reg_list); + return ERROR_FAIL; + } + + for (int i = 0; i < *num_regs; i++) { + (*reg_list)[i].number = gdb_reg_list[i]->number; + (*reg_list)[i].size = gdb_reg_list[i]->size; + memcpy((*reg_list)[i].value, gdb_reg_list[i]->value, ((*reg_list)[i].size + 7) / 8); + } + + free(gdb_reg_list); + + return ERROR_OK; +} + +static int nuttx_getregs_fromstack(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs) +{ + uint16_t xcpreg_off; + uint32_t regsaddr; + const struct nuttx_params *priv = rtos->rtos_specific_params; + const struct rtos_register_stacking *stacking = priv->stacking; + + if (!stacking) { + if (priv->select_stackinfo) { + stacking = priv->select_stackinfo(rtos->target); + } else { + LOG_ERROR("Can't find a way to get stacking info"); + return ERROR_FAIL; } } - const struct rtos_register_stacking *stacking; - if (cm4_fpu_enabled) - stacking = &nuttx_stacking_cortex_m_fpu; - else - stacking = &nuttx_stacking_cortex_m; + int ret = target_read_u16(rtos->target, + rtos->symbols[NX_SYM_TCB_INFO].address + offsetof(struct tcbinfo, regs_off), + &xcpreg_off); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read registers' offset: ret = %d", ret); + return ERROR_FAIL; + } + + ret = target_read_u32(rtos->target, thread_id + xcpreg_off, ®saddr); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read registers' address: ret = %d", ret); + return ERROR_FAIL; + } - return rtos_generic_stack_read(rtos->target, stacking, - (uint32_t)thread_id + xcpreg_offset, reg_list, num_regs); + return rtos_generic_stack_read(rtos->target, stacking, regsaddr, reg_list, num_regs); } -static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) +static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs) { - unsigned int i; + if (!rtos) { + LOG_ERROR("NUTTX: out of memory"); + return ERROR_FAIL; + } - *symbol_list = (struct symbol_table_elem *) calloc(1, - sizeof(struct symbol_table_elem) * ARRAY_SIZE(nuttx_symbol_list)); + if (thread_id == rtos->current_thread) + return nuttx_getreg_current_thread(rtos, reg_list, num_regs); + return nuttx_getregs_fromstack(rtos, thread_id, reg_list, num_regs); +} - for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++) - (*symbol_list)[i].symbol_name = nuttx_symbol_list[i]; +static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) +{ + *symbol_list = calloc(ARRAY_SIZE(nuttx_symbol_list), sizeof(**symbol_list)); + if (!*symbol_list) { + LOG_ERROR("NUTTX: out of memory"); + return ERROR_FAIL; + } - return 0; + for (unsigned int i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++) { + (*symbol_list)[i].symbol_name = nuttx_symbol_list[i].name; + (*symbol_list)[i].optional = nuttx_symbol_list[i].optional; + } + + return ERROR_OK; } -struct rtos_type nuttx_rtos = { +const struct rtos_type nuttx_rtos = { .name = "nuttx", .detect_rtos = nuttx_detect_rtos, .create = nuttx_create, + .smp_init = nuttx_smp_init, .update_threads = nuttx_update_threads, .get_thread_reg_list = nuttx_get_thread_reg_list, .get_symbol_list_to_lookup = nuttx_get_symbol_list_to_lookup, diff --git a/src/rtos/nuttx_header.h b/src/rtos/nuttx_header.h deleted file mode 100644 index 00b0484ee9..0000000000 --- a/src/rtos/nuttx_header.h +++ /dev/null @@ -1,71 +0,0 @@ -/*************************************************************************** - * Copyright 2016,2017 Sony Video & Sound Products Inc. * - * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com * - * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.com * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_RTOS_NUTTX_HEADER_H -#define OPENOCD_RTOS_NUTTX_HEADER_H - -/* gdb script to update the header file - according to kernel version and build option - before executing function awareness - kernel symbol must be loaded : symbol nuttx - -define awareness - set logging off - set logging file nuttx_header.h - set logging on - - printf "#define PID %p\n",&((struct tcb_s *)(0))->pid - printf "#define XCPREG %p\n",&((struct tcb_s *)(0))->xcp.regs - printf "#define STATE %p\n",&((struct tcb_s *)(0))->task_state - printf "#define NAME %p\n",&((struct tcb_s *)(0))->name - printf "#define NAME_SIZE %d\n",sizeof(((struct tcb_s *)(0))->name) - end - - - OR ~/.gdbinit - - -define hookpost-file - - if &g_readytorun != 0 - eval "monitor nuttx.pid_offset %d", &((struct tcb_s *)(0))->pid - eval "monitor nuttx.xcpreg_offset %d", &((struct tcb_s *)(0))->xcp.regs - eval "monitor nuttx.state_offset %d", &((struct tcb_s *)(0))->task_state - eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name - eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name) - end - -end - -*/ - -/* default offset */ -#define PID 0xc -#define XCPREG 0x70 -#define STATE 0x19 -#define NAME 0xb8 -#define NAME_SIZE 32 - -/* defconfig of nuttx */ -/* #define CONFIG_DISABLE_SIGNALS */ -#define CONFIG_DISABLE_MQUEUE -/* #define CONFIG_PAGING */ - - -#endif /* OPENOCD_RTOS_NUTTX_HEADER_H */ diff --git a/src/rtos/riot.c b/src/rtos/riot.c index 8a3874202f..be5452e9e7 100644 --- a/src/rtos/riot.c +++ b/src/rtos/riot.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2015 by Daniel Krebs * * Daniel Krebs - github@daniel-krebs.net * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/rtos/rtkernel.c b/src/rtos/rtkernel.c new file mode 100644 index 0000000000..ba1de25172 --- /dev/null +++ b/src/rtos/rtkernel.c @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2016-2023 by Andreas Fritiofson * + * andreas.fritiofson@gmail.com * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/time_support.h> +#include <jtag/jtag.h> +#include "target/target.h" +#include "target/target_type.h" +#include "rtos.h" +#include "helper/log.h" +#include "helper/types.h" +#include "rtos_standard_stackings.h" +#include "target/armv7m.h" +#include "target/cortex_m.h" + +#define ST_DEAD BIT(0) /* Task is waiting to be deleted */ +#define ST_WAIT BIT(1) /* Task is blocked: */ +#define ST_SEM BIT(2) /* on semaphore */ +#define ST_MTX BIT(3) /* on mutex */ +#define ST_SIG BIT(4) /* on signal */ +#define ST_DLY BIT(5) /* on timer */ +#define ST_FLAG BIT(6) /* on flag */ +#define ST_FLAG_ALL BIT(7) /* on flag and flag mode is "ALL" */ +#define ST_MBOX BIT(8) /* on mailbox */ +#define ST_STP BIT(9) /* self stopped */ +#define ST_SUSPEND BIT(10) /* Task is suspended */ +#define ST_TT BIT(11) /* Time triggered task */ +#define ST_TT_YIELD BIT(12) /* Time triggered task that yields */ +#define ST_CREATE BIT(13) /* Task was created by task_create() */ + +struct rtkernel_params { + const char *target_name; + const struct rtos_register_stacking *stacking_info_cm3; + const struct rtos_register_stacking *stacking_info_cm4f; + const struct rtos_register_stacking *stacking_info_cm4f_fpu; +}; + +static const struct rtkernel_params rtkernel_params_list[] = { + { + "cortex_m", /* target_name */ + &rtos_standard_cortex_m3_stacking, /* stacking_info */ + &rtos_standard_cortex_m4f_stacking, + &rtos_standard_cortex_m4f_fpu_stacking, + }, + { + "hla_target", /* target_name */ + &rtos_standard_cortex_m3_stacking, /* stacking_info */ + &rtos_standard_cortex_m4f_stacking, + &rtos_standard_cortex_m4f_fpu_stacking, + }, +}; + +enum rtkernel_symbol_values { + sym_os_state = 0, + sym___off_os_state2chain = 1, + sym___off_os_state2current = 2, + sym___off_task2chain = 3, + sym___off_task2magic = 4, + sym___off_task2stack = 5, + sym___off_task2state = 6, + sym___off_task2name = 7, + sym___val_task_magic = 8, +}; + +struct symbols { + const char *name; + bool optional; +}; + +static const struct symbols rtkernel_symbol_list[] = { + { "os_state", false }, + { "__off_os_state2chain", false }, + { "__off_os_state2current", false }, + { "__off_task2chain", false }, + { "__off_task2magic", false }, + { "__off_task2stack", false }, + { "__off_task2state", false }, + { "__off_task2name", false }, + { "__val_task_magic", false }, + { NULL, false } +}; + +static void *realloc_preserve(void *ptr, size_t old_size, size_t new_size) +{ + void *new_ptr = malloc(new_size); + + if (new_ptr) { + memcpy(new_ptr, ptr, MIN(old_size, new_size)); + free(ptr); + } + + return new_ptr; +} + +static int rtkernel_add_task(struct rtos *rtos, uint32_t task, uint32_t current_task) +{ + int retval; + int new_thread_count = rtos->thread_count + 1; + struct thread_detail *new_thread_details = realloc_preserve(rtos->thread_details, + rtos->thread_count * sizeof(struct thread_detail), + new_thread_count * sizeof(struct thread_detail)); + if (!new_thread_details) { + LOG_ERROR("Error growing memory to %d threads", new_thread_count); + return ERROR_FAIL; + } + rtos->thread_details = new_thread_details; + struct thread_detail *thread = &new_thread_details[rtos->thread_count]; + + *thread = (struct thread_detail){ .threadid = task, .exists = true }; + + /* Read the task name */ + uint32_t name; + retval = target_read_u32(rtos->target, task + rtos->symbols[sym___off_task2name].address, &name); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read task name pointer from target"); + return retval; + } + uint8_t tmp_str[33]; + retval = target_read_buffer(rtos->target, name, sizeof(tmp_str) - 1, tmp_str); + if (retval != ERROR_OK) { + LOG_ERROR("Error reading task name from target"); + return retval; + } + tmp_str[sizeof(tmp_str) - 1] = '\0'; + LOG_DEBUG("task name at 0x%" PRIx32 ", value \"%s\"", name, tmp_str); + + if (tmp_str[0] != '\0') + thread->thread_name_str = strdup((char *)tmp_str); + else + thread->thread_name_str = strdup("No Name"); + + /* Read the task state */ + uint16_t state; + retval = target_read_u16(rtos->target, task + rtos->symbols[sym___off_task2state].address, &state); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read task state from target"); + return retval; + } + + LOG_DEBUG("task state 0x%" PRIx16, state); + + char state_str[64] = ""; + if (state & ST_TT) + strcat(state_str, "TT|"); + if (task == current_task) { + strcat(state_str, "RUN"); + } else { + if (state & (ST_TT | ST_TT_YIELD)) + strcat(state_str, "YIELD"); + else if (state & ST_DEAD) + strcat(state_str, "DEAD"); + else if (state & ST_WAIT) + strcat(state_str, "WAIT"); + else if (state & ST_SUSPEND) + strcat(state_str, "SUSP"); + else + strcat(state_str, "READY"); + } + if (state & ST_SEM) + strcat(state_str, "|SEM"); + if (state & ST_MTX) + strcat(state_str, "|MTX"); + if (state & ST_SIG) + strcat(state_str, "|SIG"); + if (state & ST_DLY) + strcat(state_str, "|DLY"); + if ((state & ST_FLAG) || (state & ST_FLAG_ALL)) + strcat(state_str, "|FLAG"); + if (state & ST_FLAG_ALL) + strcat(state_str, "_ALL"); + if (state & ST_MBOX) + strcat(state_str, "|MBOX"); + if (state & ST_STP) + strcat(state_str, "|STP"); + + thread->extra_info_str = strdup(state_str); + + rtos->thread_count = new_thread_count; + if (task == current_task) + rtos->current_thread = task; + return ERROR_OK; +} + +static int rtkernel_verify_task(struct rtos *rtos, uint32_t task) +{ + int retval; + uint32_t magic; + retval = target_read_u32(rtos->target, task + rtos->symbols[sym___off_task2magic].address, &magic); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read task magic from target"); + return retval; + } + if (magic != rtos->symbols[sym___val_task_magic].address) { + LOG_ERROR("Invalid task found (magic=0x%" PRIx32 ")", magic); + return ERROR_FAIL; + } + return retval; +} + +static int rtkernel_update_threads(struct rtos *rtos) +{ + /* wipe out previous thread details if any */ + /* do this first because rtos layer does not check our retval */ + rtos_free_threadlist(rtos); + rtos->current_thread = 0; + + if (!rtos->symbols) { + LOG_ERROR("No symbols for rt-kernel"); + return -3; + } + + /* read the current task */ + uint32_t current_task; + int retval = target_read_u32(rtos->target, + rtos->symbols[sym_os_state].address + rtos->symbols[sym___off_os_state2current].address, + ¤t_task); + if (retval != ERROR_OK) { + LOG_ERROR("Error reading current task"); + return retval; + } + LOG_DEBUG("current task is 0x%" PRIx32, current_task); + + retval = rtkernel_verify_task(rtos, current_task); + if (retval != ERROR_OK) { + LOG_ERROR("Current task is invalid"); + return retval; + } + + /* loop through kernel task list */ + uint32_t chain = rtos->symbols[sym_os_state].address + rtos->symbols[sym___off_os_state2chain].address; + LOG_DEBUG("chain start at 0x%" PRIx32, chain); + + uint32_t next = chain; + for (;;) { + retval = target_read_u32(rtos->target, next, &next); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read rt-kernel data structure from target"); + return retval; + } + LOG_DEBUG("next entry at 0x%" PRIx32, next); + if (next == chain) { + LOG_DEBUG("end of chain detected"); + break; + } + uint32_t task = next - rtos->symbols[sym___off_task2chain].address; + LOG_DEBUG("found task at 0x%" PRIx32, task); + + retval = rtkernel_verify_task(rtos, task); + if (retval != ERROR_OK) { + LOG_ERROR("Invalid task found"); + return retval; + } + + retval = rtkernel_add_task(rtos, task, current_task); + if (retval != ERROR_OK) { + LOG_ERROR("Could not add task to rtos system"); + return retval; + } + } + return ERROR_OK; +} + +static int rtkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs) +{ + uint32_t stack_ptr = 0; + + if (!rtos) + return -1; + + if (thread_id == 0) + return -2; + + if (!rtos->rtos_specific_params) + return -1; + + const struct rtkernel_params *param = rtos->rtos_specific_params; + + /* Read the stack pointer */ + int retval = target_read_u32(rtos->target, thread_id + rtos->symbols[sym___off_task2stack].address, &stack_ptr); + if (retval != ERROR_OK) { + LOG_ERROR("Error reading stack pointer from rtkernel thread"); + return retval; + } + LOG_DEBUG("stack pointer at 0x%" PRIx64 ", value 0x%" PRIx32, + thread_id + rtos->symbols[sym___off_task2stack].address, + stack_ptr); + + /* Adjust stack pointer to ignore non-standard BASEPRI register stacking */ + stack_ptr += 4; + + /* Check for armv7m with *enabled* FPU, i.e. a Cortex M4F */ + bool cm4_fpu_enabled = false; + struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); + if (is_armv7m(armv7m_target)) { + if (armv7m_target->fp_feature != FP_NONE) { + /* Found ARM v7m target which includes a FPU */ + uint32_t cpacr; + + retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read CPACR register to check FPU state"); + return -1; + } + + /* Check if CP10 and CP11 are set to full access. */ + if (cpacr & 0x00F00000) { + /* Found target with enabled FPU */ + cm4_fpu_enabled = true; + } + } + } + + if (!cm4_fpu_enabled) { + LOG_DEBUG("cm3 stacking"); + return rtos_generic_stack_read(rtos->target, param->stacking_info_cm3, stack_ptr, reg_list, num_regs); + } + + /* Read the LR to decide between stacking with or without FPU */ + uint32_t lr_svc; + retval = target_read_u32(rtos->target, stack_ptr + 0x20, &lr_svc); + if (retval != ERROR_OK) { + LOG_OUTPUT("Error reading stack frame from rtkernel thread\r\n"); + return retval; + } + + if ((lr_svc & 0x10) == 0) { + LOG_DEBUG("cm4f_fpu stacking"); + return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f_fpu, stack_ptr, reg_list, num_regs); + } + + LOG_DEBUG("cm4f stacking"); + return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f, stack_ptr, reg_list, num_regs); +} + +static int rtkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]) +{ + *symbol_list = calloc(ARRAY_SIZE(rtkernel_symbol_list), sizeof(struct symbol_table_elem)); + if (!*symbol_list) + return ERROR_FAIL; + + for (size_t i = 0; i < ARRAY_SIZE(rtkernel_symbol_list); i++) { + (*symbol_list)[i].symbol_name = rtkernel_symbol_list[i].name; + (*symbol_list)[i].optional = rtkernel_symbol_list[i].optional; + } + + return ERROR_OK; +} + +static bool rtkernel_detect_rtos(struct target *target) +{ + return (target->rtos->symbols) && + (target->rtos->symbols[sym___off_os_state2chain].address != 0); +} + +static int rtkernel_create(struct target *target) +{ + for (size_t i = 0; i < ARRAY_SIZE(rtkernel_params_list); i++) { + if (strcmp(rtkernel_params_list[i].target_name, target->type->name) == 0) { + target->rtos->rtos_specific_params = (void *)&rtkernel_params_list[i]; + return 0; + } + } + + LOG_ERROR("Could not find target in rt-kernel compatibility list"); + return -1; +} + +const struct rtos_type rtkernel_rtos = { + .name = "rtkernel", + + .detect_rtos = rtkernel_detect_rtos, + .create = rtkernel_create, + .update_threads = rtkernel_update_threads, + .get_thread_reg_list = rtkernel_get_thread_reg_list, + .get_symbol_list_to_lookup = rtkernel_get_symbol_list_to_lookup, +}; diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index b82ecb3388..b5e8e9adda 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -27,22 +16,7 @@ #include "helper/binarybuffer.h" #include "server/gdb_server.h" -/* RTOSs */ -extern struct rtos_type freertos_rtos; -extern struct rtos_type threadx_rtos; -extern struct rtos_type ecos_rtos; -extern struct rtos_type linux_rtos; -extern struct rtos_type chibios_rtos; -extern struct rtos_type chromium_ec_rtos; -extern struct rtos_type embkernel_rtos; -extern struct rtos_type mqx_rtos; -extern struct rtos_type ucos_iii_rtos; -extern struct rtos_type nuttx_rtos; -extern struct rtos_type hwthread_rtos; -extern struct rtos_type riot_rtos; -extern struct rtos_type zephyr_rtos; - -static struct rtos_type *rtos_types[] = { +static const struct rtos_type *rtos_types[] = { &threadx_rtos, &freertos_rtos, &ecos_rtos, @@ -55,6 +29,7 @@ static struct rtos_type *rtos_types[] = { &nuttx_rtos, &riot_rtos, &zephyr_rtos, + &rtkernel_rtos, /* keep this as last, as it always matches with rtos auto */ &hwthread_rtos, NULL @@ -62,8 +37,6 @@ static struct rtos_type *rtos_types[] = { static int rtos_try_next(struct target *target); -int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size); - int rtos_smp_init(struct target *target) { if (target->rtos->type->smp_init) @@ -82,7 +55,7 @@ static int rtos_target_for_threadid(struct connection *connection, return ERROR_OK; } -static int os_alloc(struct target *target, struct rtos_type *ostype, +static int os_alloc(struct target *target, const struct rtos_type *ostype, struct command_context *cmd_ctx) { struct rtos *os = target->rtos = calloc(1, sizeof(struct rtos)); @@ -110,11 +83,12 @@ static void os_free(struct target *target) return; free(target->rtos->symbols); + rtos_free_threadlist(target->rtos); free(target->rtos); target->rtos = NULL; } -static int os_alloc_create(struct target *target, struct rtos_type *ostype, +static int os_alloc_create(struct target *target, const struct rtos_type *ostype, struct command_context *cmd_ctx) { int ret = os_alloc(target, ostype, cmd_ctx); @@ -148,6 +122,9 @@ int rtos_create(struct jim_getopt_info *goi, struct target *target) if (e != JIM_OK) return e; + if (strcmp(cp, "none") == 0) + return JIM_OK; + if (strcmp(cp, "auto") == 0) { /* Auto detect tries to look up all symbols for each RTOS, * and runs the RTOS driver's _detect() function when GDB @@ -167,7 +144,7 @@ int rtos_create(struct jim_getopt_info *goi, struct target *target) res = Jim_GetResult(goi->interp); for (x = 0; rtos_types[x]; x++) Jim_AppendStrings(goi->interp, res, rtos_types[x]->name, ", ", NULL); - Jim_AppendStrings(goi->interp, res, " or auto", NULL); + Jim_AppendStrings(goi->interp, res, ", auto or none", NULL); return JIM_ERR; } @@ -186,35 +163,32 @@ int gdb_thread_packet(struct connection *connection, char const *packet, int pac return target->rtos->gdb_thread_packet(connection, packet, packet_size); } -static struct symbol_table_elem *next_symbol(struct rtos *os, char *cur_symbol, uint64_t cur_addr) +static struct symbol_table_elem *find_symbol(const struct rtos *os, const char *symbol) { struct symbol_table_elem *s; - if (!os->symbols) - os->type->get_symbol_list_to_lookup(&os->symbols); - - if (!cur_symbol[0]) - return &os->symbols[0]; - for (s = os->symbols; s->symbol_name; s++) - if (!strcmp(s->symbol_name, cur_symbol)) { - s->address = cur_addr; - s++; + if (!strcmp(s->symbol_name, symbol)) return s; - } return NULL; } -/* searches for 'symbol' in the lookup table for 'os' and returns TRUE, - * if 'symbol' is not declared optional */ -static bool is_symbol_mandatory(const struct rtos *os, const char *symbol) +static struct symbol_table_elem *next_symbol(struct rtos *os, char *cur_symbol, uint64_t cur_addr) { - for (struct symbol_table_elem *s = os->symbols; s->symbol_name; ++s) { - if (!strcmp(s->symbol_name, symbol)) - return !s->optional; - } - return false; + if (!os->symbols) + os->type->get_symbol_list_to_lookup(&os->symbols); + + if (!cur_symbol[0]) + return &os->symbols[0]; + + struct symbol_table_elem *s = find_symbol(os, cur_symbol); + if (!s) + return NULL; + + s->address = cur_addr; + s++; + return s; } /* rtos_qsymbol() processes and replies to all qSymbol packets from GDB. @@ -234,6 +208,12 @@ static bool is_symbol_mandatory(const struct rtos *os, const char *symbol) * specified explicitly, then no further symbol lookup is done. When * auto-detecting, the RTOS driver _detect() function must return success. * + * The symbol is tried twice to handle the -flto case with gcc. The first + * attempt uses the symbol as-is, and the second attempt tries the symbol + * with ".lto_priv.0" appended to it. We only consider the first static + * symbol here from the -flto case. (Each subsequent static symbol with + * the same name is exported as .lto_priv.1, .lto_priv.2, etc.) + * * rtos_qsymbol() returns 1 if an RTOS has been detected, or 0 otherwise. */ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_size) @@ -242,7 +222,7 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s uint64_t addr = 0; size_t reply_len; char reply[GDB_BUFFER_SIZE + 1], cur_sym[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for null-termination */ - struct symbol_table_elem *next_sym; + struct symbol_table_elem *next_sym = NULL; struct target *target = get_target_from_connection(connection); struct rtos *os = target->rtos; @@ -255,33 +235,60 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s size_t len = unhexify((uint8_t *)cur_sym, strchr(packet + 8, ':') + 1, strlen(strchr(packet + 8, ':') + 1)); cur_sym[len] = 0; + const char no_suffix[] = ""; + const char lto_suffix[] = ".lto_priv.0"; + const size_t lto_suffix_len = strlen(lto_suffix); + + const char *cur_suffix; + const char *next_suffix; + + /* Detect what suffix was used during the previous symbol lookup attempt, and + * speculatively determine the next suffix (only used for the unknown address case) */ + if (len > lto_suffix_len && !strcmp(cur_sym + len - lto_suffix_len, lto_suffix)) { + /* Trim the suffix from cur_sym for comparison purposes below */ + cur_sym[len - lto_suffix_len] = '\0'; + cur_suffix = lto_suffix; + next_suffix = NULL; + } else { + cur_suffix = no_suffix; + next_suffix = lto_suffix; + } + if ((strcmp(packet, "qSymbol::") != 0) && /* GDB is not offering symbol lookup for the first time */ - (!sscanf(packet, "qSymbol:%" SCNx64 ":", &addr)) && /* GDB did not find an address for a symbol */ - is_symbol_mandatory(os, cur_sym)) { /* the symbol is mandatory for this RTOS */ + (!sscanf(packet, "qSymbol:%" SCNx64 ":", &addr))) { /* GDB did not find an address for a symbol */ /* GDB could not find an address for the previous symbol */ - if (!target->rtos_auto_detect) { - LOG_WARNING("RTOS %s not detected. (GDB could not find symbol \'%s\')", os->type->name, cur_sym); - goto done; - } else { - /* Autodetecting RTOS - try next RTOS */ - if (!rtos_try_next(target)) { - LOG_WARNING("No RTOS could be auto-detected!"); + struct symbol_table_elem *sym = find_symbol(os, cur_sym); + + if (next_suffix) { + next_sym = sym; + } else if (sym && !sym->optional) { /* the symbol is mandatory for this RTOS */ + if (!target->rtos_auto_detect) { + LOG_WARNING("RTOS %s not detected. (GDB could not find symbol \'%s\')", os->type->name, cur_sym); goto done; - } + } else { + /* Autodetecting RTOS - try next RTOS */ + if (!rtos_try_next(target)) { + LOG_WARNING("No RTOS could be auto-detected!"); + goto done; + } - /* Next RTOS selected - invalidate current symbol */ - cur_sym[0] = '\x00'; + /* Next RTOS selected - invalidate current symbol */ + cur_sym[0] = '\x00'; + } } } - LOG_DEBUG("RTOS: Address of symbol '%s' is 0x%" PRIx64, cur_sym, addr); + LOG_DEBUG("RTOS: Address of symbol '%s%s' is 0x%" PRIx64, cur_sym, cur_suffix, addr); - next_sym = next_symbol(os, cur_sym, addr); + if (!next_sym) { + next_sym = next_symbol(os, cur_sym, addr); + next_suffix = no_suffix; + } /* Should never happen unless the debugger misbehaves */ if (!next_sym) { - LOG_WARNING("RTOS: Debugger sent us qSymbol with '%s' that we did not ask for", cur_sym); + LOG_WARNING("RTOS: Debugger sent us qSymbol with '%s%s' that we did not ask for", cur_sym, cur_suffix); goto done; } @@ -303,17 +310,26 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s } } - if (8 + (strlen(next_sym->symbol_name) * 2) + 1 > sizeof(reply)) { - LOG_ERROR("ERROR: RTOS symbol '%s' name is too long for GDB!", next_sym->symbol_name); + assert(next_suffix); + + reply_len = 8; /* snprintf(..., "qSymbol:") */ + reply_len += 2 * strlen(next_sym->symbol_name); /* hexify(..., next_sym->symbol_name, ...) */ + reply_len += 2 * strlen(next_suffix); /* hexify(..., next_suffix, ...) */ + reply_len += 1; /* Terminating NUL */ + if (reply_len > sizeof(reply)) { + LOG_ERROR("ERROR: RTOS symbol '%s%s' name is too long for GDB!", next_sym->symbol_name, next_suffix); goto done; } - LOG_DEBUG("RTOS: Requesting symbol lookup of '%s' from the debugger", next_sym->symbol_name); + LOG_DEBUG("RTOS: Requesting symbol lookup of '%s%s' from the debugger", next_sym->symbol_name, next_suffix); reply_len = snprintf(reply, sizeof(reply), "qSymbol:"); reply_len += hexify(reply + reply_len, (const uint8_t *)next_sym->symbol_name, strlen(next_sym->symbol_name), sizeof(reply) - reply_len); + reply_len += hexify(reply + reply_len, + (const uint8_t *)next_suffix, strlen(next_suffix), + sizeof(reply) - reply_len); done: gdb_put_packet(connection, reply, reply_len); @@ -496,68 +512,70 @@ int rtos_get_gdb_reg(struct connection *connection, int reg_num) { struct target *target = get_target_from_connection(connection); threadid_t current_threadid = target->rtos->current_threadid; - if ((target->rtos) && (current_threadid != -1) && - (current_threadid != 0) && - ((current_threadid != target->rtos->current_thread) || - (target->smp))) { /* in smp several current thread are possible */ - struct rtos_reg *reg_list; - int num_regs; + if (!target->rtos || + current_threadid == -1 || + current_threadid == 0 || + (current_threadid == target->rtos->current_thread && + !target->smp)) { /* in smp several current thread are possible */ + return ERROR_NOT_IMPLEMENTED; + } - LOG_DEBUG("getting register %d for thread 0x%" PRIx64 - ", target->rtos->current_thread=0x%" PRIx64, - reg_num, - current_threadid, - target->rtos->current_thread); - - int retval; - if (target->rtos->type->get_thread_reg_value) { - uint32_t reg_size; - uint8_t *reg_value; - retval = target->rtos->type->get_thread_reg_value(target->rtos, - current_threadid, reg_num, ®_size, ®_value); - if (retval != ERROR_OK) { - LOG_ERROR("RTOS: failed to get register %d", reg_num); - return retval; - } + struct rtos_reg *reg_list; + int num_regs; - /* Create a reg_list with one register that can - * accommodate the full size of the one we just got the - * value for. To do that we allocate extra space off the - * end of the struct, relying on the fact that - * rtos_reg.value is the last element in the struct. */ - reg_list = calloc(1, sizeof(*reg_list) + DIV_ROUND_UP(reg_size, 8)); - if (!reg_list) { - free(reg_value); - LOG_ERROR("Failed to allocated reg_list for %d-byte register.", - reg_size); - return ERROR_FAIL; - } - reg_list[0].number = reg_num; - reg_list[0].size = reg_size; - memcpy(®_list[0].value, reg_value, DIV_ROUND_UP(reg_size, 8)); - free(reg_value); - num_regs = 1; - } else { - retval = target->rtos->type->get_thread_reg_list(target->rtos, - current_threadid, - ®_list, - &num_regs); - if (retval != ERROR_OK) { - LOG_ERROR("RTOS: failed to get register list"); - return retval; - } + LOG_TARGET_DEBUG(target, "getting register %d for thread 0x%" PRIx64 + ", target->rtos->current_thread=0x%" PRIx64, + reg_num, current_threadid, target->rtos->current_thread); + + int retval; + if (target->rtos->type->get_thread_reg_value) { + uint32_t reg_size; + uint8_t *reg_value; + retval = target->rtos->type->get_thread_reg_value(target->rtos, + current_threadid, reg_num, ®_size, ®_value); + if (retval != ERROR_OK) { + LOG_ERROR("RTOS: failed to get register %d", reg_num); + return retval; } - for (int i = 0; i < num_regs; ++i) { - if (reg_list[i].number == (uint32_t)reg_num) { - rtos_put_gdb_reg_list(connection, reg_list + i, 1); - free(reg_list); - return ERROR_OK; - } + /* Create a reg_list with one register that can + * accommodate the full size of the one we just got the + * value for. To do that we allocate extra space off the + * end of the struct, relying on the fact that + * rtos_reg.value is the last element in the struct. */ + reg_list = calloc(1, sizeof(*reg_list) + DIV_ROUND_UP(reg_size, 8)); + if (!reg_list) { + free(reg_value); + LOG_ERROR("Failed to allocated reg_list for %d-byte register.", + reg_size); + return ERROR_FAIL; } + reg_list[0].number = reg_num; + reg_list[0].size = reg_size; + memcpy(®_list[0].value, reg_value, DIV_ROUND_UP(reg_size, 8)); + free(reg_value); + num_regs = 1; + } else { + retval = target->rtos->type->get_thread_reg_list(target->rtos, + current_threadid, + ®_list, + &num_regs); + if (retval != ERROR_OK) { + LOG_ERROR("RTOS: failed to get register list"); + return retval; + } + } - free(reg_list); + for (int i = 0; i < num_regs; ++i) { + if (reg_list[i].number == (uint32_t)reg_num) { + rtos_put_gdb_reg_list(connection, reg_list + i, 1); + free(reg_list); + return ERROR_OK; + } } + + free(reg_list); + return ERROR_FAIL; } @@ -626,7 +644,10 @@ int rtos_generic_stack_read(struct target *target, if (stacking->stack_growth_direction == 1) address -= stacking->stack_registers_size; - retval = target_read_buffer(target, address, stacking->stack_registers_size, stack_data); + if (stacking->read_stack) + retval = stacking->read_stack(target, address, stacking, stack_data); + else + retval = target_read_buffer(target, address, stacking->stack_registers_size, stack_data); if (retval != ERROR_OK) { free(stack_data); LOG_ERROR("Error reading stack frame from thread"); @@ -769,7 +790,7 @@ int rtos_generic_stack_write_reg(struct target *target, static int rtos_try_next(struct target *target) { struct rtos *os = target->rtos; - struct rtos_type **type = rtos_types; + const struct rtos_type **type = rtos_types; if (!os) return 0; diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index 745bea7bbc..210f4fc99e 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_RTOS_RTOS_H @@ -137,7 +126,15 @@ struct rtos_register_stacking { /* Total number of registers on the stack, including the general ones. This * may be 0 if there are no additional registers on the stack beyond the * general ones. */ - unsigned total_register_count; + unsigned int total_register_count; + + /* Optional field for targets which may have to implement their own stack read function. + * Because stack format can be weird or stack data needed to be edited before passing to the gdb. + */ + int (*read_stack)(struct target *target, + int64_t stack_ptr, + const struct rtos_register_stacking *stacking, + uint8_t *stack_data); }; #define GDB_THREAD_PACKET_NOT_CONSUMED (-40) @@ -160,6 +157,7 @@ int rtos_generic_stack_write_reg(struct target *target, target_addr_t stack_ptr, uint32_t reg_num, uint8_t *reg_value); int gdb_thread_packet(struct connection *connection, char const *packet, int packet_size); +int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size); int rtos_get_gdb_reg(struct connection *connection, int reg_num); int rtos_get_gdb_reg_list(struct connection *connection); int rtos_update_threads(struct target *target); @@ -176,4 +174,19 @@ struct target *rtos_swbp_target(struct target *target, target_addr_t address, uint32_t length, enum breakpoint_type type); struct rtos *rtos_of_target(struct target *target); +extern const struct rtos_type chibios_rtos; +extern const struct rtos_type chromium_ec_rtos; +extern const struct rtos_type ecos_rtos; +extern const struct rtos_type embkernel_rtos; +extern const struct rtos_type freertos_rtos; +extern const struct rtos_type hwthread_rtos; +extern const struct rtos_type linux_rtos; +extern const struct rtos_type mqx_rtos; +extern const struct rtos_type nuttx_rtos; +extern const struct rtos_type riot_rtos; +extern const struct rtos_type rtkernel_rtos; +extern const struct rtos_type threadx_rtos; +extern const struct rtos_type ucos_iii_rtos; +extern const struct rtos_type zephyr_rtos; + #endif /* OPENOCD_RTOS_RTOS_H */ diff --git a/src/rtos/rtos_chibios_stackings.c b/src/rtos/rtos_chibios_stackings.c index 77bcb86cb7..c0816ac3cf 100644 --- a/src/rtos/rtos_chibios_stackings.c +++ b/src/rtos/rtos_chibios_stackings.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2012 by Matthias Blaicher * * Matthias Blaicher - matthias@blaicher.com * * * * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -25,6 +14,7 @@ #include "rtos.h" #include "target/armv7m.h" +#include "rtos_chibios_stackings.h" static const struct stack_register_offset rtos_chibios_arm_v7m_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, -1, 32 }, /* r0 */ @@ -43,7 +33,7 @@ static const struct stack_register_offset rtos_chibios_arm_v7m_stack_offsets[ARM { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, -1, 32 }, /* lr */ { ARMV7M_PC, 0x20, 32 }, /* pc */ - { ARMV7M_xPSR, -1, 32 }, /* xPSR */ + { ARMV7M_XPSR, -1, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking = { @@ -70,7 +60,7 @@ static const struct stack_register_offset rtos_chibios_arm_v7m_stack_offsets_w_f { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, -1, 32 }, /* lr */ { ARMV7M_PC, 0x60, 32 }, /* pc */ - { ARMV7M_xPSR, -1, 32 }, /* xPSR */ + { ARMV7M_XPSR, -1, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking_w_fpu = { diff --git a/src/rtos/rtos_chibios_stackings.h b/src/rtos/rtos_chibios_stackings.h index 130aaa18f7..e909451e25 100644 --- a/src/rtos/rtos_chibios_stackings.h +++ b/src/rtos/rtos_chibios_stackings.h @@ -1,28 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_RTOS_RTOS_CHIBIOS_STACKINGS_H #define OPENOCD_RTOS_RTOS_CHIBIOS_STACKINGS_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "rtos.h" extern const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking; diff --git a/src/rtos/rtos_ecos_stackings.c b/src/rtos/rtos_ecos_stackings.c index 4745470ce2..cae271270a 100644 --- a/src/rtos/rtos_ecos_stackings.c +++ b/src/rtos/rtos_ecos_stackings.c @@ -1,27 +1,21 @@ -/*************************************************************************** - * * - * 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/>. * - ***************************************************************************/ +// SPDX-License-Identifier: GPL-2.0-or-later #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" -#include "rtos_standard_stackings.h" #include "target/armv7m.h" +#include "rtos_standard_stackings.h" +#include "rtos_ecos_stackings.h" + +/* For Cortex-M eCos applications the actual thread context register layout can + * be different between active threads of an application depending on whether + * the FPU is in use, configured for lazy FPU context saving, etc. */ +/* Default fixed thread register context description used for older eCos + * application builds without the necessary symbolic information describing the + * actual configuration-dependent offsets. */ static const struct stack_register_offset rtos_ecos_cortex_m3_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, 0x0c, 32 }, /* r0 */ { ARMV7M_R1, 0x10, 32 }, /* r1 */ @@ -39,7 +33,7 @@ static const struct stack_register_offset rtos_ecos_cortex_m3_stack_offsets[ARMV { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, -1, 32 }, /* lr */ { ARMV7M_PC, 0x40, 32 }, /* pc */ - { ARMV7M_xPSR, -1, 32 }, /* xPSR */ + { ARMV7M_XPSR, -1, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_ecos_cortex_m3_stacking = { diff --git a/src/rtos/rtos_ecos_stackings.h b/src/rtos/rtos_ecos_stackings.h index d66d05fe9c..a6bcf1acbb 100644 --- a/src/rtos/rtos_ecos_stackings.h +++ b/src/rtos/rtos_ecos_stackings.h @@ -1,26 +1,8 @@ -/*************************************************************************** - * * - * 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/>. * - ***************************************************************************/ +/* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef OPENOCD_RTOS_RTOS_ECOS_STACKINGS_H #define OPENOCD_RTOS_RTOS_ECOS_STACKINGS_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "rtos.h" extern const struct rtos_register_stacking rtos_ecos_cortex_m3_stacking; diff --git a/src/rtos/rtos_embkernel_stackings.c b/src/rtos/rtos_embkernel_stackings.c index df1fc51f29..b98628a136 100644 --- a/src/rtos/rtos_embkernel_stackings.c +++ b/src/rtos/rtos_embkernel_stackings.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -23,6 +12,7 @@ #include "rtos.h" #include "target/armv7m.h" #include "rtos_standard_stackings.h" +#include "rtos_embkernel_stackings.h" static const struct stack_register_offset rtos_embkernel_cortex_m_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, 0x24, 32 }, /* r0 */ @@ -41,7 +31,7 @@ static const struct stack_register_offset rtos_embkernel_cortex_m_stack_offsets[ { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x38, 32 }, /* lr */ { ARMV7M_PC, 0x3c, 32 }, /* pc */ - { ARMV7M_xPSR, 0x40, 32 }, /* xPSR */ + { ARMV7M_XPSR, 0x40, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_embkernel_cortex_m_stacking = { diff --git a/src/rtos/rtos_embkernel_stackings.h b/src/rtos/rtos_embkernel_stackings.h index 7850bebcd0..87bd0e73b8 100644 --- a/src/rtos/rtos_embkernel_stackings.h +++ b/src/rtos/rtos_embkernel_stackings.h @@ -1,28 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_RTOS_RTOS_EMBKERNEL_STACKINGS_H #define OPENOCD_RTOS_RTOS_EMBKERNEL_STACKINGS_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "rtos.h" extern const struct rtos_register_stacking rtos_embkernel_cortex_m_stacking; diff --git a/src/rtos/rtos_mqx_stackings.c b/src/rtos/rtos_mqx_stackings.c index f99190ea5b..5ab743bf30 100644 --- a/src/rtos/rtos_mqx_stackings.c +++ b/src/rtos/rtos_mqx_stackings.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2014 by Marian Cingel * * cingel.marian@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -22,7 +11,7 @@ #include "rtos.h" #include "target/armv7m.h" - +#include "rtos_mqx_stackings.h" /* * standard exception stack @@ -67,7 +56,7 @@ static const struct stack_register_offset rtos_mqx_arm_v7m_stack_offsets[ARMV7M_ { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x28, 32 }, /* lr */ { ARMV7M_PC, 0x44, 32 }, /* pc */ - { ARMV7M_xPSR, 0x48, 32 }, /* xPSR */ + { ARMV7M_XPSR, 0x48, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_mqx_arm_v7m_stacking = { diff --git a/src/rtos/rtos_mqx_stackings.h b/src/rtos/rtos_mqx_stackings.h index 6ebd28789c..faa741de60 100644 --- a/src/rtos/rtos_mqx_stackings.h +++ b/src/rtos/rtos_mqx_stackings.h @@ -1,28 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2014 by Marian Cingel * * cingel.marian@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_RTOS_RTOS_MQX_STACKINGS_H #define OPENOCD_RTOS_RTOS_MQX_STACKINGS_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "rtos.h" extern const struct rtos_register_stacking rtos_mqx_arm_v7m_stacking; diff --git a/src/rtos/rtos_nuttx_stackings.c b/src/rtos/rtos_nuttx_stackings.c new file mode 100644 index 0000000000..b70cccb33a --- /dev/null +++ b/src/rtos/rtos_nuttx_stackings.c @@ -0,0 +1,468 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "rtos.h" +#include "target/armv7m.h" +#include "rtos_nuttx_stackings.h" +#include "rtos_standard_stackings.h" +#include <target/riscv/riscv.h> + +/* see arch/arm/include/armv7-m/irq_cmnvector.h */ +static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = { + { ARMV7M_R0, 0x28, 32 }, /* r0 */ + { ARMV7M_R1, 0x2c, 32 }, /* r1 */ + { ARMV7M_R2, 0x30, 32 }, /* r2 */ + { ARMV7M_R3, 0x34, 32 }, /* r3 */ + { ARMV7M_R4, 0x08, 32 }, /* r4 */ + { ARMV7M_R5, 0x0c, 32 }, /* r5 */ + { ARMV7M_R6, 0x10, 32 }, /* r6 */ + { ARMV7M_R7, 0x14, 32 }, /* r7 */ + { ARMV7M_R8, 0x18, 32 }, /* r8 */ + { ARMV7M_R9, 0x1c, 32 }, /* r9 */ + { ARMV7M_R10, 0x20, 32 }, /* r10 */ + { ARMV7M_R11, 0x24, 32 }, /* r11 */ + { ARMV7M_R12, 0x38, 32 }, /* r12 */ + { ARMV7M_R13, 0, 32 }, /* sp */ + { ARMV7M_R14, 0x3c, 32 }, /* lr */ + { ARMV7M_PC, 0x40, 32 }, /* pc */ + { ARMV7M_XPSR, 0x44, 32 }, /* xPSR */ +}; + +const struct rtos_register_stacking nuttx_stacking_cortex_m = { + .stack_registers_size = 0x48, + .stack_growth_direction = -1, + .num_output_registers = 17, + .register_offsets = nuttx_stack_offsets_cortex_m, +}; + +static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = { + { ARMV7M_R0, 0x6c, 32 }, /* r0 */ + { ARMV7M_R1, 0x70, 32 }, /* r1 */ + { ARMV7M_R2, 0x74, 32 }, /* r2 */ + { ARMV7M_R3, 0x78, 32 }, /* r3 */ + { ARMV7M_R4, 0x08, 32 }, /* r4 */ + { ARMV7M_R5, 0x0c, 32 }, /* r5 */ + { ARMV7M_R6, 0x10, 32 }, /* r6 */ + { ARMV7M_R7, 0x14, 32 }, /* r7 */ + { ARMV7M_R8, 0x18, 32 }, /* r8 */ + { ARMV7M_R9, 0x1c, 32 }, /* r9 */ + { ARMV7M_R10, 0x20, 32 }, /* r10 */ + { ARMV7M_R11, 0x24, 32 }, /* r11 */ + { ARMV7M_R12, 0x7c, 32 }, /* r12 */ + { ARMV7M_R13, 0, 32 }, /* sp */ + { ARMV7M_R14, 0x80, 32 }, /* lr */ + { ARMV7M_PC, 0x84, 32 }, /* pc */ + { ARMV7M_XPSR, 0x88, 32 }, /* xPSR */ +}; + +const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = { + .stack_registers_size = 0x8c, + .stack_growth_direction = -1, + .num_output_registers = 17, + .register_offsets = nuttx_stack_offsets_cortex_m_fpu, +}; + +static const struct stack_register_offset nuttx_stack_offsets_riscv[] = { + { GDB_REGNO_ZERO, -1, 32 }, + { GDB_REGNO_RA, 0x04, 32 }, + { GDB_REGNO_SP, 0x08, 32 }, + { GDB_REGNO_GP, 0x0c, 32 }, + { GDB_REGNO_TP, 0x10, 32 }, + { GDB_REGNO_T0, 0x14, 32 }, + { GDB_REGNO_T1, 0x18, 32 }, + { GDB_REGNO_T2, 0x1c, 32 }, + { GDB_REGNO_FP, 0x20, 32 }, + { GDB_REGNO_S1, 0x24, 32 }, + { GDB_REGNO_A0, 0x28, 32 }, + { GDB_REGNO_A1, 0x2c, 32 }, + { GDB_REGNO_A2, 0x30, 32 }, + { GDB_REGNO_A3, 0x34, 32 }, + { GDB_REGNO_A4, 0x38, 32 }, + { GDB_REGNO_A5, 0x3c, 32 }, + { GDB_REGNO_A6, 0x40, 32 }, + { GDB_REGNO_A7, 0x44, 32 }, + { GDB_REGNO_S2, 0x48, 32 }, + { GDB_REGNO_S3, 0x4c, 32 }, + { GDB_REGNO_S4, 0x50, 32 }, + { GDB_REGNO_S5, 0x54, 32 }, + { GDB_REGNO_S6, 0x58, 32 }, + { GDB_REGNO_S7, 0x5c, 32 }, + { GDB_REGNO_S8, 0x60, 32 }, + { GDB_REGNO_S9, 0x64, 32 }, + { GDB_REGNO_S10, 0x68, 32 }, + { GDB_REGNO_S11, 0x6c, 32 }, + { GDB_REGNO_T3, 0x70, 32 }, + { GDB_REGNO_T4, 0x74, 32 }, + { GDB_REGNO_T5, 0x78, 32 }, + { GDB_REGNO_T6, 0x7c, 32 }, + { GDB_REGNO_PC, 0x00, 32 }, +}; + +const struct rtos_register_stacking nuttx_riscv_stacking = { + .stack_registers_size = 33 * 4, + .stack_growth_direction = -1, + .num_output_registers = 33, + .calculate_process_stack = rtos_generic_stack_align8, + .register_offsets = nuttx_stack_offsets_riscv, +}; + +static int nuttx_esp_xtensa_stack_read(struct target *target, + int64_t stack_ptr, const struct rtos_register_stacking *stacking, + uint8_t *stack_data) +{ + int retval = target_read_buffer(target, stack_ptr, stacking->stack_registers_size, stack_data); + if (retval != ERROR_OK) + return retval; + + stack_data[4] &= ~0x10; /* Clear exception bit in PS */ + + return ERROR_OK; +} + +static const struct stack_register_offset nuttx_stack_offsets_esp32[] = { + { 0, 0x00, 32 }, /* PC */ + { 1, 0x08, 32 }, /* A0 */ + { 2, 0x0c, 32 }, /* A1 */ + { 3, 0x10, 32 }, /* A2 */ + { 4, 0x14, 32 }, /* A3 */ + { 5, 0x18, 32 }, /* A4 */ + { 6, 0x1c, 32 }, /* A5 */ + { 7, 0x20, 32 }, /* A6 */ + { 8, 0x24, 32 }, /* A7 */ + { 9, 0x28, 32 }, /* A8 */ + { 10, 0x2c, 32 }, /* A9 */ + { 11, 0x30, 32 }, /* A10 */ + { 12, 0x34, 32 }, /* A11 */ + { 13, 0x38, 32 }, /* A12 */ + { 14, 0x3c, 32 }, /* A13 */ + { 15, 0x40, 32 }, /* A14 */ + { 16, 0x44, 32 }, /* A15 */ + /* A16-A63 aren't in the stack frame because they've been flushed to the stack earlier */ + { 17, -1, 32 }, /* A16 */ + { 18, -1, 32 }, /* A17 */ + { 19, -1, 32 }, /* A18 */ + { 20, -1, 32 }, /* A19 */ + { 21, -1, 32 }, /* A20 */ + { 22, -1, 32 }, /* A21 */ + { 23, -1, 32 }, /* A22 */ + { 24, -1, 32 }, /* A23 */ + { 25, -1, 32 }, /* A24 */ + { 26, -1, 32 }, /* A25 */ + { 27, -1, 32 }, /* A26 */ + { 28, -1, 32 }, /* A27 */ + { 29, -1, 32 }, /* A28 */ + { 30, -1, 32 }, /* A29 */ + { 31, -1, 32 }, /* A30 */ + { 32, -1, 32 }, /* A31 */ + { 33, -1, 32 }, /* A32 */ + { 34, -1, 32 }, /* A33 */ + { 35, -1, 32 }, /* A34 */ + { 36, -1, 32 }, /* A35 */ + { 37, -1, 32 }, /* A36 */ + { 38, -1, 32 }, /* A37 */ + { 39, -1, 32 }, /* A38 */ + { 40, -1, 32 }, /* A39 */ + { 41, -1, 32 }, /* A40 */ + { 42, -1, 32 }, /* A41 */ + { 43, -1, 32 }, /* A42 */ + { 44, -1, 32 }, /* A43 */ + { 45, -1, 32 }, /* A44 */ + { 46, -1, 32 }, /* A45 */ + { 47, -1, 32 }, /* A46 */ + { 48, -1, 32 }, /* A47 */ + { 49, -1, 32 }, /* A48 */ + { 50, -1, 32 }, /* A49 */ + { 51, -1, 32 }, /* A50 */ + { 52, -1, 32 }, /* A51 */ + { 53, -1, 32 }, /* A52 */ + { 54, -1, 32 }, /* A53 */ + { 55, -1, 32 }, /* A54 */ + { 56, -1, 32 }, /* A55 */ + { 57, -1, 32 }, /* A56 */ + { 58, -1, 32 }, /* A57 */ + { 59, -1, 32 }, /* A58 */ + { 60, -1, 32 }, /* A59 */ + { 61, -1, 32 }, /* A60 */ + { 62, -1, 32 }, /* A61 */ + { 63, -1, 32 }, /* A62 */ + { 64, -1, 32 }, /* A63 */ + { 65, 0x58, 32 }, /* lbeg */ + { 66, 0x5c, 32 }, /* lend */ + { 67, 0x60, 32 }, /* lcount */ + { 68, 0x48, 32 }, /* SAR */ + { 69, -1, 32 }, /* windowbase */ + { 70, -1, 32 }, /* windowstart */ + { 71, -1, 32 }, /* configid0 */ + { 72, -1, 32 }, /* configid1 */ + { 73, 0x04, 32 }, /* PS */ + { 74, -1, 32 }, /* threadptr */ + { 75, -1, 32 }, /* br */ + { 76, 0x54, 32 }, /* scompare1 */ + { 77, -1, 32 }, /* acclo */ + { 78, -1, 32 }, /* acchi */ + { 79, -1, 32 }, /* m0 */ + { 80, -1, 32 }, /* m1 */ + { 81, -1, 32 }, /* m2 */ + { 82, -1, 32 }, /* m3 */ + { 83, -1, 32 }, /* expstate */ + { 84, -1, 32 }, /* f64r_lo */ + { 85, -1, 32 }, /* f64r_hi */ + { 86, -1, 32 }, /* f64s */ + { 87, -1, 32 }, /* f0 */ + { 88, -1, 32 }, /* f1 */ + { 89, -1, 32 }, /* f2 */ + { 90, -1, 32 }, /* f3 */ + { 91, -1, 32 }, /* f4 */ + { 92, -1, 32 }, /* f5 */ + { 93, -1, 32 }, /* f6 */ + { 94, -1, 32 }, /* f7 */ + { 95, -1, 32 }, /* f8 */ + { 96, -1, 32 }, /* f9 */ + { 97, -1, 32 }, /* f10 */ + { 98, -1, 32 }, /* f11 */ + { 99, -1, 32 }, /* f12 */ + { 100, -1, 32 }, /* f13 */ + { 101, -1, 32 }, /* f14 */ + { 102, -1, 32 }, /* f15 */ + { 103, -1, 32 }, /* fcr */ + { 104, -1, 32 }, /* fsr */ +}; + +const struct rtos_register_stacking nuttx_esp32_stacking = { + .stack_registers_size = 26 * 4, + .stack_growth_direction = -1, + .num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_esp32), + .calculate_process_stack = rtos_generic_stack_align8, + .register_offsets = nuttx_stack_offsets_esp32, + .read_stack = nuttx_esp_xtensa_stack_read, +}; + +static const struct stack_register_offset nuttx_stack_offsets_esp32s2[] = { + { 0, 0x00, 32 }, /* PC */ + { 1, 0x08, 32 }, /* A0 */ + { 2, 0x0c, 32 }, /* A1 */ + { 3, 0x10, 32 }, /* A2 */ + { 4, 0x14, 32 }, /* A3 */ + { 5, 0x18, 32 }, /* A4 */ + { 6, 0x1c, 32 }, /* A5 */ + { 7, 0x20, 32 }, /* A6 */ + { 8, 0x24, 32 }, /* A7 */ + { 9, 0x28, 32 }, /* A8 */ + { 10, 0x2c, 32 }, /* A9 */ + { 11, 0x30, 32 }, /* A10 */ + { 12, 0x34, 32 }, /* A11 */ + { 13, 0x38, 32 }, /* A12 */ + { 14, 0x3c, 32 }, /* A13 */ + { 15, 0x40, 32 }, /* A14 */ + { 16, 0x44, 32 }, /* A15 */ + /* A16-A63 aren't in the stack frame because they've been flushed to the stack earlier */ + { 17, -1, 32 }, /* A16 */ + { 18, -1, 32 }, /* A17 */ + { 19, -1, 32 }, /* A18 */ + { 20, -1, 32 }, /* A19 */ + { 21, -1, 32 }, /* A20 */ + { 22, -1, 32 }, /* A21 */ + { 23, -1, 32 }, /* A22 */ + { 24, -1, 32 }, /* A23 */ + { 25, -1, 32 }, /* A24 */ + { 26, -1, 32 }, /* A25 */ + { 27, -1, 32 }, /* A26 */ + { 28, -1, 32 }, /* A27 */ + { 29, -1, 32 }, /* A28 */ + { 30, -1, 32 }, /* A29 */ + { 31, -1, 32 }, /* A30 */ + { 32, -1, 32 }, /* A31 */ + { 33, -1, 32 }, /* A32 */ + { 34, -1, 32 }, /* A33 */ + { 35, -1, 32 }, /* A34 */ + { 36, -1, 32 }, /* A35 */ + { 37, -1, 32 }, /* A36 */ + { 38, -1, 32 }, /* A37 */ + { 39, -1, 32 }, /* A38 */ + { 40, -1, 32 }, /* A39 */ + { 41, -1, 32 }, /* A40 */ + { 42, -1, 32 }, /* A41 */ + { 43, -1, 32 }, /* A42 */ + { 44, -1, 32 }, /* A43 */ + { 45, -1, 32 }, /* A44 */ + { 46, -1, 32 }, /* A45 */ + { 47, -1, 32 }, /* A46 */ + { 48, -1, 32 }, /* A47 */ + { 49, -1, 32 }, /* A48 */ + { 50, -1, 32 }, /* A49 */ + { 51, -1, 32 }, /* A50 */ + { 52, -1, 32 }, /* A51 */ + { 53, -1, 32 }, /* A52 */ + { 54, -1, 32 }, /* A53 */ + { 55, -1, 32 }, /* A54 */ + { 56, -1, 32 }, /* A55 */ + { 57, -1, 32 }, /* A56 */ + { 58, -1, 32 }, /* A57 */ + { 59, -1, 32 }, /* A58 */ + { 60, -1, 32 }, /* A59 */ + { 61, -1, 32 }, /* A60 */ + { 62, -1, 32 }, /* A61 */ + { 63, -1, 32 }, /* A62 */ + { 64, -1, 32 }, /* A63 */ + { 65, 0x48, 32 }, /* SAR */ + { 66, -1, 32 }, /* windowbase */ + { 67, -1, 32 }, /* windowstart */ + { 68, -1, 32 }, /* configid0 */ + { 69, -1, 32 }, /* configid1 */ + { 70, 0x04, 32 }, /* PS */ + { 71, -1, 32 }, /* threadptr */ + { 72, -1, 32 }, /* gpio_out */ +}; + +const struct rtos_register_stacking nuttx_esp32s2_stacking = { + .stack_registers_size = 25 * 4, + .stack_growth_direction = -1, + .num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_esp32s2), + .calculate_process_stack = rtos_generic_stack_align8, + .register_offsets = nuttx_stack_offsets_esp32s2, + .read_stack = nuttx_esp_xtensa_stack_read, +}; + +static const struct stack_register_offset nuttx_stack_offsets_esp32s3[] = { + { 0, 0x00, 32 }, /* PC */ + { 1, 0x08, 32 }, /* A0 */ + { 2, 0x0c, 32 }, /* A1 */ + { 3, 0x10, 32 }, /* A2 */ + { 4, 0x14, 32 }, /* A3 */ + { 5, 0x18, 32 }, /* A4 */ + { 6, 0x1c, 32 }, /* A5 */ + { 7, 0x20, 32 }, /* A6 */ + { 8, 0x24, 32 }, /* A7 */ + { 9, 0x28, 32 }, /* A8 */ + { 10, 0x2c, 32 }, /* A9 */ + { 11, 0x30, 32 }, /* A10 */ + { 12, 0x34, 32 }, /* A11 */ + { 13, 0x38, 32 }, /* A12 */ + { 14, 0x3c, 32 }, /* A13 */ + { 15, 0x40, 32 }, /* A14 */ + { 16, 0x44, 32 }, /* A15 */ + /* A16-A63 aren't in the stack frame because they've been flushed to the stack earlier */ + { 17, -1, 32 }, /* A16 */ + { 18, -1, 32 }, /* A17 */ + { 19, -1, 32 }, /* A18 */ + { 20, -1, 32 }, /* A19 */ + { 21, -1, 32 }, /* A20 */ + { 22, -1, 32 }, /* A21 */ + { 23, -1, 32 }, /* A22 */ + { 24, -1, 32 }, /* A23 */ + { 25, -1, 32 }, /* A24 */ + { 26, -1, 32 }, /* A25 */ + { 27, -1, 32 }, /* A26 */ + { 28, -1, 32 }, /* A27 */ + { 29, -1, 32 }, /* A28 */ + { 30, -1, 32 }, /* A29 */ + { 31, -1, 32 }, /* A30 */ + { 32, -1, 32 }, /* A31 */ + { 33, -1, 32 }, /* A32 */ + { 34, -1, 32 }, /* A33 */ + { 35, -1, 32 }, /* A34 */ + { 36, -1, 32 }, /* A35 */ + { 37, -1, 32 }, /* A36 */ + { 38, -1, 32 }, /* A37 */ + { 39, -1, 32 }, /* A38 */ + { 40, -1, 32 }, /* A39 */ + { 41, -1, 32 }, /* A40 */ + { 42, -1, 32 }, /* A41 */ + { 43, -1, 32 }, /* A42 */ + { 44, -1, 32 }, /* A43 */ + { 45, -1, 32 }, /* A44 */ + { 46, -1, 32 }, /* A45 */ + { 47, -1, 32 }, /* A46 */ + { 48, -1, 32 }, /* A47 */ + { 49, -1, 32 }, /* A48 */ + { 50, -1, 32 }, /* A49 */ + { 51, -1, 32 }, /* A50 */ + { 52, -1, 32 }, /* A51 */ + { 53, -1, 32 }, /* A52 */ + { 54, -1, 32 }, /* A53 */ + { 55, -1, 32 }, /* A54 */ + { 56, -1, 32 }, /* A55 */ + { 57, -1, 32 }, /* A56 */ + { 58, -1, 32 }, /* A57 */ + { 59, -1, 32 }, /* A58 */ + { 60, -1, 32 }, /* A59 */ + { 61, -1, 32 }, /* A60 */ + { 62, -1, 32 }, /* A61 */ + { 63, -1, 32 }, /* A62 */ + { 64, -1, 32 }, /* A63 */ + { 65, 0x58, 32 }, /* lbeg */ + { 66, 0x5c, 32 }, /* lend */ + { 67, 0x60, 32 }, /* lcount */ + { 68, 0x48, 32 }, /* SAR */ + { 69, -1, 32 }, /* windowbase */ + { 70, -1, 32 }, /* windowstart */ + { 71, -1, 32 }, /* configid0 */ + { 72, -1, 32 }, /* configid1 */ + { 73, 0x04, 32 }, /* PS */ + { 74, -1, 32 }, /* threadptr */ + { 75, -1, 32 }, /* br */ + { 76, 0x54, 32 }, /* scompare1 */ + { 77, -1, 32 }, /* acclo */ + { 78, -1, 32 }, /* acchi */ + { 79, -1, 32 }, /* m0 */ + { 80, -1, 32 }, /* m1 */ + { 81, -1, 32 }, /* m2 */ + { 82, -1, 32 }, /* m3 */ + { 83, -1, 32 }, /* gpio_out */ + { 84, -1, 32 }, /* f0 */ + { 85, -1, 32 }, /* f1 */ + { 86, -1, 32 }, /* f2 */ + { 87, -1, 32 }, /* f3 */ + { 88, -1, 32 }, /* f4 */ + { 89, -1, 32 }, /* f5 */ + { 90, -1, 32 }, /* f6 */ + { 91, -1, 32 }, /* f7 */ + { 92, -1, 32 }, /* f8 */ + { 93, -1, 32 }, /* f9 */ + { 94, -1, 32 }, /* f10 */ + { 95, -1, 32 }, /* f11 */ + { 96, -1, 32 }, /* f12 */ + { 97, -1, 32 }, /* f13 */ + { 98, -1, 32 }, /* f14 */ + { 99, -1, 32 }, /* f15 */ + { 100, -1, 32 }, /* fcr */ + { 101, -1, 32 }, /* fsr */ + { 102, -1, 32 }, /* accx_0 */ + { 103, -1, 32 }, /* accx_1 */ + { 104, -1, 32 }, /* qacc_h_0 */ + { 105, -1, 32 }, /* qacc_h_1 */ + { 106, -1, 32 }, /* qacc_h_2 */ + { 107, -1, 32 }, /* qacc_h_3 */ + { 108, -1, 32 }, /* qacc_h_4 */ + { 109, -1, 32 }, /* qacc_l_0 */ + { 110, -1, 32 }, /* qacc_l_1 */ + { 111, -1, 32 }, /* qacc_l_2 */ + { 112, -1, 32 }, /* qacc_l_3 */ + { 113, -1, 32 }, /* qacc_l_4 */ + { 114, -1, 32 }, /* sar_byte */ + { 115, -1, 32 }, /* fft_bit_width */ + { 116, -1, 32 }, /* ua_state_0 */ + { 117, -1, 32 }, /* ua_state_1 */ + { 118, -1, 32 }, /* ua_state_2 */ + { 119, -1, 32 }, /* ua_state_3 */ + { 120, -1, 128 }, /* q0 */ + { 121, -1, 128 }, /* q1 */ + { 122, -1, 128 }, /* q2 */ + { 123, -1, 128 }, /* q3 */ + { 124, -1, 128 }, /* q4 */ + { 125, -1, 128 }, /* q5 */ + { 126, -1, 128 }, /* q6 */ + { 127, -1, 128 }, /* q7 */ +}; + +const struct rtos_register_stacking nuttx_esp32s3_stacking = { + .stack_registers_size = 26 * 4, + .stack_growth_direction = -1, + .num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_esp32s3), + .calculate_process_stack = rtos_generic_stack_align8, + .register_offsets = nuttx_stack_offsets_esp32s3, + .read_stack = nuttx_esp_xtensa_stack_read, +}; diff --git a/src/rtos/rtos_nuttx_stackings.h b/src/rtos/rtos_nuttx_stackings.h new file mode 100644 index 0000000000..213a060336 --- /dev/null +++ b/src/rtos/rtos_nuttx_stackings.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef INCLUDED_RTOS_NUTTX_STACKINGS_H +#define INCLUDED_RTOS_NUTTX_STACKINGS_H + +#include "rtos.h" + +extern const struct rtos_register_stacking nuttx_stacking_cortex_m; +extern const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu; +extern const struct rtos_register_stacking nuttx_riscv_stacking; +extern const struct rtos_register_stacking nuttx_esp32_stacking; +extern const struct rtos_register_stacking nuttx_esp32s2_stacking; +extern const struct rtos_register_stacking nuttx_esp32s3_stacking; + +#endif /* INCLUDED_RTOS_NUTTX_STACKINGS_H */ diff --git a/src/rtos/rtos_riot_stackings.c b/src/rtos/rtos_riot_stackings.c index 84e1f7ff83..e467621684 100644 --- a/src/rtos/rtos_riot_stackings.c +++ b/src/rtos/rtos_riot_stackings.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2015 by Daniel Krebs * * Daniel Krebs - github@daniel-krebs.net * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -23,6 +12,7 @@ #include "rtos.h" #include "target/armv7m.h" #include "rtos_standard_stackings.h" +#include "rtos_riot_stackings.h" /* This works for the M0 and M34 stackings as xPSR is in a fixed * location @@ -54,7 +44,7 @@ static const struct stack_register_offset rtos_riot_cortex_m0_stack_offsets[ARMV { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x38, 32 }, /* lr */ { ARMV7M_PC, 0x3c, 32 }, /* pc */ - { ARMV7M_xPSR, 0x40, 32 }, /* xPSR */ + { ARMV7M_XPSR, 0x40, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_riot_cortex_m0_stacking = { @@ -83,7 +73,7 @@ static const struct stack_register_offset rtos_riot_cortex_m34_stack_offsets[ARM { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x38, 32 }, /* lr */ { ARMV7M_PC, 0x3c, 32 }, /* pc */ - { ARMV7M_xPSR, 0x40, 32 }, /* xPSR */ + { ARMV7M_XPSR, 0x40, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_riot_cortex_m34_stacking = { diff --git a/src/rtos/rtos_riot_stackings.h b/src/rtos/rtos_riot_stackings.h index c5b8f59e23..ebd5337568 100644 --- a/src/rtos/rtos_riot_stackings.h +++ b/src/rtos/rtos_riot_stackings.h @@ -1,32 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2015 by Daniel Krebs * * Daniel Krebs - github@daniel-krebs.net * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_RTOS_RTOS_RIOT_STACKINGS_H #define OPENOCD_RTOS_RTOS_RIOT_STACKINGS_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "rtos.h" extern const struct rtos_register_stacking rtos_riot_cortex_m0_stacking; extern const struct rtos_register_stacking rtos_riot_cortex_m34_stacking; #endif /* OPENOCD_RTOS_RTOS_RIOT_STACKINGS_H */ - diff --git a/src/rtos/rtos_standard_stackings.c b/src/rtos/rtos_standard_stackings.c index d338a479f0..0ca664fdb1 100644 --- a/src/rtos/rtos_standard_stackings.c +++ b/src/rtos/rtos_standard_stackings.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -23,6 +12,7 @@ #include "rtos.h" #include "target/armv7m.h" #include "target/riscv/riscv.h" +#include "rtos_standard_stackings.h" static const struct stack_register_offset rtos_standard_cortex_m3_stack_offsets[ARMV7M_NUM_CORE_REGS] = { { ARMV7M_R0, 0x20, 32 }, /* r0 */ @@ -41,7 +31,7 @@ static const struct stack_register_offset rtos_standard_cortex_m3_stack_offsets[ { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x34, 32 }, /* lr */ { ARMV7M_PC, 0x38, 32 }, /* pc */ - { ARMV7M_xPSR, 0x3c, 32 }, /* xPSR */ + { ARMV7M_XPSR, 0x3c, 32 }, /* xPSR */ }; static const struct stack_register_offset rtos_standard_cortex_m4f_stack_offsets[] = { @@ -61,7 +51,7 @@ static const struct stack_register_offset rtos_standard_cortex_m4f_stack_offsets { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x38, 32 }, /* lr */ { ARMV7M_PC, 0x3c, 32 }, /* pc */ - { ARMV7M_xPSR, 0x40, 32 }, /* xPSR */ + { ARMV7M_XPSR, 0x40, 32 }, /* xPSR */ }; static const struct stack_register_offset rtos_standard_cortex_m4f_fpu_stack_offsets[] = { @@ -81,7 +71,7 @@ static const struct stack_register_offset rtos_standard_cortex_m4f_fpu_stack_off { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x78, 32 }, /* lr */ { ARMV7M_PC, 0x7c, 32 }, /* pc */ - { ARMV7M_xPSR, 0x80, 32 }, /* xPSR */ + { ARMV7M_XPSR, 0x80, 32 }, /* xPSR */ }; @@ -114,45 +104,6 @@ static const struct stack_register_offset rtos_standard_cortex_r4_stack_offsets[ { 26, 0x04, 32 }, /* CSPR */ }; -static const struct stack_register_offset rtos_standard_nds32_n1068_stack_offsets[] = { - { 0, 0x88, 32 }, /* R0 */ - { 1, 0x8C, 32 }, /* R1 */ - { 2, 0x14, 32 }, /* R2 */ - { 3, 0x18, 32 }, /* R3 */ - { 4, 0x1C, 32 }, /* R4 */ - { 5, 0x20, 32 }, /* R5 */ - { 6, 0x24, 32 }, /* R6 */ - { 7, 0x28, 32 }, /* R7 */ - { 8, 0x2C, 32 }, /* R8 */ - { 9, 0x30, 32 }, /* R9 */ - { 10, 0x34, 32 }, /* R10 */ - { 11, 0x38, 32 }, /* R11 */ - { 12, 0x3C, 32 }, /* R12 */ - { 13, 0x40, 32 }, /* R13 */ - { 14, 0x44, 32 }, /* R14 */ - { 15, 0x48, 32 }, /* R15 */ - { 16, 0x4C, 32 }, /* R16 */ - { 17, 0x50, 32 }, /* R17 */ - { 18, 0x54, 32 }, /* R18 */ - { 19, 0x58, 32 }, /* R19 */ - { 20, 0x5C, 32 }, /* R20 */ - { 21, 0x60, 32 }, /* R21 */ - { 22, 0x64, 32 }, /* R22 */ - { 23, 0x68, 32 }, /* R23 */ - { 24, 0x6C, 32 }, /* R24 */ - { 25, 0x70, 32 }, /* R25 */ - { 26, 0x74, 32 }, /* R26 */ - { 27, 0x78, 32 }, /* R27 */ - { 28, 0x7C, 32 }, /* R28 */ - { 29, 0x80, 32 }, /* R29 */ - { 30, 0x84, 32 }, /* R30 (LP) */ - { 31, 0x00, 32 }, /* R31 (SP) */ - { 32, 0x04, 32 }, /* PSW */ - { 33, 0x08, 32 }, /* IPC */ - { 34, 0x0C, 32 }, /* IPSW */ - { 35, 0x10, 32 }, /* IFC_LP */ -}; - static const struct stack_register_offset rtos_metal_rv32_stack_offsets[] = { /* zero isn't on the stack. By making its offset -1 we leave the value at 0 * inside rtos_generic_stack_read(). */ @@ -447,14 +398,6 @@ const struct rtos_register_stacking rtos_standard_cortex_r4_stacking = { .register_offsets = rtos_standard_cortex_r4_stack_offsets }; -const struct rtos_register_stacking rtos_standard_nds32_n1068_stacking = { - .stack_registers_size = 0x90, - .stack_growth_direction = -1, - .num_output_registers = 32, - .calculate_process_stack = rtos_generic_stack_align8, - .register_offsets = rtos_standard_nds32_n1068_stack_offsets -}; - const struct rtos_register_stacking rtos_metal_rv32_stacking = { .stack_registers_size = (32 + 2) * 4, .stack_growth_direction = -1, diff --git a/src/rtos/rtos_standard_stackings.h b/src/rtos/rtos_standard_stackings.h index 71118fd403..40a3503a27 100644 --- a/src/rtos/rtos_standard_stackings.h +++ b/src/rtos/rtos_standard_stackings.h @@ -1,35 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_RTOS_RTOS_STANDARD_STACKINGS_H #define OPENOCD_RTOS_RTOS_STANDARD_STACKINGS_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "rtos.h" extern const struct rtos_register_stacking rtos_standard_cortex_m3_stacking; extern const struct rtos_register_stacking rtos_standard_cortex_m4f_stacking; extern const struct rtos_register_stacking rtos_standard_cortex_m4f_fpu_stacking; extern const struct rtos_register_stacking rtos_standard_cortex_r4_stacking; -extern const struct rtos_register_stacking rtos_standard_nds32_n1068_stacking; target_addr_t rtos_generic_stack_align8(struct target *target, const uint8_t *stack_data, const struct rtos_register_stacking *stacking, target_addr_t stack_ptr); diff --git a/src/rtos/rtos_ucos_iii_stackings.c b/src/rtos/rtos_ucos_iii_stackings.c index 0d533b55e3..f1e248231e 100644 --- a/src/rtos/rtos_ucos_iii_stackings.c +++ b/src/rtos/rtos_ucos_iii_stackings.c @@ -1,30 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2017 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include <helper/types.h> -#include <rtos/rtos.h> -#include <rtos/rtos_standard_stackings.h> -#include <target/armv7m.h> -#include <target/esirisc.h> +#include "rtos.h" +#include "target/armv7m.h" +#include "target/esirisc.h" +#include "rtos_standard_stackings.h" +#include "rtos_ucos_iii_stackings.h" static const struct stack_register_offset rtos_ucos_iii_cortex_m_stack_offsets[] = { { ARMV7M_R0, 0x20, 32 }, /* r0 */ @@ -43,7 +32,7 @@ static const struct stack_register_offset rtos_ucos_iii_cortex_m_stack_offsets[] { ARMV7M_R13, -2, 32 }, /* sp */ { ARMV7M_R14, 0x34, 32 }, /* lr */ { ARMV7M_PC, 0x38, 32 }, /* pc */ - { ARMV7M_xPSR, 0x3c, 32 }, /* xPSR */ + { ARMV7M_XPSR, 0x3c, 32 }, /* xPSR */ }; static const struct stack_register_offset rtos_ucos_iii_esi_risc_stack_offsets[] = { diff --git a/src/rtos/rtos_ucos_iii_stackings.h b/src/rtos/rtos_ucos_iii_stackings.h index f2f120fd9f..dfe60b27b4 100644 --- a/src/rtos/rtos_ucos_iii_stackings.h +++ b/src/rtos/rtos_ucos_iii_stackings.h @@ -1,29 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2017 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H #define OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <rtos/rtos.h> +#include "rtos.h" extern const struct rtos_register_stacking rtos_ucos_iii_cortex_m_stacking; extern const struct rtos_register_stacking rtos_ucos_iii_esi_risc_stacking; diff --git a/src/rtos/uCOS-III.c b/src/rtos/uCOS-III.c index 385c8d8411..4d704a44fe 100644 --- a/src/rtos/uCOS-III.c +++ b/src/rtos/uCOS-III.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2017 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -40,6 +29,12 @@ struct ucos_iii_params { const char *target_name; const unsigned char pointer_width; + size_t threadid_start; + const struct rtos_register_stacking *stacking_info; +}; + +struct ucos_iii_private { + const struct ucos_iii_params *params; symbol_address_t thread_stack_offset; symbol_address_t thread_name_offset; symbol_address_t thread_state_offset; @@ -47,40 +42,22 @@ struct ucos_iii_params { symbol_address_t thread_prev_offset; symbol_address_t thread_next_offset; bool thread_offsets_updated; - size_t threadid_start; - const struct rtos_register_stacking *stacking_info; size_t num_threads; - symbol_address_t threads[]; + symbol_address_t threads[UCOS_III_MAX_THREADS]; }; static const struct ucos_iii_params ucos_iii_params_list[] = { { - "cortex_m", /* target_name */ - sizeof(uint32_t), /* pointer_width */ - 0, /* thread_stack_offset */ - 0, /* thread_name_offset */ - 0, /* thread_state_offset */ - 0, /* thread_priority_offset */ - 0, /* thread_prev_offset */ - 0, /* thread_next_offset */ - false, /* thread_offsets_updated */ - 1, /* threadid_start */ - &rtos_ucos_iii_cortex_m_stacking, /* stacking_info */ - 0, /* num_threads */ + .target_name = "cortex_m", + .pointer_width = sizeof(uint32_t), + .threadid_start = 1, + .stacking_info = &rtos_ucos_iii_cortex_m_stacking, }, { - "esirisc", /* target_name */ - sizeof(uint32_t), /* pointer_width */ - 0, /* thread_stack_offset */ - 0, /* thread_name_offset */ - 0, /* thread_state_offset */ - 0, /* thread_priority_offset */ - 0, /* thread_prev_offset */ - 0, /* thread_next_offset */ - false, /* thread_offsets_updated */ - 1, /* threadid_start */ - &rtos_ucos_iii_esi_risc_stacking, /* stacking_info */ - 0, /* num_threads */ + .target_name = "esirisc", + .pointer_width = sizeof(uint32_t), + .threadid_start = 1, + .stacking_info = &rtos_ucos_iii_esi_risc_stacking, }, }; @@ -129,7 +106,7 @@ static const char * const ucos_iii_thread_state_list[] = { static int ucos_iii_find_or_create_thread(struct rtos *rtos, symbol_address_t thread_address, threadid_t *threadid) { - struct ucos_iii_params *params = rtos->rtos_specific_params; + struct ucos_iii_private *params = rtos->rtos_specific_params; size_t thread_index; for (thread_index = 0; thread_index < params->num_threads; thread_index++) @@ -144,17 +121,17 @@ static int ucos_iii_find_or_create_thread(struct rtos *rtos, symbol_address_t th params->threads[thread_index] = thread_address; params->num_threads++; found: - *threadid = thread_index + params->threadid_start; + *threadid = thread_index + params->params->threadid_start; return ERROR_OK; } static int ucos_iii_find_thread_address(struct rtos *rtos, threadid_t threadid, symbol_address_t *thread_address) { - struct ucos_iii_params *params = rtos->rtos_specific_params; + struct ucos_iii_private *params = rtos->rtos_specific_params; size_t thread_index; - thread_index = threadid - params->threadid_start; + thread_index = threadid - params->params->threadid_start; if (thread_index >= params->num_threads) { LOG_ERROR("uCOS-III: failed to find thread address"); return ERROR_FAIL; @@ -166,7 +143,7 @@ static int ucos_iii_find_thread_address(struct rtos *rtos, threadid_t threadid, static int ucos_iii_find_last_thread_address(struct rtos *rtos, symbol_address_t *thread_address) { - struct ucos_iii_params *params = rtos->rtos_specific_params; + struct ucos_iii_private *params = rtos->rtos_specific_params; int retval; /* read the thread list head */ @@ -174,7 +151,7 @@ static int ucos_iii_find_last_thread_address(struct rtos *rtos, symbol_address_t retval = target_read_memory(rtos->target, rtos->symbols[UCOS_III_VAL_OS_TASK_DBG_LIST_PTR].address, - params->pointer_width, + params->params->pointer_width, 1, (void *)&thread_list_address); if (retval != ERROR_OK) { @@ -188,7 +165,7 @@ static int ucos_iii_find_last_thread_address(struct rtos *rtos, symbol_address_t retval = target_read_memory(rtos->target, thread_list_address + params->thread_next_offset, - params->pointer_width, + params->params->pointer_width, 1, (void *)&thread_list_address); if (retval != ERROR_OK) { @@ -202,7 +179,7 @@ static int ucos_iii_find_last_thread_address(struct rtos *rtos, symbol_address_t static int ucos_iii_update_thread_offsets(struct rtos *rtos) { - struct ucos_iii_params *params = rtos->rtos_specific_params; + struct ucos_iii_private *params = rtos->rtos_specific_params; if (params->thread_offsets_updated) return ERROR_OK; @@ -242,7 +219,7 @@ static int ucos_iii_update_thread_offsets(struct rtos *rtos) int retval = target_read_memory(rtos->target, rtos->symbols[thread_offset_map->symbol_value].address, - params->pointer_width, + params->params->pointer_width, 1, (void *)thread_offset_map->thread_offset); if (retval != ERROR_OK) { @@ -263,7 +240,7 @@ static bool ucos_iii_detect_rtos(struct target *target) static int ucos_iii_reset_handler(struct target *target, enum target_reset_mode reset_mode, void *priv) { - struct ucos_iii_params *params = target->rtos->rtos_specific_params; + struct ucos_iii_private *params = target->rtos->rtos_specific_params; params->thread_offsets_updated = false; params->num_threads = 0; @@ -273,17 +250,17 @@ static int ucos_iii_reset_handler(struct target *target, enum target_reset_mode static int ucos_iii_create(struct target *target) { - struct ucos_iii_params *params; + struct ucos_iii_private *params; for (size_t i = 0; i < ARRAY_SIZE(ucos_iii_params_list); i++) if (strcmp(ucos_iii_params_list[i].target_name, target->type->name) == 0) { - params = malloc(sizeof(*params) + (UCOS_III_MAX_THREADS * sizeof(*params->threads))); + params = calloc(1, sizeof(*params)); if (!params) { LOG_ERROR("uCOS-III: out of memory"); return ERROR_FAIL; } - memcpy(params, &ucos_iii_params_list[i], sizeof(ucos_iii_params_list[i])); + params->params = &ucos_iii_params_list[i]; target->rtos->rtos_specific_params = (void *)params; target_register_reset_callback(ucos_iii_reset_handler, NULL); @@ -297,7 +274,7 @@ static int ucos_iii_create(struct target *target) static int ucos_iii_update_threads(struct rtos *rtos) { - struct ucos_iii_params *params = rtos->rtos_specific_params; + struct ucos_iii_private *params = rtos->rtos_specific_params; int retval; if (!rtos->symbols) { @@ -351,7 +328,7 @@ static int ucos_iii_update_threads(struct rtos *rtos) retval = target_read_memory(rtos->target, rtos->symbols[UCOS_III_VAL_OS_TCB_CUR_PTR].address, - params->pointer_width, + params->params->pointer_width, 1, (void *)¤t_thread_address); if (retval != ERROR_OK) { @@ -407,7 +384,7 @@ static int ucos_iii_update_threads(struct rtos *rtos) retval = target_read_memory(rtos->target, thread_address + params->thread_name_offset, - params->pointer_width, + params->params->pointer_width, 1, (void *)&thread_name_address); if (retval != ERROR_OK) { @@ -461,7 +438,7 @@ static int ucos_iii_update_threads(struct rtos *rtos) /* read previous thread address */ retval = target_read_memory(rtos->target, thread_address + params->thread_prev_offset, - params->pointer_width, + params->params->pointer_width, 1, (void *)&thread_address); if (retval != ERROR_OK) { @@ -476,7 +453,7 @@ static int ucos_iii_update_threads(struct rtos *rtos) static int ucos_iii_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, struct rtos_reg **reg_list, int *num_regs) { - struct ucos_iii_params *params = rtos->rtos_specific_params; + struct ucos_iii_private *params = rtos->rtos_specific_params; int retval; /* find thread address for threadid */ @@ -493,7 +470,7 @@ static int ucos_iii_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, retval = target_read_memory(rtos->target, thread_address + params->thread_stack_offset, - params->pointer_width, + params->params->pointer_width, 1, (void *)&stack_address); if (retval != ERROR_OK) { @@ -502,7 +479,7 @@ static int ucos_iii_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, } return rtos_generic_stack_read(rtos->target, - params->stacking_info, + params->params->stacking_info, stack_address, reg_list, num_regs); diff --git a/src/rtos/zephyr.c b/src/rtos/zephyr.c index 7f3325fead..a4c60904b5 100644 --- a/src/rtos/zephyr.c +++ b/src/rtos/zephyr.c @@ -1,11 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2017 by Intel Corporation * Leandro Pereira <leandro.pereira@intel.com> * Daniel Glöckner <dg@emlix.com>* * Copyright (C) 2021 by Synopsys, Inc. * Evgeniy Didin <didin@synopsys.com> - * * - * SPDX-License-Identifier: GPL-2.0-or-later * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -57,6 +57,7 @@ enum zephyr_offsets { OFFSET_T_ARCH, OFFSET_T_PREEMPT_FLOAT, OFFSET_T_COOP_FLOAT, + OFFSET_T_ARM_EXC_RETURN, OFFSET_MAX }; @@ -136,7 +137,7 @@ static const struct stack_register_offset arm_cpu_saved[] = { { ARMV7M_R13, -2, 32 }, { ARMV7M_R14, 20, 32 }, { ARMV7M_PC, 24, 32 }, - { ARMV7M_xPSR, 28, 32 }, + { ARMV7M_XPSR, 28, 32 }, }; static struct stack_register_offset arc_cpu_saved[] = { @@ -785,7 +786,7 @@ static int zephyr_get_symbol_list_to_lookup(struct symbol_table_elem **symbol_li return ERROR_OK; } -struct rtos_type zephyr_rtos = { +const struct rtos_type zephyr_rtos = { .name = "Zephyr", .detect_rtos = zephyr_detect_rtos, diff --git a/src/rtt/Makefile.am b/src/rtt/Makefile.am index e3fcefdbf8..99685547a1 100644 --- a/src/rtt/Makefile.am +++ b/src/rtt/Makefile.am @@ -1,2 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/librtt.la %C%_librtt_la_SOURCES = %D%/rtt.c %D%/rtt.h %D%/tcl.c diff --git a/src/rtt/rtt.c b/src/rtt/rtt.c index 3da3cce816..e31e75410d 100644 --- a/src/rtt/rtt.c +++ b/src/rtt/rtt.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de> - * - * 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/>. */ #ifdef HAVE_CONFIG_H diff --git a/src/rtt/rtt.h b/src/rtt/rtt.h index bc21bd0128..a5630a9515 100644 --- a/src/rtt/rtt.h +++ b/src/rtt/rtt.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de> - * - * 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/>. */ #ifndef OPENOCD_RTT_RTT_H diff --git a/src/rtt/tcl.c b/src/rtt/tcl.c index 4a34d8b981..2b8822fce8 100644 --- a/src/rtt/tcl.c +++ b/src/rtt/tcl.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright (C) 2019-2020 by Marc Schink <dev@zapb.de> - * - * 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/>. */ #ifdef HAVE_CONFIG_H @@ -28,7 +17,7 @@ COMMAND_HANDLER(handle_rtt_setup_command) { -struct rtt_source source; + struct rtt_source source; if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; @@ -161,17 +150,17 @@ COMMAND_HANDLER(handle_rtt_channels_command) return ERROR_OK; } -static int jim_channel_list(Jim_Interp *interp, int argc, - Jim_Obj * const *argv) +COMMAND_HANDLER(handle_channel_list) { - Jim_Obj *list; - Jim_Obj *channel_list; char channel_name[CHANNEL_NAME_SIZE]; const struct rtt_control *ctrl; struct rtt_channel_info info; + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + if (!rtt_found_cb()) { - Jim_SetResultFormatted(interp, "rtt: Control block not available"); + command_print(CMD, "rtt: Control block not available"); return ERROR_FAIL; } @@ -180,81 +169,47 @@ static int jim_channel_list(Jim_Interp *interp, int argc, info.name = channel_name; info.name_length = sizeof(channel_name); - list = Jim_NewListObj(interp, NULL, 0); - channel_list = Jim_NewListObj(interp, NULL, 0); + command_print(CMD, "{"); for (unsigned int i = 0; i < ctrl->num_up_channels; i++) { - int ret; - Jim_Obj *tmp; - - ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info); - + int ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info); if (ret != ERROR_OK) return ret; if (!info.size) continue; - tmp = Jim_NewListObj(interp, NULL, 0); - - Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, - "name", -1)); - Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, - info.name, -1)); - - Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, - "size", -1)); - Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp, - info.size)); - - Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, - "flags", -1)); - Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp, - info.flags)); - - Jim_ListAppendElement(interp, channel_list, tmp); + command_print(CMD, + " {\n" + " name %s\n" + " size 0x%" PRIx32 "\n" + " flags 0x%" PRIx32 "\n" + " }", + info.name, info.size, info.flags); } - Jim_ListAppendElement(interp, list, channel_list); - - channel_list = Jim_NewListObj(interp, NULL, 0); + command_print(CMD, "}\n{"); for (unsigned int i = 0; i < ctrl->num_down_channels; i++) { - int ret; - Jim_Obj *tmp; - - ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info); - + int ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info); if (ret != ERROR_OK) return ret; if (!info.size) continue; - tmp = Jim_NewListObj(interp, NULL, 0); - - Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, - "name", -1)); - Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, - info.name, -1)); - - Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, - "size", -1)); - Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp, - info.size)); - - Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, - "flags", -1)); - Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp, - info.flags)); - - Jim_ListAppendElement(interp, channel_list, tmp); + command_print(CMD, + " {\n" + " name %s\n" + " size 0x%" PRIx32 "\n" + " flags 0x%" PRIx32 "\n" + " }", + info.name, info.size, info.flags); } - Jim_ListAppendElement(interp, list, channel_list); - Jim_SetResult(interp, list); + command_print(CMD, "}"); - return JIM_OK; + return ERROR_OK; } static const struct command_registration rtt_subcommand_handlers[] = { @@ -295,7 +250,7 @@ static const struct command_registration rtt_subcommand_handlers[] = { }, { .name = "channellist", - .jim_handler = jim_channel_list, + .handler = handle_channel_list, .mode = COMMAND_EXEC, .help = "list available channels", .usage = "" diff --git a/src/server/Makefile.am b/src/server/Makefile.am index e3699f181b..13a5914093 100644 --- a/src/server/Makefile.am +++ b/src/server/Makefile.am @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libserver.la %C%_libserver_la_SOURCES = \ %D%/server.c \ diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 086fd11217..4bab5e5cf3 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -19,19 +21,6 @@ * * * Copyright (C) 2013 Franck Jullien * * elec4fun@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -106,6 +95,8 @@ struct gdb_connection { char *thread_list; /* flag to mask the output from gdb_log_callback() */ enum gdb_output_flag output_flag; + /* Unique index for this GDB connection. */ + unsigned int unique_index; }; #if 0 @@ -128,7 +119,7 @@ static void gdb_sig_halted(struct connection *connection); /* number of gdb connections, mainly to suppress gdb related debugging spam * in helper/log.c when no gdb connections are actually active */ -int gdb_actual_connections; +static int gdb_actual_connections; /* set if we are sending a memory map to gdb * via qXfer:memory-map:read packet */ @@ -154,8 +145,52 @@ static int gdb_use_target_description = 1; /* current processing free-run type, used by file-I/O */ static char gdb_running_type; +/* Find an available target in the SMP group that gdb is connected to. For + * commands that affect an entire SMP group (like memory access and run control) + * this will give better results than returning the unavailable target and having + * the command fail. If gdb was aware that targets can be unavailable we + * wouldn't need this logic. + */ +struct target *get_available_target_from_connection(struct connection *connection) +{ + struct gdb_service *gdb_service = connection->service->priv; + struct target *target = gdb_service->target; + if (target->state == TARGET_UNAVAILABLE && target->smp) { + struct target_list *tlist; + foreach_smp_target(tlist, target->smp_targets) { + struct target *t = tlist->target; + if (t->state != TARGET_UNAVAILABLE) + return t; + } + /* If we can't find an available target, just return the + * original. */ + } + return target; +} + +/** Return true iff the given connection includes the given target. */ +static bool gdb_connection_includes_target(struct connection *connection, struct target *target) +{ + struct gdb_service *gdb_service = connection->service->priv; + struct target *service_target = gdb_service->target; + if (service_target->smp) { + struct target_list *tlist; + foreach_smp_target(tlist, service_target->smp_targets) { + struct target *t = tlist->target; + if (t == target) + return true; + } + return false; + } + /* Non-SMP target. */ + return service_target == target; +} + static int gdb_last_signal(struct target *target) { + LOG_TARGET_DEBUG(target, "Debug reason is: %s", + target_debug_reason_str(target->debug_reason)); + switch (target->debug_reason) { case DBG_REASON_DBGRQ: return 0x2; /* SIGINT */ @@ -170,8 +205,9 @@ static int gdb_last_signal(struct target *target) case DBG_REASON_NOTHALTED: return 0x0; /* no signal... shouldn't happen */ default: - LOG_USER("undefined debug reason %d - target needs reset", - target->debug_reason); + LOG_USER("undefined debug reason %d (%s) - target needs reset", + target->debug_reason, + target_debug_reason_str(target->debug_reason)); return 0x0; } } @@ -242,39 +278,20 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char) } #ifdef _WIN32 - errno = WSAGetLastError(); - - switch (errno) { - case WSAEWOULDBLOCK: - usleep(1000); - break; - case WSAECONNABORTED: - gdb_con->closed = true; - return ERROR_SERVER_REMOTE_CLOSED; - case WSAECONNRESET: - gdb_con->closed = true; - return ERROR_SERVER_REMOTE_CLOSED; - default: - LOG_ERROR("read: %d", errno); - exit(-1); - } + bool retry = (WSAGetLastError() == WSAEWOULDBLOCK); #else - switch (errno) { - case EAGAIN: - usleep(1000); - break; - case ECONNABORTED: - gdb_con->closed = true; - return ERROR_SERVER_REMOTE_CLOSED; - case ECONNRESET: - gdb_con->closed = true; - return ERROR_SERVER_REMOTE_CLOSED; - default: - LOG_ERROR("read: %s", strerror(errno)); - gdb_con->closed = true; - return ERROR_SERVER_REMOTE_CLOSED; - } + bool retry = (errno == EAGAIN); #endif + + if (retry) { + // Try again after a delay + usleep(1000); + } else { + // Print error and close the socket + log_socket_error("GDB"); + gdb_con->closed = true; + return ERROR_SERVER_REMOTE_CLOSED; + } } #ifdef _DEBUG_GDB_IO_ @@ -377,6 +394,7 @@ static void gdb_log_incoming_packet(struct connection *connection, char *packet) return; struct target *target = get_target_from_connection(connection); + struct gdb_connection *gdb_connection = connection->priv; /* Avoid dumping non-printable characters to the terminal */ const unsigned packet_len = strlen(packet); @@ -391,14 +409,15 @@ static void gdb_log_incoming_packet(struct connection *connection, char *packet) if (packet_prefix_printable) { const unsigned int prefix_len = colon - packet + 1; /* + 1 to include the ':' */ const unsigned int payload_len = packet_len - prefix_len; - LOG_TARGET_DEBUG(target, "received packet: %.*s<binary-data-%u-bytes>", prefix_len, - packet, payload_len); + LOG_TARGET_DEBUG(target, "{%d} received packet: %.*s<binary-data-%u-bytes>", + gdb_connection->unique_index, prefix_len, packet, payload_len); } else { - LOG_TARGET_DEBUG(target, "received packet: <binary-data-%u-bytes>", packet_len); + LOG_TARGET_DEBUG(target, "{%d} received packet: <binary-data-%u-bytes>", + gdb_connection->unique_index, packet_len); } } else { /* All chars printable, dump the packet as is */ - LOG_TARGET_DEBUG(target, "received packet: %s", packet); + LOG_TARGET_DEBUG(target, "{%d} received packet: %s", gdb_connection->unique_index, packet); } } @@ -409,13 +428,14 @@ static void gdb_log_outgoing_packet(struct connection *connection, char *packet_ return; struct target *target = get_target_from_connection(connection); + struct gdb_connection *gdb_connection = connection->priv; if (find_nonprint_char(packet_buf, packet_len)) - LOG_TARGET_DEBUG(target, "sending packet: $<binary-data-%u-bytes>#%2.2x", - packet_len, checksum); + LOG_TARGET_DEBUG(target, "{%d} sending packet: $<binary-data-%u-bytes>#%2.2x", + gdb_connection->unique_index, packet_len, checksum); else - LOG_TARGET_DEBUG(target, "sending packet: $%.*s#%2.2x", packet_len, packet_buf, - checksum); + LOG_TARGET_DEBUG(target, "{%d} sending packet: $%.*s#%2.2x", + gdb_connection->unique_index, packet_len, packet_buf, checksum); } static int gdb_put_packet_inner(struct connection *connection, @@ -814,6 +834,7 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio } if (gdb_connection->ctrl_c) { + LOG_TARGET_DEBUG(target, "Responding with signal 2 (SIGINT) to debugger due to Ctrl-C"); signal_var = 0x2; } else signal_var = gdb_last_signal(ct); @@ -976,9 +997,9 @@ static int gdb_target_callback_event_handler(struct target *target, enum target_event event, void *priv) { struct connection *connection = priv; - struct gdb_service *gdb_service = connection->service->priv; - if (gdb_service->target != target) + /* Propagate this event if it's for any of the targets on this gdb connection. */ + if (!gdb_connection_includes_target(connection, target)) return ERROR_OK; switch (event) { @@ -1001,6 +1022,7 @@ static int gdb_new_connection(struct connection *connection) struct target *target; int retval; int initial_ack; + static unsigned int next_unique_id = 1; target = get_target_from_connection(connection); connection->priv = gdb_connection; @@ -1023,6 +1045,7 @@ static int gdb_new_connection(struct connection *connection) gdb_connection->target_desc.tdesc_length = 0; gdb_connection->thread_list = NULL; gdb_connection->output_flag = GDB_OUTPUT_NO; + gdb_connection->unique_index = next_unique_id++; /* send ACK to GDB for debug request */ gdb_write(connection, "+", 1); @@ -1081,20 +1104,19 @@ static int gdb_new_connection(struct connection *connection) } } - gdb_actual_connections++; log_printf_lf(all_targets->next ? LOG_LVL_INFO : LOG_LVL_DEBUG, __FILE__, __LINE__, __func__, "New GDB Connection: %d, Target %s, state: %s", - gdb_actual_connections, + gdb_connection->unique_index, target_name(target), target_state_name(target)); if (!target_was_examined(target)) { LOG_ERROR("Target %s not examined yet, refuse gdb connection %d!", - target_name(target), gdb_actual_connections); - gdb_actual_connections--; + target_name(target), gdb_connection->unique_index); return ERROR_TARGET_NOT_EXAMINED; } + gdb_actual_connections++; if (target->state != TARGET_HALTED) LOG_WARNING("GDB connection %d on target %s not halted", @@ -1125,7 +1147,8 @@ static int gdb_connection_closed(struct connection *connection) log_remove_callback(gdb_log_callback, connection); gdb_actual_connections--; - LOG_DEBUG("GDB Close, Target: %s, state: %s, gdb_actual_connections=%d", + LOG_DEBUG("{%d} GDB Close, Target: %s, state: %s, gdb_actual_connections=%d", + gdb_connection->unique_index, target_name(target), target_state_name(target), gdb_actual_connections); @@ -1237,6 +1260,27 @@ static void gdb_target_to_reg(struct target *target, } } +/* get register value if needed and fill the buffer accordingly */ +static int gdb_get_reg_value_as_str(struct target *target, char *tstr, struct reg *reg) +{ + int retval = ERROR_OK; + + if (!reg->valid) + retval = reg->type->get(reg); + + const unsigned int len = DIV_ROUND_UP(reg->size, 8) * 2; + switch (retval) { + case ERROR_OK: + gdb_str_to_target(target, tstr, reg); + return ERROR_OK; + case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: + memset(tstr, 'x', len); + tstr[len] = '\0'; + return ERROR_OK; + } + return ERROR_FAIL; +} + static int gdb_get_registers_packet(struct connection *connection, char const *packet, int packet_size) { @@ -1278,16 +1322,11 @@ static int gdb_get_registers_packet(struct connection *connection, for (i = 0; i < reg_list_size; i++) { if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden) continue; - if (!reg_list[i]->valid) { - retval = reg_list[i]->type->get(reg_list[i]); - if (retval != ERROR_OK && gdb_report_register_access_error) { - LOG_DEBUG("Couldn't get register %s.", reg_list[i]->name); - free(reg_packet); - free(reg_list); - return gdb_error(connection, retval); - } + if (gdb_get_reg_value_as_str(target, reg_packet_p, reg_list[i]) != ERROR_OK) { + free(reg_packet); + free(reg_list); + return gdb_error(connection, retval); } - gdb_str_to_target(target, reg_packet_p, reg_list[i]); reg_packet_p += DIV_ROUND_UP(reg_list[i]->size, 8) * 2; } @@ -1339,6 +1378,8 @@ static int gdb_set_registers_packet(struct connection *connection, packet_p = packet; for (i = 0; i < reg_list_size; i++) { uint8_t *bin_buf; + if (!reg_list[i] || !reg_list[i]->exist || reg_list[i]->hidden) + continue; int chars = (DIV_ROUND_UP(reg_list[i]->size, 8) * 2); if (packet_p + chars > packet + packet_size) @@ -1383,31 +1424,32 @@ static int gdb_get_register_packet(struct connection *connection, LOG_DEBUG("-"); #endif - if ((target->rtos) && (rtos_get_gdb_reg(connection, reg_num) == ERROR_OK)) - return ERROR_OK; + if (target->rtos) { + retval = rtos_get_gdb_reg(connection, reg_num); + if (retval == ERROR_OK) + return ERROR_OK; + if (retval != ERROR_NOT_IMPLEMENTED) + return gdb_error(connection, retval); + } retval = target_get_gdb_reg_list_noread(target, ®_list, ®_list_size, REG_CLASS_ALL); if (retval != ERROR_OK) return gdb_error(connection, retval); - if (reg_list_size <= reg_num) { + if ((reg_list_size <= reg_num) || !reg_list[reg_num] || + !reg_list[reg_num]->exist || reg_list[reg_num]->hidden) { LOG_ERROR("gdb requested a non-existing register (reg_num=%d)", reg_num); - return ERROR_SERVER_REMOTE_CLOSED; - } - - if (!reg_list[reg_num]->valid) { - retval = reg_list[reg_num]->type->get(reg_list[reg_num]); - if (retval != ERROR_OK && gdb_report_register_access_error) { - LOG_DEBUG("Couldn't get register %s.", reg_list[reg_num]->name); - free(reg_list); - return gdb_error(connection, retval); - } + return gdb_error(connection, ERROR_FAIL); } reg_packet = calloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1, 1); /* plus one for string termination null */ - gdb_str_to_target(target, reg_packet, reg_list[reg_num]); + if (gdb_get_reg_value_as_str(target, reg_packet, reg_list[reg_num]) != ERROR_OK) { + free(reg_packet); + free(reg_list); + return gdb_error(connection, retval); + } gdb_put_packet(connection, reg_packet, DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2); @@ -1453,7 +1495,8 @@ static int gdb_set_register_packet(struct connection *connection, return gdb_error(connection, retval); } - if (reg_list_size <= reg_num) { + if ((reg_list_size <= reg_num) || !reg_list[reg_num] || + !reg_list[reg_num]->exist || reg_list[reg_num]->hidden) { LOG_ERROR("gdb requested a non-existing register (reg_num=%d)", reg_num); free(bin_buf); free(reg_list); @@ -1503,7 +1546,7 @@ static int gdb_error(struct connection *connection, int retval) static int gdb_read_memory_packet(struct connection *connection, char const *packet, int packet_size) { - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); char *separator; uint64_t addr = 0; uint32_t len = 0; @@ -1578,7 +1621,7 @@ static int gdb_read_memory_packet(struct connection *connection, static int gdb_write_memory_packet(struct connection *connection, char const *packet, int packet_size) { - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); char *separator; uint64_t addr = 0; uint32_t len = 0; @@ -1629,7 +1672,7 @@ static int gdb_write_memory_packet(struct connection *connection, static int gdb_write_memory_binary_packet(struct connection *connection, char const *packet, int packet_size) { - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); char *separator; uint64_t addr = 0; uint32_t len = 0; @@ -1708,7 +1751,7 @@ static int gdb_write_memory_binary_packet(struct connection *connection, static int gdb_step_continue_packet(struct connection *connection, char const *packet, int packet_size) { - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); int current = 0; uint64_t address = 0x0; int retval = ERROR_OK; @@ -1736,7 +1779,7 @@ static int gdb_step_continue_packet(struct connection *connection, static int gdb_breakpoint_watchpoint_packet(struct connection *connection, char const *packet, int packet_size) { - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); int type; enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */; enum watchpoint_rw wp_type = WPT_READ /* dummy init to avoid warning */; @@ -1785,8 +1828,17 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection, case 0: case 1: if (packet[0] == 'Z') { + struct target *bp_target = target; + if (target->rtos && bp_type == BKPT_SOFT) { + bp_target = rtos_swbp_target(target, address, size, bp_type); + if (!bp_target) + return ERROR_FAIL; + } retval = breakpoint_add(target, address, size, bp_type); - if (retval != ERROR_OK) { + if (retval == ERROR_NOT_IMPLEMENTED) { + /* Send empty reply to report that breakpoints of this type are not supported */ + gdb_put_packet(connection, "", 0); + } else if (retval != ERROR_OK) { retval = gdb_error(connection, retval); if (retval != ERROR_OK) return retval; @@ -1802,8 +1854,11 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection, case 4: { if (packet[0] == 'Z') { - retval = watchpoint_add(target, address, size, wp_type, 0, 0xffffffffu); - if (retval != ERROR_OK) { + retval = watchpoint_add(target, address, size, wp_type, 0, WATCHPOINT_IGNORE_DATA_VALUE_MASK); + if (retval == ERROR_NOT_IMPLEMENTED) { + /* Send empty reply to report that watchpoints of this type are not supported */ + gdb_put_packet(connection, "", 0); + } else if (retval != ERROR_OK) { retval = gdb_error(connection, retval); if (retval != ERROR_OK) return retval; @@ -1912,7 +1967,7 @@ static int gdb_memory_map(struct connection *connection, * have to regenerate it a couple of times. */ - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); struct flash_bank *p; char *xml = NULL; int size = 0; @@ -2354,6 +2409,7 @@ static int smp_reg_list_noread(struct target *target, local_list = realloc(local_list, combined_allocated * sizeof(struct reg *)); if (!local_list) { LOG_ERROR("realloc(%zu) failed", combined_allocated * sizeof(struct reg *)); + free(reg_list); return ERROR_FAIL; } } @@ -2973,13 +3029,19 @@ static int gdb_query_packet(struct connection *connection, gdb_connection->noack_mode = 1; gdb_put_packet(connection, "OK", 2); return ERROR_OK; + } else if (target->type->gdb_query_custom) { + char *buffer = NULL; + int ret = target->type->gdb_query_custom(target, packet, &buffer); + gdb_put_packet(connection, buffer, strlen(buffer)); + return ret; } gdb_put_packet(connection, "", 0); return ERROR_OK; } -static bool gdb_handle_vcont_packet(struct connection *connection, const char *packet, int packet_size) +static bool gdb_handle_vcont_packet(struct connection *connection, const char *packet, + __attribute__((unused)) int packet_size) { struct gdb_connection *gdb_connection = connection->priv; struct target *target = get_target_from_connection(connection); @@ -2998,12 +3060,29 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p if (parse[0] == ';') { ++parse; - --packet_size; } /* simple case, a continue packet */ if (parse[0] == 'c') { gdb_running_type = 'c'; + + if (target->state == TARGET_UNAVAILABLE) { + struct target *available_target = get_available_target_from_connection(connection); + if (target == available_target) { + LOG_DEBUG("All targets for this gdb connection " + "are unavailable. Fake to gdb that the resume " + "succeeded and the target is now running."); + gdb_connection->frontend_state = TARGET_RUNNING; + gdb_connection->output_flag = GDB_OUTPUT_ALL; + target_call_event_callbacks(target, TARGET_EVENT_GDB_START); + return true; + } + LOG_TARGET_DEBUG(target, "Target is unavailable. Resume %s instead.", + target_name(available_target)); + /* Resume an available target. */ + target = available_target; + } + LOG_DEBUG("target %s continue", target_name(target)); gdb_connection->output_flag = GDB_OUTPUT_ALL; retval = target_resume(target, 1, 0, 0, 0); @@ -3033,139 +3112,140 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p gdb_running_type = 's'; bool fake_step = false; - if (strncmp(parse, "s:", 2) == 0) { - struct target *ct = target; - int current_pc = 1; - int64_t thread_id; + struct target *ct = target; + int current_pc = 1; + int64_t thread_id; + parse++; + if (parse[0] == ':') { char *endp; - - parse += 2; - packet_size -= 2; - + parse++; thread_id = strtoll(parse, &endp, 16); if (endp) { - packet_size -= endp - parse; parse = endp; } + } else { + thread_id = 0; + } - if (target->rtos) { - /* FIXME: why is this necessary? rtos state should be up-to-date here already! */ - - /* Sometimes this results in picking a different thread than - * gdb just requested to step. Then we fake it, and now there's - * a different thread selected than gdb expects, so register - * accesses go to the wrong one! - * E.g.: - * Hg1$ - * P8=72101ce197869329$ # write r8 on thread 1 - * g$ - * vCont?$ - * vCont;s:1;c$ # rtos_update_threads changes to other thread - * g$ - * qXfer:threads:read::0,fff$ - * P8=cc060607eb89ca7f$ # write r8 on other thread - * g$ - * */ - /* rtos_update_threads(target); */ - - target->rtos->gdb_target_for_threadid(connection, thread_id, &ct); - - /* - * check if the thread to be stepped is the current rtos thread - * if not, we must fake the step - */ - fake_step = rtos_needs_fake_step(target, thread_id); - } + if (target->rtos) { + /* FIXME: why is this necessary? rtos state should be up-to-date here already! */ + + /* Sometimes this results in picking a different thread than + * gdb just requested to step. Then we fake it, and now there's + * a different thread selected than gdb expects, so register + * accesses go to the wrong one! + * E.g.: + * Hg1$ + * P8=72101ce197869329$ # write r8 on thread 1 + * g$ + * vCont?$ + * vCont;s:1;c$ # rtos_update_threads changes to other thread + * g$ + * qXfer:threads:read::0,fff$ + * P8=cc060607eb89ca7f$ # write r8 on other thread + * g$ + * */ + /* rtos_update_threads(target); */ + + target->rtos->gdb_target_for_threadid(connection, thread_id, &ct); + + /* + * check if the thread to be stepped is the current rtos thread + * if not, we must fake the step + */ + fake_step = rtos_needs_fake_step(target, thread_id); + } - if (parse[0] == ';') { - ++parse; - --packet_size; + if (parse[0] == ';') { + ++parse; - if (parse[0] == 'c') { + if (parse[0] == 'c') { + parse += 1; + + /* check if thread-id follows */ + if (parse[0] == ':') { + int64_t tid; parse += 1; - /* check if thread-id follows */ - if (parse[0] == ':') { - int64_t tid; - parse += 1; - - tid = strtoll(parse, &endp, 16); - if (tid == thread_id) { - /* - * Special case: only step a single thread (core), - * keep the other threads halted. Currently, only - * aarch64 target understands it. Other target types don't - * care (nobody checks the actual value of 'current') - * and it doesn't really matter. This deserves - * a symbolic constant and a formal interface documentation - * at a later time. - */ - LOG_DEBUG("request to step current core only"); - /* uncomment after checking that indeed other targets are safe */ - /*current_pc = 2;*/ - } + tid = strtoll(parse, NULL, 16); + if (tid == thread_id) { + /* + * Special case: only step a single thread (core), + * keep the other threads halted. Currently, only + * aarch64 target understands it. Other target types don't + * care (nobody checks the actual value of 'current') + * and it doesn't really matter. This deserves + * a symbolic constant and a formal interface documentation + * at a later time. + */ + LOG_DEBUG("request to step current core only"); + /* uncomment after checking that indeed other targets are safe */ + /*current_pc = 2;*/ } } } + } - LOG_DEBUG("target %s single-step thread %"PRIx64, target_name(ct), thread_id); - gdb_connection->output_flag = GDB_OUTPUT_ALL; - target_call_event_callbacks(ct, TARGET_EVENT_GDB_START); - - if (fake_step) { - /* We just fake the step to not trigger an internal error in - * gdb. See https://sourceware.org/bugzilla/show_bug.cgi?id=22925 - * for details. */ - int sig_reply_len; - char sig_reply[128]; + LOG_DEBUG("target %s single-step thread %"PRIx64, target_name(ct), thread_id); + gdb_connection->output_flag = GDB_OUTPUT_ALL; + target_call_event_callbacks(ct, TARGET_EVENT_GDB_START); - LOG_DEBUG("fake step thread %"PRIx64, thread_id); - target->rtos->current_threadid = thread_id; + if (fake_step) { + /* We just fake the step to not trigger an internal error in + * gdb. See https://sourceware.org/bugzilla/show_bug.cgi?id=22925 + * for details. */ + int sig_reply_len; + char sig_reply[128]; - sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), - "T05thread:%016"PRIx64";", thread_id); + LOG_DEBUG("fake step thread %"PRIx64, thread_id); + target->rtos->current_threadid = thread_id; - gdb_put_packet(connection, sig_reply, sig_reply_len); - gdb_connection->output_flag = GDB_OUTPUT_NO; + sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), + "T05thread:%016"PRIx64";", thread_id); - return true; - } - - /* support for gdb_sync command */ - if (gdb_connection->sync) { - gdb_connection->sync = false; - if (ct->state == TARGET_HALTED) { - LOG_DEBUG("stepi ignored. GDB will now fetch the register state " - "from the target."); - gdb_sig_halted(connection); - gdb_connection->output_flag = GDB_OUTPUT_NO; - } else - gdb_connection->frontend_state = TARGET_RUNNING; - return true; - } + gdb_put_packet(connection, sig_reply, sig_reply_len); + gdb_connection->output_flag = GDB_OUTPUT_NO; - retval = target_step(ct, current_pc, 0, 0); - if (retval == ERROR_TARGET_NOT_HALTED) - LOG_INFO("target %s was not halted when step was requested", target_name(ct)); + return true; + } - /* if step was successful send a reply back to gdb */ - if (retval == ERROR_OK) { - retval = target_poll(ct); - if (retval != ERROR_OK) - LOG_DEBUG("error polling target %s after successful step", target_name(ct)); - /* send back signal information */ - gdb_signal_reply(ct, connection); - /* stop forwarding log packets! */ + /* support for gdb_sync command */ + if (gdb_connection->sync) { + gdb_connection->sync = false; + if (ct->state == TARGET_HALTED) { + LOG_DEBUG("stepi ignored. GDB will now fetch the register state " + "from the target."); + gdb_sig_halted(connection); gdb_connection->output_flag = GDB_OUTPUT_NO; } else gdb_connection->frontend_state = TARGET_RUNNING; + return true; + } + + if (ct->state == TARGET_UNAVAILABLE) { + LOG_TARGET_ERROR(ct, "Target is unavailable, so cannot be stepped. " + "Pretending to gdb that it is running until it's available again."); + retval = ERROR_FAIL; } else { - LOG_ERROR("Unknown vCont packet"); - return false; + retval = target_step(ct, current_pc, 0, 0); + if (retval == ERROR_TARGET_NOT_HALTED) + LOG_INFO("target %s was not halted when step was requested", target_name(ct)); } + + /* if step was successful send a reply back to gdb */ + if (retval == ERROR_OK) { + retval = target_poll(ct); + if (retval != ERROR_OK) + LOG_DEBUG("error polling target %s after successful step", target_name(ct)); + /* send back signal information */ + gdb_signal_reply(ct, connection); + /* stop forwarding log packets! */ + gdb_connection->output_flag = GDB_OUTPUT_NO; + } else + gdb_connection->frontend_state = TARGET_RUNNING; return true; } - + LOG_ERROR("Unknown vCont packet"); return false; } @@ -3221,7 +3301,7 @@ static void gdb_restart_inferior(struct connection *connection, const char *pack static bool gdb_handle_vrun_packet(struct connection *connection, const char *packet, int packet_size) { - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); const char *parse = packet; /* Skip "vRun" */ @@ -3267,7 +3347,7 @@ static int gdb_v_packet(struct connection *connection, struct gdb_connection *gdb_connection = connection->priv; int result; - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); if (strncmp(packet, "vCont", 5) == 0) { bool handled; @@ -3438,7 +3518,7 @@ static int gdb_detach(struct connection *connection) static int gdb_fileio_response_packet(struct connection *connection, char const *packet, int packet_size) { - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); char *separator; char *parsing_point; int fileio_retcode = strtoul(packet + 1, &separator, 16); @@ -3687,12 +3767,14 @@ static int gdb_input_inner(struct connection *connection) break; case 'j': + /* DEPRECATED */ /* packet supported only by smp target i.e cortex_a.c*/ /* handle smp packet replying coreid played to gbd */ gdb_read_smp_packet(connection, packet, packet_size); break; case 'J': + /* DEPRECATED */ /* packet supported only by smp target i.e cortex_a.c */ /* handle smp packet setting coreid to be played at next * resume to gdb */ @@ -3725,10 +3807,11 @@ static int gdb_input_inner(struct connection *connection) } if (gdb_con->ctrl_c) { - if (target->state == TARGET_RUNNING) { - struct target *t = target; - if (target->rtos) - target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &t); + struct target *available_target = get_available_target_from_connection(connection); + if (available_target->state == TARGET_RUNNING) { + struct target *t = available_target; + if (available_target->rtos) + available_target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &t); retval = target_halt(t); if (retval == ERROR_OK) retval = target_poll(t); @@ -3736,7 +3819,8 @@ static int gdb_input_inner(struct connection *connection) target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); gdb_con->ctrl_c = false; } else { - LOG_INFO("The target is not running when halt was requested, stopping GDB."); + LOG_TARGET_INFO(target, "Not running when halt was requested, stopping GDB. (state=%d)", + target->state); target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } } @@ -4116,14 +4200,13 @@ int gdb_register_commands(struct command_context *cmd_ctx) return register_commands(cmd_ctx, NULL, gdb_command_handlers); } -void gdb_set_frontend_state_running(struct connection *connection) -{ - struct gdb_connection *gdb_con = connection->priv; - gdb_con->frontend_state = TARGET_RUNNING; -} - void gdb_service_free(void) { free(gdb_port); free(gdb_port_next); } + +int gdb_get_actual_connections(void) +{ + return gdb_actual_connections; +} diff --git a/src/server/gdb_server.h b/src/server/gdb_server.h index 0c50836fbc..4288ceb878 100644 --- a/src/server/gdb_server.h +++ b/src/server/gdb_server.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -10,19 +12,6 @@ * * * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_SERVER_GDB_SERVER_H @@ -31,6 +20,7 @@ struct image; struct reg; #include <target/target.h> +#include <server/server.h> #define GDB_BUFFER_SIZE 16384 @@ -40,14 +30,14 @@ void gdb_service_free(void); int gdb_put_packet(struct connection *connection, char *buffer, int len); +int gdb_get_actual_connections(void); + static inline struct target *get_target_from_connection(struct connection *connection) { struct gdb_service *gdb_service = connection->service->priv; return gdb_service->target; } -void gdb_set_frontend_state_running(struct connection *connection); - #define ERROR_GDB_BUFFER_TOO_SMALL (-800) #define ERROR_GDB_TIMEOUT (-801) diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c index 3bbcf07146..0733230322 100644 --- a/src/server/ipdbg.c +++ b/src/server/ipdbg.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later /* Copyright (C) 2020 by Daniel Anselmi <danselmi@gmx.ch> */ #ifdef HAVE_CONFIG_H @@ -10,15 +10,27 @@ #include <jtag/jtag.h> #include <server/server.h> #include <target/target.h> +#include <pld/pld.h> #include "ipdbg.h" #define IPDBG_BUFFER_SIZE 16384 -#define IPDBG_MIN_NUM_OF_OPTIONS 4 +#define IPDBG_MIN_NUM_OF_OPTIONS 2 #define IPDBG_MAX_NUM_OF_OPTIONS 14 #define IPDBG_MIN_DR_LENGTH 11 #define IPDBG_MAX_DR_LENGTH 13 #define IPDBG_TCP_PORT_STR_MAX_LENGTH 6 +#define IPDBG_SCRATCH_MEMORY_SIZE 1024 +#define IPDBG_EMPTY_DOWN_TRANSFERS 1024 +#define IPDBG_CONSECUTIVE_UP_TRANSFERS 1024 + +#if IPDBG_SCRATCH_MEMORY_SIZE < IPDBG_EMPTY_DOWN_TRANSFERS +#error "scratch Memory must be at least IPDBG_EMPTY_DOWN_TRANSFERS" +#endif + +#if IPDBG_SCRATCH_MEMORY_SIZE < IPDBG_CONSECUTIVE_UP_TRANSFERS +#error "scratch Memory must be at least IPDBG_CONSECUTIVE_UP_TRANSFERS" +#endif /* private connection data for IPDBG */ struct ipdbg_fifo { @@ -47,6 +59,13 @@ struct ipdbg_virtual_ir_info { uint32_t value; }; +struct ipdbg_hub_scratch_memory { + uint8_t *dr_out_vals; + uint8_t *dr_in_vals; + uint8_t *vir_out_val; + struct scan_field *fields; +}; + struct ipdbg_hub { uint32_t user_instruction; uint32_t max_tools; @@ -61,7 +80,9 @@ struct ipdbg_hub { struct connection **connections; uint8_t data_register_length; uint8_t dn_xoff; + uint8_t flow_control_enabled; struct ipdbg_virtual_ir_info *virtual_ir; + struct ipdbg_hub_scratch_memory scratch_memory; }; static struct ipdbg_hub *ipdbg_first_hub; @@ -90,7 +111,7 @@ static void ipdbg_zero_rd_idx(struct ipdbg_fifo *fifo) return; size_t ri = fifo->rd_idx; - for (size_t idx = 0 ; idx < fifo->count ; ++idx) + for (size_t idx = 0; idx < fifo->count; ++idx) fifo->buffer[idx] = fifo->buffer[ri++]; fifo->rd_idx = 0; } @@ -149,7 +170,7 @@ static int ipdbg_max_tools_from_data_register_length(uint8_t data_register_lengt static struct ipdbg_service *ipdbg_find_service(struct ipdbg_hub *hub, uint8_t tool) { struct ipdbg_service *service; - for (service = ipdbg_first_service ; service ; service = service->next) { + for (service = ipdbg_first_service; service; service = service->next) { if (service->hub == hub && service->tool == tool) break; } @@ -160,7 +181,7 @@ static void ipdbg_add_service(struct ipdbg_service *service) { struct ipdbg_service *iservice; if (ipdbg_first_service) { - for (iservice = ipdbg_first_service ; iservice->next; iservice = iservice->next) + for (iservice = ipdbg_first_service; iservice->next; iservice = iservice->next) ; iservice->next = service; } else @@ -192,7 +213,7 @@ static int ipdbg_remove_service(struct ipdbg_service *service) return ERROR_OK; } - for (struct ipdbg_service *iservice = ipdbg_first_service ; iservice->next ; iservice = iservice->next) { + for (struct ipdbg_service *iservice = ipdbg_first_service; iservice->next; iservice = iservice->next) { if (service == iservice->next) { iservice->next = service->next; return ERROR_OK; @@ -205,7 +226,7 @@ static struct ipdbg_hub *ipdbg_find_hub(struct jtag_tap *tap, uint32_t user_instruction, struct ipdbg_virtual_ir_info *virtual_ir) { struct ipdbg_hub *hub = NULL; - for (hub = ipdbg_first_hub ; hub ; hub = hub->next) { + for (hub = ipdbg_first_hub; hub; hub = hub->next) { if (hub->tap == tap && hub->user_instruction == user_instruction) { if ((!virtual_ir && !hub->virtual_ir) || (virtual_ir && hub->virtual_ir && @@ -223,7 +244,7 @@ static void ipdbg_add_hub(struct ipdbg_hub *hub) { struct ipdbg_hub *ihub; if (ipdbg_first_hub) { - for (ihub = ipdbg_first_hub ; ihub->next; ihub = ihub->next) + for (ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next) ; ihub->next = hub; } else @@ -235,20 +256,28 @@ static int ipdbg_create_hub(struct jtag_tap *tap, uint32_t user_instruction, uin { *hub = NULL; struct ipdbg_hub *new_hub = calloc(1, sizeof(struct ipdbg_hub)); - if (!new_hub) { - free(virtual_ir); - LOG_ERROR("Out of memory"); - return ERROR_FAIL; - } + if (!new_hub) + goto mem_err_hub; + const size_t dreg_buffer_size = DIV_ROUND_UP(data_register_length, 8); new_hub->max_tools = ipdbg_max_tools_from_data_register_length(data_register_length); + + new_hub->scratch_memory.dr_out_vals = calloc(IPDBG_SCRATCH_MEMORY_SIZE, dreg_buffer_size); + new_hub->scratch_memory.dr_in_vals = calloc(IPDBG_SCRATCH_MEMORY_SIZE, dreg_buffer_size); + new_hub->scratch_memory.fields = calloc(IPDBG_SCRATCH_MEMORY_SIZE, sizeof(struct scan_field)); new_hub->connections = calloc(new_hub->max_tools, sizeof(struct connection *)); - if (!new_hub->connections) { - free(virtual_ir); - free(new_hub); - LOG_ERROR("Out of memory"); - return ERROR_FAIL; - } + + if (virtual_ir) + new_hub->scratch_memory.vir_out_val = calloc(1, DIV_ROUND_UP(virtual_ir->length, 8)); + + if (!new_hub->scratch_memory.dr_out_vals || !new_hub->scratch_memory.dr_in_vals || + !new_hub->scratch_memory.fields || (virtual_ir && !new_hub->scratch_memory.vir_out_val) || + !new_hub->connections) + goto mem_err2; + + if (virtual_ir) + buf_set_u32(new_hub->scratch_memory.vir_out_val, 0, virtual_ir->length, virtual_ir->value); + new_hub->tap = tap; new_hub->user_instruction = user_instruction; new_hub->data_register_length = data_register_length; @@ -259,8 +288,19 @@ static int ipdbg_create_hub(struct jtag_tap *tap, uint32_t user_instruction, uin new_hub->virtual_ir = virtual_ir; *hub = new_hub; - return ERROR_OK; + +mem_err2: + free(new_hub->scratch_memory.vir_out_val); + free(new_hub->connections); + free(new_hub->scratch_memory.fields); + free(new_hub->scratch_memory.dr_in_vals); + free(new_hub->scratch_memory.dr_out_vals); + free(new_hub); +mem_err_hub: + free(virtual_ir); + LOG_ERROR("Out of memory"); + return ERROR_FAIL; } static void ipdbg_free_hub(struct ipdbg_hub *hub) @@ -269,6 +309,10 @@ static void ipdbg_free_hub(struct ipdbg_hub *hub) return; free(hub->connections); free(hub->virtual_ir); + free(hub->scratch_memory.dr_out_vals); + free(hub->scratch_memory.dr_in_vals); + free(hub->scratch_memory.fields); + free(hub->scratch_memory.vir_out_val); free(hub); } @@ -281,7 +325,7 @@ static int ipdbg_remove_hub(struct ipdbg_hub *hub) return ERROR_OK; } - for (struct ipdbg_hub *ihub = ipdbg_first_hub ; ihub->next ; ihub = ihub->next) { + for (struct ipdbg_hub *ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next) { if (hub == ihub->next) { ihub->next = hub->next; return ERROR_OK; @@ -315,6 +359,10 @@ static int ipdbg_shift_instr(struct ipdbg_hub *hub, uint32_t instr) } uint8_t *ir_out_val = calloc(DIV_ROUND_UP(tap->ir_length, 8), 1); + if (!ir_out_val) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } buf_set_u32(ir_out_val, 0, tap->ir_length, instr); struct scan_field fields; @@ -343,16 +391,11 @@ static int ipdbg_shift_vir(struct ipdbg_hub *hub) if (!tap) return ERROR_FAIL; - uint8_t *dr_out_val = calloc(DIV_ROUND_UP(hub->virtual_ir->length, 8), 1); - buf_set_u32(dr_out_val, 0, hub->virtual_ir->length, hub->virtual_ir->value); - - struct scan_field fields; - ipdbg_init_scan_field(&fields, NULL, hub->virtual_ir->length, dr_out_val); - jtag_add_dr_scan(tap, 1, &fields, TAP_IDLE); + ipdbg_init_scan_field(hub->scratch_memory.fields, NULL, + hub->virtual_ir->length, hub->scratch_memory.vir_out_val); + jtag_add_dr_scan(tap, 1, hub->scratch_memory.fields, TAP_IDLE); retval = jtag_execute_queue(); - free(dr_out_val); - return retval; } @@ -365,20 +408,15 @@ static int ipdbg_shift_data(struct ipdbg_hub *hub, uint32_t dn_data, uint32_t *u if (!tap) return ERROR_FAIL; - uint8_t *dr_out_val = calloc(DIV_ROUND_UP(hub->data_register_length, 8), 1); - buf_set_u32(dr_out_val, 0, hub->data_register_length, dn_data); - uint8_t *dr_in_val = up_data ? calloc(DIV_ROUND_UP(hub->data_register_length, 8), 1) : NULL; + buf_set_u32(hub->scratch_memory.dr_out_vals, 0, hub->data_register_length, dn_data); - struct scan_field fields; - ipdbg_init_scan_field(&fields, dr_in_val, hub->data_register_length, dr_out_val); - jtag_add_dr_scan(tap, 1, &fields, TAP_IDLE); + ipdbg_init_scan_field(hub->scratch_memory.fields, hub->scratch_memory.dr_in_vals, + hub->data_register_length, hub->scratch_memory.dr_out_vals); + jtag_add_dr_scan(tap, 1, hub->scratch_memory.fields, TAP_IDLE); int retval = jtag_execute_queue(); if (up_data && retval == ERROR_OK) - *up_data = buf_get_u32(dr_in_val, 0, hub->data_register_length); - - free(dr_out_val); - free(dr_in_val); + *up_data = buf_get_u32(hub->scratch_memory.dr_in_vals, 0, hub->data_register_length); return retval; } @@ -410,6 +448,60 @@ static int ipdbg_distribute_data_from_hub(struct ipdbg_hub *hub, uint32_t up) return ERROR_OK; } +static void ipdbg_check_for_xoff(struct ipdbg_hub *hub, size_t tool, + uint32_t rx_data) +{ + if ((rx_data & hub->xoff_mask) && hub->last_dn_tool != hub->max_tools) { + hub->dn_xoff |= BIT(hub->last_dn_tool); + LOG_INFO("tool %d sent xoff", hub->last_dn_tool); + } + + hub->last_dn_tool = tool; +} + +static int ipdbg_shift_empty_data(struct ipdbg_hub *hub) +{ + if (!hub) + return ERROR_FAIL; + + struct jtag_tap *tap = hub->tap; + if (!tap) + return ERROR_FAIL; + + const size_t dreg_buffer_size = DIV_ROUND_UP(hub->data_register_length, 8); + memset(hub->scratch_memory.dr_out_vals, 0, dreg_buffer_size); + for (size_t i = 0; i < IPDBG_EMPTY_DOWN_TRANSFERS; ++i) { + ipdbg_init_scan_field(hub->scratch_memory.fields + i, + hub->scratch_memory.dr_in_vals + i * dreg_buffer_size, + hub->data_register_length, + hub->scratch_memory.dr_out_vals); + jtag_add_dr_scan(tap, 1, hub->scratch_memory.fields + i, TAP_IDLE); + } + + int retval = jtag_execute_queue(); + + if (retval == ERROR_OK) { + uint32_t up_data; + for (size_t i = 0; i < IPDBG_EMPTY_DOWN_TRANSFERS; ++i) { + up_data = buf_get_u32(hub->scratch_memory.dr_in_vals + + i * dreg_buffer_size, 0, + hub->data_register_length); + int rv = ipdbg_distribute_data_from_hub(hub, up_data); + if (rv != ERROR_OK) + retval = rv; + + if (i == 0) { + /* check if xoff sent is only needed on the first transfer which + may contain the xoff of the prev down transfer. + */ + ipdbg_check_for_xoff(hub, hub->max_tools, up_data); + } + } + } + + return retval; +} + static int ipdbg_jtag_transfer_byte(struct ipdbg_hub *hub, size_t tool, struct ipdbg_connection *connection) { uint32_t dn = hub->valid_mask | ((tool & hub->tool_mask) << 8) | @@ -423,14 +515,63 @@ static int ipdbg_jtag_transfer_byte(struct ipdbg_hub *hub, size_t tool, struct i if (ret != ERROR_OK) return ret; - if ((up & hub->xoff_mask) && (hub->last_dn_tool != hub->max_tools)) { - hub->dn_xoff |= BIT(hub->last_dn_tool); - LOG_INFO("tool %d sent xoff", hub->last_dn_tool); + ipdbg_check_for_xoff(hub, tool, up); + + return ERROR_OK; +} + +static int ipdbg_jtag_transfer_bytes(struct ipdbg_hub *hub, + size_t tool, struct ipdbg_connection *connection) +{ + if (!hub) + return ERROR_FAIL; + + struct jtag_tap *tap = hub->tap; + if (!tap) + return ERROR_FAIL; + + const size_t dreg_buffer_size = DIV_ROUND_UP(hub->data_register_length, 8); + size_t num_tx = (connection->dn_fifo.count < IPDBG_CONSECUTIVE_UP_TRANSFERS) ? + connection->dn_fifo.count : IPDBG_CONSECUTIVE_UP_TRANSFERS; + + for (size_t i = 0; i < num_tx; ++i) { + uint32_t dn_data = hub->valid_mask | ((tool & hub->tool_mask) << 8) | + (0x00fful & ipdbg_get_from_fifo(&connection->dn_fifo)); + buf_set_u32(hub->scratch_memory.dr_out_vals + i * dreg_buffer_size, 0, + hub->data_register_length, dn_data); + + ipdbg_init_scan_field(hub->scratch_memory.fields + i, + hub->scratch_memory.dr_in_vals + + i * dreg_buffer_size, + hub->data_register_length, + hub->scratch_memory.dr_out_vals + + i * dreg_buffer_size); + jtag_add_dr_scan(tap, 1, hub->scratch_memory.fields + i, TAP_IDLE); } - hub->last_dn_tool = tool; + int retval = jtag_execute_queue(); - return ERROR_OK; + if (retval == ERROR_OK) { + uint32_t up_data; + for (size_t i = 0; i < num_tx; ++i) { + up_data = buf_get_u32(hub->scratch_memory.dr_in_vals + + i * dreg_buffer_size, + 0, hub->data_register_length); + int rv = ipdbg_distribute_data_from_hub(hub, up_data); + if (rv != ERROR_OK) + retval = rv; + if (i == 0) { + /* check if xoff sent is only needed on the first transfer which + may contain the xoff of the prev down transfer. + No checks for this channel because this function is only + called for channels without enabled flow control. + */ + ipdbg_check_for_xoff(hub, tool, up_data); + } + } + } + + return retval; } static int ipdbg_polling_callback(void *priv) @@ -446,36 +587,28 @@ static int ipdbg_polling_callback(void *priv) return ret; /* transfer dn buffers to jtag-hub */ - unsigned int num_transfers = 0; - for (size_t tool = 0 ; tool < hub->max_tools ; ++tool) { + for (size_t tool = 0; tool < hub->max_tools; ++tool) { struct connection *conn = hub->connections[tool]; if (conn && conn->priv) { struct ipdbg_connection *connection = conn->priv; while (((hub->dn_xoff & BIT(tool)) == 0) && !ipdbg_fifo_is_empty(&connection->dn_fifo)) { - ret = ipdbg_jtag_transfer_byte(hub, tool, connection); + if (hub->flow_control_enabled & BIT(tool)) + ret = ipdbg_jtag_transfer_byte(hub, tool, connection); + else + ret = ipdbg_jtag_transfer_bytes(hub, tool, connection); if (ret != ERROR_OK) return ret; - ++num_transfers; } } } /* some transfers to get data from jtag-hub in case there is no dn data */ - while (num_transfers++ < hub->max_tools) { - uint32_t dn = 0; - uint32_t up = 0; - - int retval = ipdbg_shift_data(hub, dn, &up); - if (retval != ERROR_OK) - return ret; - - retval = ipdbg_distribute_data_from_hub(hub, up); - if (retval != ERROR_OK) - return ret; - } + ret = ipdbg_shift_empty_data(hub); + if (ret != ERROR_OK) + return ret; /* write from up fifos to sockets */ - for (size_t tool = 0 ; tool < hub->max_tools ; ++tool) { + for (size_t tool = 0; tool < hub->max_tools; ++tool) { struct connection *conn = hub->connections[tool]; if (conn && conn->priv) { struct ipdbg_connection *connection = conn->priv; @@ -488,6 +621,33 @@ static int ipdbg_polling_callback(void *priv) return ERROR_OK; } +static int ipdbg_get_flow_control_info_from_hub(struct ipdbg_hub *hub) +{ + uint32_t up_data; + + /* on older implementations the flow_control_enable_word is not sent to us. + so we don't know -> assume it's enabled on all channels */ + hub->flow_control_enabled = 0x7f; + + int ret = ipdbg_shift_data(hub, 0UL, &up_data); + if (ret != ERROR_OK) + return ret; + + const bool valid_up_data = up_data & hub->valid_mask; + if (valid_up_data) { + const size_t tool = (up_data >> 8) & hub->tool_mask; + /* the first valid data from hub is flow_control_enable_word */ + if (tool == hub->tool_mask) + hub->flow_control_enabled = up_data & 0x007f; + else + ipdbg_distribute_data_from_hub(hub, up_data); + } + + LOG_INFO("Flow control enabled on IPDBG JTAG Hub: 0x%02x", hub->flow_control_enabled); + + return ERROR_OK; +} + static int ipdbg_start_polling(struct ipdbg_service *service, struct connection *connection) { struct ipdbg_hub *hub = service->hub; @@ -514,6 +674,10 @@ static int ipdbg_start_polling(struct ipdbg_service *service, struct connection if (ret != ERROR_OK) return ret; + ret = ipdbg_get_flow_control_info_from_hub(hub); + if (ret != ERROR_OK) + return ret; + LOG_INFO("IPDBG start_polling"); const int time_ms = 20; @@ -610,10 +774,8 @@ static int ipdbg_start(uint16_t port, struct jtag_tap *tap, uint32_t user_instru } } else { int retval = ipdbg_create_hub(tap, user_instruction, data_register_length, virtual_ir, &hub); - if (retval != ERROR_OK) { - free(virtual_ir); + if (retval != ERROR_OK) return retval; - } } struct ipdbg_service *service = NULL; @@ -695,6 +857,7 @@ COMMAND_HANDLER(handle_ipdbg_command) uint32_t virtual_ir_length = 5; uint32_t virtual_ir_value = 0x11; struct ipdbg_virtual_ir_info *virtual_ir = NULL; + int user_num = 1; if ((CMD_ARGC < IPDBG_MIN_NUM_OF_OPTIONS) || (CMD_ARGC > IPDBG_MAX_NUM_OF_OPTIONS)) return ERROR_COMMAND_SYNTAX_ERROR; @@ -721,6 +884,34 @@ COMMAND_HANDLER(handle_ipdbg_command) IPDBG_MIN_DR_LENGTH, IPDBG_MAX_DR_LENGTH); return ERROR_FAIL; } + } else if (strcmp(CMD_ARGV[i], "-pld") == 0) { + ++i; + if (i >= CMD_ARGC || CMD_ARGV[i][0] == '-') + return ERROR_COMMAND_SYNTAX_ERROR; + struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[i]); + if (!device || !device->driver) { + command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[i]); + return ERROR_FAIL; + } + COMMAND_PARSE_OPTIONAL_NUMBER(int, i, user_num); + struct pld_ipdbg_hub pld_hub; + struct pld_driver *driver = device->driver; + if (!driver->get_ipdbg_hub) { + command_print(CMD, "pld driver has no ipdbg support"); + return ERROR_FAIL; + } + if (driver->get_ipdbg_hub(user_num, device, &pld_hub) != ERROR_OK) { + command_print(CMD, "unable to retrieve hub from pld driver"); + return ERROR_FAIL; + } + if (!pld_hub.tap) { + command_print(CMD, "no tap received from pld driver"); + return ERROR_FAIL; + } + hub_configured = true; + user_instruction = pld_hub.user_ir_code; + tap = pld_hub.tap; + } else if (strcmp(CMD_ARGV[i], "-vir") == 0) { COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_value); COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_length); diff --git a/src/server/rtt_server.c b/src/server/rtt_server.c index 3850c26876..9769153475 100644 --- a/src/server/rtt_server.c +++ b/src/server/rtt_server.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright (C) 2016-2017 by Marc Schink <dev@zapb.de> - * - * 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/>. */ #ifdef HAVE_CONFIG_H @@ -36,6 +25,7 @@ struct rtt_service { unsigned int channel; + char *hello_message; }; static int read_callback(unsigned int channel, const uint8_t *buffer, @@ -76,6 +66,9 @@ static int rtt_new_connection(struct connection *connection) if (ret != ERROR_OK) return ret; + if (service->hello_message) + connection_write(connection, service->hello_message, strlen(service->hello_message)); + return ERROR_OK; } @@ -128,16 +121,30 @@ COMMAND_HANDLER(handle_rtt_start_command) int ret; struct rtt_service *service; - if (CMD_ARGC != 2) + if (CMD_ARGC < 2 || CMD_ARGC > 3) return ERROR_COMMAND_SYNTAX_ERROR; - service = malloc(sizeof(struct rtt_service)); + service = calloc(1, sizeof(struct rtt_service)); if (!service) return ERROR_FAIL; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], service->channel); + if (CMD_ARGC >= 3) { + const char *hello_message = CMD_ARGV[2]; + size_t hello_length = strlen(hello_message); + + service->hello_message = malloc(hello_length + 2); + if (!service->hello_message) { + LOG_ERROR("Out of memory"); + free(service); + return ERROR_FAIL; + } + strcpy(service->hello_message, hello_message); + service->hello_message[hello_length] = '\n'; + service->hello_message[hello_length + 1] = '\0'; + } ret = add_service(&rtt_service_driver, CMD_ARGV[0], CONNECTION_LIMIT_UNLIMITED, service); if (ret != ERROR_OK) { @@ -164,7 +171,7 @@ static const struct command_registration rtt_server_subcommand_handlers[] = { .handler = handle_rtt_start_command, .mode = COMMAND_ANY, .help = "Start a RTT server", - .usage = "<port> <channel>" + .usage = "<port> <channel> [message]" }, { .name = "stop", diff --git a/src/server/rtt_server.h b/src/server/rtt_server.h index aec6f22228..5cea25a00c 100644 --- a/src/server/rtt_server.h +++ b/src/server/rtt_server.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Copyright (C) 2016-2017 by Marc Schink <dev@zapb.de> - * - * 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/>. */ #ifndef OPENOCD_SERVER_RTT_SERVER_H diff --git a/src/server/server.c b/src/server/server.c index 7b0004d641..2be90451f7 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -484,7 +473,7 @@ int server_loop(struct command_context *command_context) tv.tv_usec = 0; retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv); } else { - /* Every 100ms, can be changed with "poll_period" command */ + /* Timeout socket_select() when a target timer expires or every polling_period */ int timeout_ms = next_event - timeval_ms(); if (timeout_ms < 0) timeout_ms = 0; @@ -492,7 +481,6 @@ int server_loop(struct command_context *command_context) timeout_ms = polling_period; tv.tv_usec = timeout_ms * 1000; /* Only while we're sleeping we'll let others run */ - kept_alive(); retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv); } @@ -519,9 +507,12 @@ int server_loop(struct command_context *command_context) } if (retval == 0) { - /* We only execute these callbacks when there was nothing to do or we timed - *out */ - target_call_timer_callbacks_now(); + /* Execute callbacks of expired timers when + * - there was nothing to do if poll_ok was true + * - socket_select() timed out if poll_ok was false, now one or more + * timers expired or the polling period elapsed + */ + target_call_timer_callbacks(); next_event = target_timer_next_event(); process_jim_events(command_context); @@ -756,6 +747,11 @@ int connection_read(struct connection *connection, void *data, int len) return read(connection->fd, data, len); } +bool openocd_is_shutdown_pending(void) +{ + return shutdown_openocd != CONTINUE_MAIN_LOOP; +} + /* tell the server we want to shut down */ COMMAND_HANDLER(handle_shutdown_command) { @@ -763,6 +759,8 @@ COMMAND_HANDLER(handle_shutdown_command) shutdown_openocd = SHUTDOWN_REQUESTED; + command_run_line(CMD_CTX, "_run_pre_shutdown_commands"); + if (CMD_ARGC == 1) { if (!strcmp(CMD_ARGV[0], "error")) { shutdown_openocd = SHUTDOWN_WITH_ERROR_CODE; diff --git a/src/server/server.h b/src/server/server.h index a6b1963a67..c9d4698af8 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_SERVER_SERVER_H @@ -115,6 +104,8 @@ int server_register_commands(struct command_context *context); int connection_write(struct connection *connection, const void *data, int len); int connection_read(struct connection *connection, void *data, int len); +bool openocd_is_shutdown_pending(void); + /** * Defines an extended command handler function declaration to enable * access to (and manipulation of) the server port number. diff --git a/src/server/startup.tcl b/src/server/startup.tcl index 447b57cc36..1d30b1dd37 100644 --- a/src/server/startup.tcl +++ b/src/server/startup.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Defines basic Tcl procs for OpenOCD server modules # Handle GDB 'R' packet. Can be overridden by configuration script, diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c index 458d7eada3..16cbedc76c 100644 --- a/src/server/tcl_server.c +++ b/src/server/tcl_server.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2010 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/server/tcl_server.h b/src/server/tcl_server.h index 6ce3ab95fe..bee562ce88 100644 --- a/src/server/tcl_server.h +++ b/src/server/tcl_server.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2008 * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_SERVER_TCL_SERVER_H diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index 791a1a5485..938bc5b062 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -222,9 +211,8 @@ static int telnet_new_connection(struct connection *connection) { struct telnet_connection *telnet_connection; struct telnet_service *telnet_service = connection->service->priv; - int i; - telnet_connection = malloc(sizeof(struct telnet_connection)); + telnet_connection = calloc(1, sizeof(struct telnet_connection)); if (!telnet_connection) { LOG_ERROR("Failed to allocate telnet connection."); @@ -234,9 +222,6 @@ static int telnet_new_connection(struct connection *connection) connection->priv = telnet_connection; /* initialize telnet connection information */ - telnet_connection->closed = false; - telnet_connection->line_size = 0; - telnet_connection->line_cursor = 0; telnet_connection->prompt = strdup("> "); telnet_connection->prompt_visible = true; telnet_connection->state = TELNET_STATE_DATA; @@ -257,11 +242,6 @@ static int telnet_new_connection(struct connection *connection) telnet_write(connection, "\r", 1); telnet_prompt(connection); - /* initialize history */ - for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++) - telnet_connection->history[i] = NULL; - telnet_connection->next_history = 0; - telnet_connection->current_history = 0; telnet_load_history(telnet_connection); log_add_callback(telnet_log_callback, connection); @@ -624,7 +604,11 @@ static void telnet_auto_complete(struct connection *connection) while ((usr_cmd_pos < t_con->line_cursor) && isspace(t_con->line[usr_cmd_pos])) usr_cmd_pos++; - /* user command length */ + /* check user command length */ + if (t_con->line_cursor < usr_cmd_pos) { + telnet_bell(connection); + return; + } size_t usr_cmd_len = t_con->line_cursor - usr_cmd_pos; /* optimize multiple spaces in the user command, diff --git a/src/server/telnet_server.h b/src/server/telnet_server.h index 27148d7cee..313b529f0d 100644 --- a/src/server/telnet_server.h +++ b/src/server/telnet_server.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_SERVER_TELNET_SERVER_H diff --git a/src/svf/Makefile.am b/src/svf/Makefile.am index 5603d53b54..5fcb02c3f4 100644 --- a/src/svf/Makefile.am +++ b/src/svf/Makefile.am @@ -1,2 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libsvf.la %C%_libsvf_la_SOURCES = %D%/svf.c %D%/svf.h diff --git a/src/svf/svf.c b/src/svf/svf.c index 3021dcb669..dd3d5175c3 100644 --- a/src/svf/svf.c +++ b/src/svf/svf.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 by Simon Qian * * SimonQian@SimonQian.com * - * * - * 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/>. * ***************************************************************************/ /* The specification for SVF is available here: @@ -33,6 +22,8 @@ #include "svf.h" #include "helper/system.h" #include <helper/time_support.h> +#include <helper/nvp.h> +#include <stdbool.h> /* SVF command */ enum svf_command { @@ -150,6 +141,9 @@ static const struct svf_statemove svf_statemoves[] = { #define XXR_TDO (1 << 1) #define XXR_MASK (1 << 2) #define XXR_SMASK (1 << 3) + +#define SVF_MAX_ADDCYCLES 255 + struct svf_xxr_para { int len; int data_mask; @@ -231,6 +225,8 @@ static int svf_buffer_index, svf_buffer_size; static int svf_quiet; static int svf_nil; static int svf_ignore_error; +static bool svf_noreset; +static int svf_addcycles; /* Targeting particular tap */ static int svf_tap_is_specified; @@ -351,19 +347,51 @@ int svf_add_statemove(tap_state_t state_to) return ERROR_FAIL; } +enum svf_cmd_param { + OPT_ADDCYCLES, + OPT_IGNORE_ERROR, + OPT_NIL, + OPT_NORESET, + OPT_PROGRESS, + OPT_QUIET, + OPT_TAP, + /* DEPRECATED */ + DEPRECATED_OPT_IGNORE_ERROR, + DEPRECATED_OPT_NIL, + DEPRECATED_OPT_PROGRESS, + DEPRECATED_OPT_QUIET, +}; + +static const struct nvp svf_cmd_opts[] = { + { .name = "-addcycles", .value = OPT_ADDCYCLES }, + { .name = "-ignore_error", .value = OPT_IGNORE_ERROR }, + { .name = "-nil", .value = OPT_NIL }, + { .name = "-noreset", .value = OPT_NORESET }, + { .name = "-progress", .value = OPT_PROGRESS }, + { .name = "-quiet", .value = OPT_QUIET }, + { .name = "-tap", .value = OPT_TAP }, + /* DEPRECATED */ + { .name = "ignore_error", .value = DEPRECATED_OPT_IGNORE_ERROR }, + { .name = "nil", .value = DEPRECATED_OPT_NIL }, + { .name = "progress", .value = DEPRECATED_OPT_PROGRESS }, + { .name = "quiet", .value = DEPRECATED_OPT_QUIET }, + { .name = NULL, .value = -1 } +}; + COMMAND_HANDLER(handle_svf_command) { #define SVF_MIN_NUM_OF_OPTIONS 1 -#define SVF_MAX_NUM_OF_OPTIONS 5 +#define SVF_MAX_NUM_OF_OPTIONS 8 int command_num = 0; int ret = ERROR_OK; int64_t time_measure_ms; int time_measure_s, time_measure_m; - /* use NULL to indicate a "plain" svf file which accounts for + /* + * use NULL to indicate a "plain" svf file which accounts for * any additional devices in the scan chain, otherwise the device * that should be affected - */ + */ struct jtag_tap *tap = NULL; if ((CMD_ARGC < SVF_MIN_NUM_OF_OPTIONS) || (CMD_ARGC > SVF_MAX_NUM_OF_OPTIONS)) @@ -374,34 +402,78 @@ COMMAND_HANDLER(handle_svf_command) svf_nil = 0; svf_progress_enabled = 0; svf_ignore_error = 0; + svf_noreset = false; + svf_addcycles = 0; + for (unsigned int i = 0; i < CMD_ARGC; i++) { - if (strcmp(CMD_ARGV[i], "-tap") == 0) { + const struct nvp *n = nvp_name2value(svf_cmd_opts, CMD_ARGV[i]); + switch (n->value) { + case OPT_ADDCYCLES: + svf_addcycles = atoi(CMD_ARGV[i + 1]); + if (svf_addcycles > SVF_MAX_ADDCYCLES) { + command_print(CMD, "addcycles: %s out of range", CMD_ARGV[i + 1]); + if (svf_fd) + fclose(svf_fd); + svf_fd = NULL; + return ERROR_COMMAND_ARGUMENT_INVALID; + } + i++; + break; + + case OPT_TAP: tap = jtag_tap_by_string(CMD_ARGV[i+1]); if (!tap) { command_print(CMD, "Tap: %s unknown", CMD_ARGV[i+1]); - return ERROR_FAIL; + if (svf_fd) + fclose(svf_fd); + svf_fd = NULL; + return ERROR_COMMAND_ARGUMENT_INVALID; } i++; - } else if ((strcmp(CMD_ARGV[i], - "quiet") == 0) || (strcmp(CMD_ARGV[i], "-quiet") == 0)) + break; + + case DEPRECATED_OPT_QUIET: + LOG_INFO("DEPRECATED flag '%s'; use '-%s'", CMD_ARGV[i], CMD_ARGV[i]); + /* fallthrough */ + case OPT_QUIET: svf_quiet = 1; - else if ((strcmp(CMD_ARGV[i], "nil") == 0) || (strcmp(CMD_ARGV[i], "-nil") == 0)) + break; + + case DEPRECATED_OPT_NIL: + LOG_INFO("DEPRECATED flag '%s'; use '-%s'", CMD_ARGV[i], CMD_ARGV[i]); + /* fallthrough */ + case OPT_NIL: svf_nil = 1; - else if ((strcmp(CMD_ARGV[i], - "progress") == 0) || (strcmp(CMD_ARGV[i], "-progress") == 0)) + break; + + case DEPRECATED_OPT_PROGRESS: + LOG_INFO("DEPRECATED flag '%s'; use '-%s'", CMD_ARGV[i], CMD_ARGV[i]); + /* fallthrough */ + case OPT_PROGRESS: svf_progress_enabled = 1; - else if ((strcmp(CMD_ARGV[i], - "ignore_error") == 0) || (strcmp(CMD_ARGV[i], "-ignore_error") == 0)) + break; + + case DEPRECATED_OPT_IGNORE_ERROR: + LOG_INFO("DEPRECATED flag '%s'; use '-%s'", CMD_ARGV[i], CMD_ARGV[i]); + /* fallthrough */ + case OPT_IGNORE_ERROR: svf_ignore_error = 1; - else { + break; + + case OPT_NORESET: + svf_noreset = true; + break; + + default: svf_fd = fopen(CMD_ARGV[i], "r"); if (!svf_fd) { int err = errno; command_print(CMD, "open(\"%s\"): %s", CMD_ARGV[i], strerror(err)); /* no need to free anything now */ return ERROR_COMMAND_SYNTAX_ERROR; - } else - LOG_USER("svf processing file: \"%s\"", CMD_ARGV[i]); + } + LOG_USER("svf processing file: \"%s\"", CMD_ARGV[i]); + break; } } @@ -435,7 +507,7 @@ COMMAND_HANDLER(handle_svf_command) memcpy(&svf_para, &svf_para_init, sizeof(svf_para)); - if (!svf_nil) { + if (!svf_nil && !svf_noreset) { /* TAP_RESET */ jtag_add_tlr(); } @@ -460,27 +532,31 @@ COMMAND_HANDLER(handle_svf_command) } /* HDR %d TDI (0) */ - if (svf_set_padding(&svf_para.hdr_para, header_dr_len, 0) != ERROR_OK) { - LOG_ERROR("failed to set data header"); - return ERROR_FAIL; + ret = svf_set_padding(&svf_para.hdr_para, header_dr_len, 0); + if (ret != ERROR_OK) { + command_print(CMD, "failed to set data header"); + goto free_all; } /* HIR %d TDI (0xFF) */ - if (svf_set_padding(&svf_para.hir_para, header_ir_len, 0xFF) != ERROR_OK) { - LOG_ERROR("failed to set instruction header"); - return ERROR_FAIL; + ret = svf_set_padding(&svf_para.hir_para, header_ir_len, 0xFF); + if (ret != ERROR_OK) { + command_print(CMD, "failed to set instruction header"); + goto free_all; } /* TDR %d TDI (0) */ - if (svf_set_padding(&svf_para.tdr_para, trailer_dr_len, 0) != ERROR_OK) { - LOG_ERROR("failed to set data trailer"); - return ERROR_FAIL; + ret = svf_set_padding(&svf_para.tdr_para, trailer_dr_len, 0); + if (ret != ERROR_OK) { + command_print(CMD, "failed to set data trailer"); + goto free_all; } /* TIR %d TDI (0xFF) */ - if (svf_set_padding(&svf_para.tir_para, trailer_ir_len, 0xFF) != ERROR_OK) { - LOG_ERROR("failed to set instruction trailer"); - return ERROR_FAIL; + ret = svf_set_padding(&svf_para.tir_para, trailer_ir_len, 0xFF); + if (ret != ERROR_OK) { + command_print(CMD, "failed to set instruction trailer"); + goto free_all; } } @@ -539,7 +615,7 @@ COMMAND_HANDLER(handle_svf_command) free_all: fclose(svf_fd); - svf_fd = 0; + svf_fd = NULL; /* free buffers */ free(svf_command_buffer); @@ -1200,6 +1276,9 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) svf_para.dr_end_state); } + if (svf_addcycles) + jtag_add_clocks(svf_addcycles); + svf_buffer_index += (i + 7) >> 3; } else if (command == SIR) { /* check buffer size first, reallocate if necessary */ @@ -1556,7 +1635,7 @@ static const struct command_registration svf_command_handlers[] = { .handler = handle_svf_command, .mode = COMMAND_EXEC, .help = "Runs a SVF file.", - .usage = "[-tap device.tap] <file> [quiet] [nil] [progress] [ignore_error]", + .usage = "[-tap device.tap] [-quiet] [-nil] [-progress] [-ignore_error] [-noreset] [-addcycles numcycles] file", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/svf/svf.h b/src/svf/svf.h index 4101a3f853..74f7d9ca9b 100644 --- a/src/svf/svf.h +++ b/src/svf/svf.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 by Simon Qian * * SimonQian@SimonQian.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_SVF_SVF_H diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 470b23a8e8..e8e90aa033 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -1,5 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + %C%_libtarget_la_LIBADD = %D%/openrisc/libopenrisc.la \ - %D%/riscv/libriscv.la + %D%/riscv/libriscv.la \ + %D%/xtensa/libxtensa.la \ + %D%/espressif/libespressif.la %C%_libtarget_la_CPPFLAGS = $(AM_CPPFLAGS) @@ -15,7 +19,6 @@ noinst_LTLIBRARIES += %D%/libtarget.la $(ARM_MISC_SRC) \ $(AVR32_SRC) \ $(MIPS32_SRC) \ - $(NDS32_SRC) \ $(STM8_SRC) \ $(INTEL_IA32_SRC) \ $(ESIRISC_SRC) \ @@ -134,18 +137,6 @@ MIPS64_SRC = \ %D%/trace.c \ %D%/mips_ejtag.c -NDS32_SRC = \ - %D%/nds32.c \ - %D%/nds32_reg.c \ - %D%/nds32_cmd.c \ - %D%/nds32_disassembler.c \ - %D%/nds32_tlb.c \ - %D%/nds32_v2.c \ - %D%/nds32_v3_common.c \ - %D%/nds32_v3.c \ - %D%/nds32_v3m.c \ - %D%/nds32_aice.c - STM8_SRC = \ %D%/stm8.c @@ -217,6 +208,7 @@ ARC_SRC = \ %D%/image.h \ %D%/mips32.h \ %D%/mips64.h \ + %D%/mips_cpu.h \ %D%/mips_m4k.h \ %D%/mips_mips64.h \ %D%/mips_ejtag.h \ @@ -235,18 +227,6 @@ ARC_SRC = \ %D%/avr32_jtag.h \ %D%/avr32_mem.h \ %D%/avr32_regs.h \ - %D%/nds32.h \ - %D%/nds32_cmd.h \ - %D%/nds32_disassembler.h \ - %D%/nds32_edm.h \ - %D%/nds32_insn.h \ - %D%/nds32_reg.h \ - %D%/nds32_tlb.h \ - %D%/nds32_v2.h \ - %D%/nds32_v3_common.h \ - %D%/nds32_v3.h \ - %D%/nds32_v3m.h \ - %D%/nds32_aice.h \ %D%/semihosting_common.h \ %D%/stm8.h \ %D%/lakemont.h \ @@ -264,3 +244,5 @@ ARC_SRC = \ include %D%/openrisc/Makefile.am include %D%/riscv/Makefile.am +include %D%/xtensa/Makefile.am +include %D%/espressif/Makefile.am diff --git a/src/target/a64_disassembler.c b/src/target/a64_disassembler.c index 58ddf603ec..ca3d3ea7a9 100644 --- a/src/target/a64_disassembler.c +++ b/src/target/a64_disassembler.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2019 by Mete Balci * * metebalci@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/a64_disassembler.h b/src/target/a64_disassembler.h index 5c58bbfe53..28fcf4b331 100644 --- a/src/target/a64_disassembler.h +++ b/src/target/a64_disassembler.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2019 by Mete Balci * * metebalci@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_AARCH64_DISASSEMBLER_H diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 8838da9273..1c056a015e 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2015 by David Ung * * * - * 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, write to the * - * Free Software Foundation, Inc., * - * * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -33,6 +21,7 @@ #include "arm_semihosting.h" #include "jtag/interface.h" #include "smp.h" +#include <helper/nvp.h> #include <helper/time_support.h> enum restart_mode { @@ -116,7 +105,7 @@ static int aarch64_restore_system_control_reg(struct target *target) if (target_mode != ARM_MODE_ANY) armv8_dpm_modeswitch(&armv8->dpm, target_mode); - retval = armv8->dpm.instr_write_data_r0(&armv8->dpm, instr, aarch64->system_control_reg); + retval = armv8->dpm.instr_write_data_r0_64(&armv8->dpm, instr, aarch64->system_control_reg); if (retval != ERROR_OK) return retval; @@ -193,7 +182,7 @@ static int aarch64_mmu_modify(struct target *target, int enable) if (target_mode != ARM_MODE_ANY) armv8_dpm_modeswitch(&armv8->dpm, target_mode); - retval = armv8->dpm.instr_write_data_r0(&armv8->dpm, instr, + retval = armv8->dpm.instr_write_data_r0_64(&armv8->dpm, instr, aarch64->system_control_reg_curr); if (target_mode != ARM_MODE_ANY) @@ -600,7 +589,7 @@ static int aarch64_restore_one(struct target *target, int current, resume_pc &= 0xFFFFFFFC; break; case ARM_STATE_AARCH64: - resume_pc &= 0xFFFFFFFFFFFFFFFC; + resume_pc &= 0xFFFFFFFFFFFFFFFCULL; break; case ARM_STATE_THUMB: case ARM_STATE_THUMB_EE: @@ -857,8 +846,10 @@ static int aarch64_resume(struct target *target, int current, struct armv8_common *armv8 = target_to_armv8(target); armv8->last_run_control_op = ARMV8_RUNCONTROL_RESUME; - if (target->state != TARGET_HALTED) + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; + } /* * If this target is part of a SMP group, prepare the others @@ -1064,23 +1055,26 @@ static int aarch64_post_debug_entry(struct target *target) if (target_mode != ARM_MODE_ANY) armv8_dpm_modeswitch(&armv8->dpm, target_mode); - retval = armv8->dpm.instr_read_data_r0(&armv8->dpm, instr, &aarch64->system_control_reg); + retval = armv8->dpm.instr_read_data_r0_64(&armv8->dpm, instr, &aarch64->system_control_reg); if (retval != ERROR_OK) return retval; if (target_mode != ARM_MODE_ANY) armv8_dpm_modeswitch(&armv8->dpm, ARM_MODE_ANY); - LOG_DEBUG("System_register: %8.8" PRIx32, aarch64->system_control_reg); + LOG_DEBUG("System_register: %8.8" PRIx64, aarch64->system_control_reg); aarch64->system_control_reg_curr = aarch64->system_control_reg; if (armv8->armv8_mmu.armv8_cache.info == -1) { armv8_identify_cache(armv8); armv8_read_mpidr(armv8); } - - armv8->armv8_mmu.mmu_enabled = + if (armv8->is_armv8r) { + armv8->armv8_mmu.mmu_enabled = 0; + } else { + armv8->armv8_mmu.mmu_enabled = (aarch64->system_control_reg & 0x1U) ? 1 : 0; + } armv8->armv8_mmu.armv8_cache.d_u_cache_enabled = (aarch64->system_control_reg & 0x4U) ? 1 : 0; armv8->armv8_mmu.armv8_cache.i_cache_enabled = @@ -1097,13 +1091,14 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres struct armv8_common *armv8 = target_to_armv8(target); struct aarch64_common *aarch64 = target_to_aarch64(target); int saved_retval = ERROR_OK; + int poll_retval; int retval; uint32_t edecr; armv8->last_run_control_op = ARMV8_RUNCONTROL_STEP; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1179,6 +1174,8 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres if (retval == ERROR_TARGET_TIMEOUT) saved_retval = aarch64_halt_one(target, HALT_SYNC); + poll_retval = aarch64_poll(target); + /* restore EDECR */ retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_EDECR, edecr); @@ -1195,6 +1192,9 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres if (saved_retval != ERROR_OK) return saved_retval; + if (poll_retval != ERROR_OK) + return poll_retval; + return ERROR_OK; } @@ -1257,7 +1257,7 @@ static int aarch64_set_breakpoint(struct target *target, | (byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_i].used = 1; - brp_list[brp_i].value = breakpoint->address & 0xFFFFFFFFFFFFFFFC; + brp_list[brp_i].value = breakpoint->address & 0xFFFFFFFFFFFFFFFCULL; brp_list[brp_i].control = control; bpt_value = brp_list[brp_i].value; @@ -1309,28 +1309,28 @@ static int aarch64_set_breakpoint(struct target *target, buf_set_u32(code, 0, 32, opcode); retval = target_read_memory(target, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; armv8_cache_d_inner_flush_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); retval = target_write_memory(target, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length, 1, code); if (retval != ERROR_OK) return retval; armv8_cache_d_inner_flush_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); armv8_cache_i_inner_inval_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); breakpoint->is_set = true; @@ -1462,7 +1462,7 @@ static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoin | (iva_byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_2].used = 1; - brp_list[brp_2].value = breakpoint->address & 0xFFFFFFFFFFFFFFFC; + brp_list[brp_2].value = breakpoint->address & 0xFFFFFFFFFFFFFFFCULL; brp_list[brp_2].control = control_iva; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_2].brpn, @@ -1586,29 +1586,29 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br /* restore original instruction (kept in target endianness) */ armv8_cache_d_inner_flush_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); if (breakpoint->length == 4) { retval = target_write_memory(target, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } else { retval = target_write_memory(target, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } armv8_cache_d_inner_flush_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); armv8_cache_i_inner_inval_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); } breakpoint->is_set = false; @@ -1849,7 +1849,7 @@ static int aarch64_remove_watchpoint(struct target *target, * find out which watchpoint hits * get exception address and compare the address to watchpoints */ -int aarch64_hit_watchpoint(struct target *target, +static int aarch64_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) { if (target->debug_reason != DBG_REASON_WATCHPOINT) @@ -1942,7 +1942,7 @@ static int aarch64_assert_reset(struct target *target) else if (reset_config & RESET_HAS_SRST) { bool srst_asserted = false; - if (target->reset_halt) { + if (target->reset_halt && !(reset_config & RESET_SRST_PULLS_TRST)) { if (target_was_examined(target)) { if (reset_config & RESET_SRST_NO_GATING) { @@ -1952,12 +1952,12 @@ static int aarch64_assert_reset(struct target *target) */ adapter_assert_reset(); srst_asserted = true; - - /* make sure to clear all sticky errors */ - mem_ap_write_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_DRCR, DRCR_CSE); } + /* make sure to clear all sticky errors */ + mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DRCR, DRCR_CSE); + /* set up Reset Catch debug event to halt the CPU after reset */ retval = aarch64_enable_reset_catch(target, true); if (retval != ERROR_OK) @@ -2026,9 +2026,13 @@ static int aarch64_deassert_reset(struct target *target) if (target->state != TARGET_HALTED) { LOG_WARNING("%s: ran after reset and before halt ...", target_name(target)); - retval = target_halt(target); - if (retval != ERROR_OK) - return retval; + if (target_was_examined(target)) { + retval = aarch64_halt_one(target, HALT_LAZY); + if (retval != ERROR_OK) + return retval; + } else { + target->state = TARGET_UNKNOWN; + } } } @@ -2043,6 +2047,11 @@ static int aarch64_write_cpu_memory_slow(struct target *target, struct arm *arm = &armv8->arm; int retval; + if (size > 4 && arm->core_state != ARM_STATE_AARCH64) { + LOG_ERROR("memory write sizes greater than 4 bytes is only supported for AArch64 state"); + return ERROR_FAIL; + } + armv8_reg_current(arm, 1)->dirty = true; /* change DCC to normal mode if necessary */ @@ -2055,22 +2064,32 @@ static int aarch64_write_cpu_memory_slow(struct target *target, } while (count) { - uint32_t data, opcode; + uint32_t opcode; + uint64_t data; - /* write the data to store into DTRRX */ + /* write the data to store into DTRRX (and DTRTX for 64-bit) */ if (size == 1) data = *buffer; else if (size == 2) data = target_buffer_get_u16(target, buffer); - else + else if (size == 4) data = target_buffer_get_u32(target, buffer); + else + data = target_buffer_get_u64(target, buffer); + retval = mem_ap_write_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_DTRRX, data); + armv8->debug_base + CPUV8_DBG_DTRRX, (uint32_t)data); + if (retval == ERROR_OK && size > 4) + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DTRTX, (uint32_t)(data >> 32)); if (retval != ERROR_OK) return retval; if (arm->core_state == ARM_STATE_AARCH64) - retval = dpm->instr_execute(dpm, ARMV8_MRS(SYSTEM_DBG_DTRRX_EL0, 1)); + if (size <= 4) + retval = dpm->instr_execute(dpm, ARMV8_MRS(SYSTEM_DBG_DTRRX_EL0, 1)); + else + retval = dpm->instr_execute(dpm, ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 1)); else retval = dpm->instr_execute(dpm, ARMV4_5_MRC(14, 0, 1, 0, 5, 0)); if (retval != ERROR_OK) @@ -2080,8 +2099,11 @@ static int aarch64_write_cpu_memory_slow(struct target *target, opcode = armv8_opcode(armv8, ARMV8_OPC_STRB_IP); else if (size == 2) opcode = armv8_opcode(armv8, ARMV8_OPC_STRH_IP); - else + else if (size == 4) opcode = armv8_opcode(armv8, ARMV8_OPC_STRW_IP); + else + opcode = armv8_opcode(armv8, ARMV8_OPC_STRD_IP); + retval = dpm->instr_execute(dpm, opcode); if (retval != ERROR_OK) return retval; @@ -2139,7 +2161,7 @@ static int aarch64_write_cpu_memory(struct target *target, uint32_t dscr; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2222,6 +2244,11 @@ static int aarch64_read_cpu_memory_slow(struct target *target, struct arm *arm = &armv8->arm; int retval; + if (size > 4 && arm->core_state != ARM_STATE_AARCH64) { + LOG_ERROR("memory read sizes greater than 4 bytes is only supported for AArch64 state"); + return ERROR_FAIL; + } + armv8_reg_current(arm, 1)->dirty = true; /* change DCC to normal mode (if necessary) */ @@ -2234,36 +2261,56 @@ static int aarch64_read_cpu_memory_slow(struct target *target, } while (count) { - uint32_t opcode, data; + uint32_t opcode; + uint32_t lower; + uint32_t higher; + uint64_t data; if (size == 1) opcode = armv8_opcode(armv8, ARMV8_OPC_LDRB_IP); else if (size == 2) opcode = armv8_opcode(armv8, ARMV8_OPC_LDRH_IP); - else + else if (size == 4) opcode = armv8_opcode(armv8, ARMV8_OPC_LDRW_IP); + else + opcode = armv8_opcode(armv8, ARMV8_OPC_LDRD_IP); + retval = dpm->instr_execute(dpm, opcode); if (retval != ERROR_OK) return retval; if (arm->core_state == ARM_STATE_AARCH64) - retval = dpm->instr_execute(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DTRTX_EL0, 1)); + if (size <= 4) + retval = dpm->instr_execute(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DTRTX_EL0, 1)); + else + retval = dpm->instr_execute(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0, 1)); else retval = dpm->instr_execute(dpm, ARMV4_5_MCR(14, 0, 1, 0, 5, 0)); if (retval != ERROR_OK) return retval; retval = mem_ap_read_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_DTRTX, &data); + armv8->debug_base + CPUV8_DBG_DTRTX, &lower); + if (retval == ERROR_OK) { + if (size > 4) + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DTRRX, &higher); + else + higher = 0; + } if (retval != ERROR_OK) return retval; + data = (uint64_t)lower | (uint64_t)higher << 32; + if (size == 1) *buffer = (uint8_t)data; else if (size == 2) target_buffer_set_u16(target, buffer, (uint16_t)data); + else if (size == 4) + target_buffer_set_u32(target, buffer, (uint32_t)data); else - target_buffer_set_u32(target, buffer, data); + target_buffer_set_u64(target, buffer, data); /* Advance */ buffer += size; @@ -2357,7 +2404,7 @@ static int aarch64_read_cpu_memory(struct target *target, address, size, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2554,15 +2601,21 @@ static int aarch64_examine_first(struct target *target) if (!pc) return ERROR_FAIL; - if (pc->adiv5_config.ap_num == DP_APSEL_INVALID) { - /* Search for the APB-AB */ - retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv8->debug_ap); - if (retval != ERROR_OK) { - LOG_ERROR("Could not find APB-AP for debug access"); - return retval; + if (!armv8->debug_ap) { + if (pc->adiv5_config.ap_num == DP_APSEL_INVALID) { + /* Search for the APB-AB */ + retval = dap_find_get_ap(swjdp, AP_TYPE_APB_AP, &armv8->debug_ap); + if (retval != ERROR_OK) { + LOG_ERROR("Could not find APB-AP for debug access"); + return retval; + } + } else { + armv8->debug_ap = dap_get_ap(swjdp, pc->adiv5_config.ap_num); + if (!armv8->debug_ap) { + LOG_ERROR("Cannot get AP"); + return ERROR_FAIL; + } } - } else { - armv8->debug_ap = dap_ap(swjdp, pc->adiv5_config.ap_num); } retval = mem_ap_init(armv8->debug_ap); @@ -2574,20 +2627,13 @@ static int aarch64_examine_first(struct target *target) armv8->debug_ap->memaccess_tck = 10; if (!target->dbgbase_set) { - target_addr_t dbgbase; - /* Get ROM Table base */ - uint32_t apid; - int32_t coreidx = target->coreid; - retval = dap_get_debugbase(armv8->debug_ap, &dbgbase, &apid); - if (retval != ERROR_OK) - return retval; /* Lookup Processor DAP */ - retval = dap_lookup_cs_component(armv8->debug_ap, dbgbase, ARM_CS_C9_DEVTYPE_CORE_DEBUG, - &armv8->debug_base, &coreidx); + retval = dap_lookup_cs_component(armv8->debug_ap, ARM_CS_C9_DEVTYPE_CORE_DEBUG, + &armv8->debug_base, target->coreid); if (retval != ERROR_OK) return retval; - LOG_DEBUG("Detected core %" PRId32 " dbgbase: " TARGET_ADDR_FMT - " apid: %08" PRIx32, coreidx, armv8->debug_base, apid); + LOG_DEBUG("Detected core %" PRId32 " dbgbase: " TARGET_ADDR_FMT, + target->coreid, armv8->debug_base); } else armv8->debug_base = target->dbgbase; @@ -2698,6 +2744,9 @@ static int aarch64_examine(struct target *target) if (retval == ERROR_OK) retval = aarch64_init_debug_access(target); + if (retval == ERROR_OK) + retval = aarch64_poll(target); + return retval; } @@ -2735,6 +2784,25 @@ static int aarch64_init_arch_info(struct target *target, return ERROR_OK; } +static int armv8r_target_create(struct target *target, Jim_Interp *interp) +{ + struct aarch64_private_config *pc = target->private_config; + struct aarch64_common *aarch64; + + if (adiv5_verify_config(&pc->adiv5_config) != ERROR_OK) + return ERROR_FAIL; + + aarch64 = calloc(1, sizeof(struct aarch64_common)); + if (!aarch64) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + aarch64->armv8_common.is_armv8r = true; + + return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap); +} + static int aarch64_target_create(struct target *target, Jim_Interp *interp) { struct aarch64_private_config *pc = target->private_config; @@ -2749,6 +2817,8 @@ static int aarch64_target_create(struct target *target, Jim_Interp *interp) return ERROR_FAIL; } + aarch64->armv8_common.is_armv8r = false; + return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap); } @@ -2758,6 +2828,9 @@ static void aarch64_deinit_target(struct target *target) struct armv8_common *armv8 = &aarch64->armv8_common; struct arm_dpm *dpm = &armv8->dpm; + if (armv8->debug_ap) + dap_put_ap(armv8->debug_ap); + armv8_free_reg_cache(target); free(aarch64->brp_list); free(dpm->dbp); @@ -2768,12 +2841,16 @@ static void aarch64_deinit_target(struct target *target) static int aarch64_mmu(struct target *target, int *enabled) { + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; if (target->state != TARGET_HALTED) { - LOG_ERROR("%s: target %s not halted", __func__, target_name(target)); - return ERROR_TARGET_INVALID; + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; } - - *enabled = target_to_aarch64(target)->armv8_common.armv8_mmu.mmu_enabled; + if (armv8->is_armv8r) + *enabled = 0; + else + *enabled = target_to_aarch64(target)->armv8_common.armv8_mmu.mmu_enabled; return ERROR_OK; } @@ -2935,15 +3012,15 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command) struct target *target = get_current_target(CMD_CTX); struct aarch64_common *aarch64 = target_to_aarch64(target); - static const struct jim_nvp nvp_maskisr_modes[] = { + static const struct nvp nvp_maskisr_modes[] = { { .name = "off", .value = AARCH64_ISRMASK_OFF }, { .name = "on", .value = AARCH64_ISRMASK_ON }, { .name = NULL, .value = -1 }, }; - const struct jim_nvp *n; + const struct nvp *n; if (CMD_ARGC > 0) { - n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); + n = nvp_name2value(nvp_maskisr_modes, CMD_ARGV[0]); if (!n->name) { LOG_ERROR("Unknown parameter: %s - should be off or on", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; @@ -2952,59 +3029,49 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command) aarch64->isrmasking_mode = n->value; } - n = jim_nvp_value2name_simple(nvp_maskisr_modes, aarch64->isrmasking_mode); + n = nvp_value2name(nvp_maskisr_modes, aarch64->isrmasking_mode); command_print(CMD, "aarch64 interrupt mask %s", n->name); return ERROR_OK; } -static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(aarch64_mcrmrc_command) { - struct command *c = jim_to_command(interp); - struct command_context *context; - struct target *target; - struct arm *arm; - int retval; bool is_mcr = false; - int arg_cnt = 0; + unsigned int arg_cnt = 5; - if (!strcmp(c->name, "mcr")) { + if (!strcmp(CMD_NAME, "mcr")) { is_mcr = true; - arg_cnt = 7; - } else { arg_cnt = 6; } - context = current_command_context(interp); - assert(context); + if (arg_cnt != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; - target = get_current_target(context); + struct target *target = get_current_target(CMD_CTX); if (!target) { - LOG_ERROR("%s: no current target", __func__); - return JIM_ERR; + command_print(CMD, "no current target"); + return ERROR_FAIL; } if (!target_was_examined(target)) { - LOG_ERROR("%s: not yet examined", target_name(target)); - return JIM_ERR; + command_print(CMD, "%s: not yet examined", target_name(target)); + return ERROR_TARGET_NOT_EXAMINED; } - arm = target_to_arm(target); + struct arm *arm = target_to_arm(target); if (!is_arm(arm)) { - LOG_ERROR("%s: not an ARM", target_name(target)); - return JIM_ERR; + command_print(CMD, "%s: not an ARM", target_name(target)); + return ERROR_FAIL; } - if (target->state != TARGET_HALTED) + if (target->state != TARGET_HALTED) { + command_print(CMD, "Error: [%s] not halted", target_name(target)); return ERROR_TARGET_NOT_HALTED; - - if (arm->core_state == ARM_STATE_AARCH64) { - LOG_ERROR("%s: not 32-bit arm target", target_name(target)); - return JIM_ERR; } - if (argc != arg_cnt) { - LOG_ERROR("%s: wrong number of arguments", __func__); - return JIM_ERR; + if (arm->core_state == ARM_STATE_AARCH64) { + command_print(CMD, "%s: not 32-bit arm target", target_name(target)); + return ERROR_FAIL; } int cpnum; @@ -3013,87 +3080,62 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) uint32_t crn; uint32_t crm; uint32_t value; - long l; /* NOTE: parameter sequence matches ARM instruction set usage: * MCR pNUM, op1, rX, CRn, CRm, op2 ; write CP from rX * MRC pNUM, op1, rX, CRn, CRm, op2 ; read CP into rX * The "rX" is necessarily omitted; it uses Tcl mechanisms. */ - retval = Jim_GetLong(interp, argv[1], &l); - if (retval != JIM_OK) - return retval; - if (l & ~0xf) { - LOG_ERROR("%s: %s %d out of range", __func__, - "coprocessor", (int) l); - return JIM_ERR; + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cpnum); + if (cpnum & ~0xf) { + command_print(CMD, "coprocessor %d out of range", cpnum); + return ERROR_COMMAND_ARGUMENT_INVALID; } - cpnum = l; - retval = Jim_GetLong(interp, argv[2], &l); - if (retval != JIM_OK) - return retval; - if (l & ~0x7) { - LOG_ERROR("%s: %s %d out of range", __func__, - "op1", (int) l); - return JIM_ERR; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], op1); + if (op1 & ~0x7) { + command_print(CMD, "op1 %d out of range", op1); + return ERROR_COMMAND_ARGUMENT_INVALID; } - op1 = l; - retval = Jim_GetLong(interp, argv[3], &l); - if (retval != JIM_OK) - return retval; - if (l & ~0xf) { - LOG_ERROR("%s: %s %d out of range", __func__, - "CRn", (int) l); - return JIM_ERR; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], crn); + if (crn & ~0xf) { + command_print(CMD, "CRn %d out of range", crn); + return ERROR_COMMAND_ARGUMENT_INVALID; } - crn = l; - retval = Jim_GetLong(interp, argv[4], &l); - if (retval != JIM_OK) - return retval; - if (l & ~0xf) { - LOG_ERROR("%s: %s %d out of range", __func__, - "CRm", (int) l); - return JIM_ERR; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], crm); + if (crm & ~0xf) { + command_print(CMD, "CRm %d out of range", crm); + return ERROR_COMMAND_ARGUMENT_INVALID; } - crm = l; - retval = Jim_GetLong(interp, argv[5], &l); - if (retval != JIM_OK) - return retval; - if (l & ~0x7) { - LOG_ERROR("%s: %s %d out of range", __func__, - "op2", (int) l); - return JIM_ERR; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], op2); + if (op2 & ~0x7) { + command_print(CMD, "op2 %d out of range", op2); + return ERROR_COMMAND_ARGUMENT_INVALID; } - op2 = l; - value = 0; - - if (is_mcr == true) { - retval = Jim_GetLong(interp, argv[6], &l); - if (retval != JIM_OK) - return retval; - value = l; + if (is_mcr) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[5], value); /* NOTE: parameters reordered! */ /* ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2) */ - retval = arm->mcr(target, cpnum, op1, op2, crn, crm, value); + int retval = arm->mcr(target, cpnum, op1, op2, crn, crm, value); if (retval != ERROR_OK) - return JIM_ERR; + return retval; } else { + value = 0; /* NOTE: parameters reordered! */ /* ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2) */ - retval = arm->mrc(target, cpnum, op1, op2, crn, crm, &value); + int retval = arm->mrc(target, cpnum, op1, op2, crn, crm, &value); if (retval != ERROR_OK) - return JIM_ERR; + return retval; - Jim_SetResult(interp, Jim_NewIntObj(interp, value)); + command_print(CMD, "0x%" PRIx32, value); } - return JIM_OK; + return ERROR_OK; } static const struct command_registration aarch64_exec_command_handlers[] = { @@ -3128,14 +3170,14 @@ static const struct command_registration aarch64_exec_command_handlers[] = { { .name = "mcr", .mode = COMMAND_EXEC, - .jim_handler = jim_mcrmrc, + .handler = aarch64_mcrmrc_command, .help = "write coprocessor register", .usage = "cpnum op1 CRn CRm op2 value", }, { .name = "mrc", .mode = COMMAND_EXEC, - .jim_handler = jim_mcrmrc, + .handler = aarch64_mcrmrc_command, .help = "read coprocessor register", .usage = "cpnum op1 CRn CRm op2", }, @@ -3147,8 +3189,6 @@ static const struct command_registration aarch64_exec_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -extern const struct command_registration semihosting_common_handlers[]; - static const struct command_registration aarch64_command_handlers[] = { { .name = "arm", @@ -3210,3 +3250,39 @@ struct target_type aarch64_target = { .mmu = aarch64_mmu, .virt2phys = aarch64_virt2phys, }; + +struct target_type armv8r_target = { + .name = "armv8r", + + .poll = aarch64_poll, + .arch_state = armv8_arch_state, + + .halt = aarch64_halt, + .resume = aarch64_resume, + .step = aarch64_step, + + .assert_reset = aarch64_assert_reset, + .deassert_reset = aarch64_deassert_reset, + + /* REVISIT allow exporting VFP3 registers ... */ + .get_gdb_arch = armv8_get_gdb_arch, + .get_gdb_reg_list = armv8_get_gdb_reg_list, + + .read_memory = aarch64_read_phys_memory, + .write_memory = aarch64_write_phys_memory, + + .add_breakpoint = aarch64_add_breakpoint, + .add_context_breakpoint = aarch64_add_context_breakpoint, + .add_hybrid_breakpoint = aarch64_add_hybrid_breakpoint, + .remove_breakpoint = aarch64_remove_breakpoint, + .add_watchpoint = aarch64_add_watchpoint, + .remove_watchpoint = aarch64_remove_watchpoint, + .hit_watchpoint = aarch64_hit_watchpoint, + + .commands = aarch64_command_handlers, + .target_create = armv8r_target_create, + .target_jim_configure = aarch64_jim_configure, + .init_target = aarch64_init_target, + .deinit_target = aarch64_deinit_target, + .examine = aarch64_examine, +}; diff --git a/src/target/aarch64.h b/src/target/aarch64.h index b57361f882..b265e82498 100644 --- a/src/target/aarch64.h +++ b/src/target/aarch64.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2015 by David Ung * - * * - * 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, write to the * - * Free Software Foundation, Inc., * ***************************************************************************/ #ifndef OPENOCD_TARGET_AARCH64_H @@ -21,7 +9,7 @@ #include "armv8.h" -#define AARCH64_COMMON_MAGIC 0x411fc082 +#define AARCH64_COMMON_MAGIC 0x41413634U #define CPUDBG_CPUID 0xD00 #define CPUDBG_CTYPR 0xD04 @@ -50,11 +38,13 @@ struct aarch64_brp { }; struct aarch64_common { - int common_magic; + unsigned int common_magic; + + struct armv8_common armv8_common; /* Context information */ - uint32_t system_control_reg; - uint32_t system_control_reg_curr; + uint64_t system_control_reg; + uint64_t system_control_reg_curr; /* Breakpoint register pairs */ int brp_num_context; @@ -67,8 +57,6 @@ struct aarch64_common { int wp_num_available; struct aarch64_brp *wp_list; - struct armv8_common armv8_common; - enum aarch64_isrmasking_mode isrmasking_mode; }; diff --git a/src/target/adi_v5_dapdirect.c b/src/target/adi_v5_dapdirect.c index c0deee165f..d198dacf39 100644 --- a/src/target/adi_v5_dapdirect.c +++ b/src/target/adi_v5_dapdirect.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright (C) 2019, STMicroelectronics - All Rights Reserved * Author(s): Antonio Borneo <borneo.antonio@gmail.com> for STMicroelectronics - * - * 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/>. */ /** @@ -69,8 +58,16 @@ static const struct command_registration dapdirect_jtag_subcommand_handlers[] = { .name = "newtap", .mode = COMMAND_CONFIG, - .jim_handler = jim_jtag_newtap, - .help = "declare a new TAP" + .handler = handle_jtag_newtap, + .help = "declare a new TAP", + .usage = "basename tap_type '-irlen' count " + "['-enable'|'-disable'] " + "['-expected_id' number] " + "['-ignore-version'] " + "['-ignore-bypass'] " + "['-ircapture' number] " + "['-ir-bypass' number] " + "['-mask' number]", }, { .name = "init", @@ -93,12 +90,18 @@ static const struct command_registration dapdirect_jtag_subcommand_handlers[] = { .name = "tapisenabled", .mode = COMMAND_EXEC, - .jim_handler = jim_jtag_tap_enabler, + .handler = handle_jtag_tap_enabler, + .help = "Returns a Tcl boolean (0/1) indicating whether " + "the TAP is enabled (1) or not (0).", + .usage = "tap_name", }, { .name = "tapenable", .mode = COMMAND_EXEC, - .jim_handler = jim_jtag_tap_enabler, + .handler = handle_jtag_tap_enabler, + .help = "Try to enable the specified TAP using the " + "'tap-enable' TAP event.", + .usage = "tap_name", }, { .name = "tapdisable", @@ -115,7 +118,8 @@ static const struct command_registration dapdirect_jtag_subcommand_handlers[] = { .name = "cget", .mode = COMMAND_EXEC, - .jim_handler = jim_jtag_configure, + .handler = handle_jtag_configure, + .usage = "", }, { .name = "names", @@ -146,8 +150,16 @@ static const struct command_registration dapdirect_swd_subcommand_handlers[] = { { .name = "newdap", .mode = COMMAND_CONFIG, - .jim_handler = jim_jtag_newtap, + .handler = handle_jtag_newtap, .help = "declare a new SWD DAP", + .usage = "basename dap_type ['-irlen' count] " + "['-enable'|'-disable'] " + "['-expected_id' number] " + "['-ignore-version'] " + "['-ignore-bypass'] " + "['-ircapture' number] " + "['-ir-bypass' number] " + "['-mask' number]", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/adi_v5_jtag.c b/src/target/adi_v5_jtag.c index be625807c7..8d54a50fb0 100644 --- a/src/target/adi_v5_jtag.c +++ b/src/target/adi_v5_jtag.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * lundin@mlu.mine.nu @@ -10,24 +12,13 @@ * * Copyright (C) 2009-2010 by David Brownell * - * 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/>. + * Copyright (C) 2020-2021, Ampere Computing LLC * ***************************************************************************/ /** * @file * This file implements JTAG transport support for cores implementing - the ARM Debug Interface version 5 (ADIv5). + the ARM Debug Interface version 5 (ADIv5) and version 6 (ADIv6). */ #ifdef HAVE_CONFIG_H @@ -49,13 +40,15 @@ #define JTAG_DP_IDCODE 0xFE /* three-bit ACK values for DPACC and APACC reads */ -#define JTAG_ACK_OK_FAULT 0x2 -#define JTAG_ACK_WAIT 0x1 +#define JTAG_ACK_WAIT 0x1 /* ADIv5 and ADIv6 */ +#define JTAG_ACK_OK_FAULT 0x2 /* ADIv5 */ +#define JTAG_ACK_FAULT 0x2 /* ADIv6 */ +#define JTAG_ACK_OK 0x4 /* ADIV6 */ static int jtag_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack); #ifdef DEBUG_WAIT -static const char *dap_reg_name(int instr, int reg_addr) +static const char *dap_reg_name(struct adiv5_dap *dap, uint8_t instr, uint16_t reg_addr) { char *reg_name = "UNK"; @@ -83,41 +76,32 @@ static const char *dap_reg_name(int instr, int reg_addr) } if (instr == JTAG_DP_APACC) { - switch (reg_addr) { - case MEM_AP_REG_CSW: + if (reg_addr == MEM_AP_REG_CSW(dap)) reg_name = "CSW"; - break; - case MEM_AP_REG_TAR: + else if (reg_addr == MEM_AP_REG_TAR(dap)) reg_name = "TAR"; - break; - case MEM_AP_REG_DRW: + else if (reg_addr == MEM_AP_REG_TAR64(dap)) + reg_name = "TAR64"; + else if (reg_addr == MEM_AP_REG_DRW(dap)) reg_name = "DRW"; - break; - case MEM_AP_REG_BD0: + else if (reg_addr == MEM_AP_REG_BD0(dap)) reg_name = "BD0"; - break; - case MEM_AP_REG_BD1: + else if (reg_addr == MEM_AP_REG_BD1(dap)) reg_name = "BD1"; - break; - case MEM_AP_REG_BD2: + else if (reg_addr == MEM_AP_REG_BD2(dap)) reg_name = "BD2"; - break; - case MEM_AP_REG_BD3: + else if (reg_addr == MEM_AP_REG_BD3(dap)) reg_name = "BD3"; - break; - case MEM_AP_REG_CFG: + else if (reg_addr == MEM_AP_REG_CFG(dap)) reg_name = "CFG"; - break; - case MEM_AP_REG_BASE: + else if (reg_addr == MEM_AP_REG_BASE(dap)) reg_name = "BASE"; - break; - case AP_REG_IDR: + else if (reg_addr == MEM_AP_REG_BASE64(dap)) + reg_name = "BASE64"; + else if (reg_addr == AP_REG_IDR(dap)) reg_name = "IDR"; - break; - default: + else reg_name = "UNK"; - break; - } } return reg_name; @@ -127,12 +111,12 @@ static const char *dap_reg_name(int instr, int reg_addr) struct dap_cmd { struct list_head lh; uint8_t instr; - uint8_t reg_addr; + uint16_t reg_addr; uint8_t rnw; uint8_t *invalue; uint8_t ack; uint32_t memaccess_tck; - uint32_t dp_select; + uint64_t dp_select; struct scan_field fields[2]; uint8_t out_addr_buf; @@ -147,17 +131,38 @@ struct dap_cmd_pool { struct dap_cmd cmd; }; -static void log_dap_cmd(const char *header, struct dap_cmd *el) +static void log_dap_cmd(struct adiv5_dap *dap, const char *header, struct dap_cmd *el) { #ifdef DEBUG_WAIT + const char *ack; + switch (el->ack) { + case JTAG_ACK_WAIT: /* ADIv5 and ADIv6 */ + ack = "WAIT"; + break; + case JTAG_ACK_OK_FAULT: /* ADIv5, same value as JTAG_ACK_FAULT */ + /* case JTAG_ACK_FAULT: */ /* ADIv6 */ + if (is_adiv6(dap)) + ack = "FAULT"; + else + ack = "OK"; + break; + case JTAG_ACK_OK: /* ADIv6 */ + if (is_adiv6(dap)) { + ack = "OK"; + break; + } + /* fall-through */ + default: + ack = "INVAL"; + break; + } LOG_DEBUG("%s: %2s %6s %5s 0x%08x 0x%08x %2s", header, el->instr == JTAG_DP_APACC ? "AP" : "DP", - dap_reg_name(el->instr, el->reg_addr), + dap_reg_name(dap, el->instr, el->reg_addr), el->rnw == DPAP_READ ? "READ" : "WRITE", buf_get_u32(el->outvalue_buf, 0, 32), buf_get_u32(el->invalue, 0, 32), - el->ack == JTAG_ACK_OK_FAULT ? "OK" : - (el->ack == JTAG_ACK_WAIT ? "WAIT" : "INVAL")); + ack); #endif } @@ -170,7 +175,7 @@ static int jtag_limit_queue_size(struct adiv5_dap *dap) } static struct dap_cmd *dap_cmd_new(struct adiv5_dap *dap, uint8_t instr, - uint8_t reg_addr, uint8_t rnw, + uint16_t reg_addr, uint8_t rnw, uint8_t *outvalue, uint8_t *invalue, uint32_t memaccess_tck) { @@ -268,17 +273,14 @@ static int adi_jtag_dp_scan_cmd(struct adiv5_dap *dap, struct dap_cmd *cmd, uint jtag_add_dr_scan(tap, 2, cmd->fields, TAP_IDLE); - /* Add specified number of tck clocks after starting memory bus - * access, giving the hardware time to complete the access. + /* Add specified number of tck clocks after starting AP register + * access or memory bus access, giving the hardware time to complete + * the access. * They provide more time for the (MEM) AP to complete the read ... - * See "Minimum Response Time" for JTAG-DP, in the ADIv5 spec. + * See "Minimum Response Time" for JTAG-DP, in the ADIv5/ADIv6 spec. */ - if (cmd->instr == JTAG_DP_APACC) { - if (((cmd->reg_addr == MEM_AP_REG_DRW) - || ((cmd->reg_addr & 0xF0) == MEM_AP_REG_BD0)) - && (cmd->memaccess_tck != 0)) - jtag_add_runtest(cmd->memaccess_tck, TAP_IDLE); - } + if (cmd->instr == JTAG_DP_APACC && cmd->memaccess_tck != 0) + jtag_add_runtest(cmd->memaccess_tck, TAP_IDLE); return ERROR_OK; } @@ -296,7 +298,7 @@ static int adi_jtag_dp_scan_cmd_sync(struct adiv5_dap *dap, struct dap_cmd *cmd, /** * Scan DPACC or APACC using target ordered uint8_t buffers. No endianness - * conversions are performed. See section 4.4.3 of the ADIv5 spec, which + * conversions are performed. See section 4.4.3 of the ADIv5/ADIv6 spec, which * discusses operations which access these registers. * * Note that only one scan is performed. If rnw is set, a separate scan @@ -315,7 +317,7 @@ static int adi_jtag_dp_scan_cmd_sync(struct adiv5_dap *dap, struct dap_cmd *cmd, */ static int adi_jtag_dp_scan(struct adiv5_dap *dap, - uint8_t instr, uint8_t reg_addr, uint8_t rnw, + uint8_t instr, uint16_t reg_addr, uint8_t rnw, uint8_t *outvalue, uint8_t *invalue, uint32_t memaccess_tck, uint8_t *ack) { @@ -342,13 +344,35 @@ static int adi_jtag_dp_scan(struct adiv5_dap *dap, * must be different). */ static int adi_jtag_dp_scan_u32(struct adiv5_dap *dap, - uint8_t instr, uint8_t reg_addr, uint8_t rnw, + uint8_t instr, uint16_t reg_addr, uint8_t rnw, uint32_t outvalue, uint32_t *invalue, uint32_t memaccess_tck, uint8_t *ack) { uint8_t out_value_buf[4]; int retval; + uint64_t sel = (reg_addr >> 4) & DP_SELECT_DPBANK; + + /* No need to change SELECT or RDBUFF as they are not banked */ + if (instr == JTAG_DP_DPACC && reg_addr != DP_SELECT && reg_addr != DP_RDBUFF + && (!dap->select_valid || sel != (dap->select & DP_SELECT_DPBANK))) { + /* Use the AP part of dap->select regardless of dap->select_valid: + * if !dap->select_valid + * dap->select contains a speculative value likely going to be used + * in the following swd_queue_ap_bankselect() */ + sel |= dap->select & SELECT_AP_MASK; + + LOG_DEBUG_IO("DP BANK SELECT: %" PRIx32, (uint32_t)sel); + + buf_set_u32(out_value_buf, 0, 32, (uint32_t)sel); + retval = adi_jtag_dp_scan(dap, JTAG_DP_DPACC, + DP_SELECT, DPAP_WRITE, out_value_buf, NULL, 0, NULL); + if (retval != ERROR_OK) + return retval; + + dap->select = sel; + dap->select_valid = true; + } buf_set_u32(out_value_buf, 0, 32, outvalue); retval = adi_jtag_dp_scan(dap, instr, reg_addr, rnw, @@ -377,7 +401,7 @@ static int adi_jtag_finish_read(struct adiv5_dap *dap) } static int adi_jtag_scan_inout_check_u32(struct adiv5_dap *dap, - uint8_t instr, uint8_t reg_addr, uint8_t rnw, + uint8_t instr, uint16_t reg_addr, uint8_t rnw, uint32_t outvalue, uint32_t *invalue, uint32_t memaccess_tck) { int retval; @@ -416,14 +440,19 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) /* skip all completed transactions up to the first WAIT */ list_for_each_entry(el, &dap->cmd_journal, lh) { - if (el->ack == JTAG_ACK_OK_FAULT) { - log_dap_cmd("LOG", el); + /* + * JTAG_ACK_OK_FAULT (ADIv5) and JTAG_ACK_FAULT (ADIv6) are equal so + * the following statement is checking to see if an acknowledgment of + * OK or FAULT is generated for ADIv5 or ADIv6 + */ + if (el->ack == JTAG_ACK_OK_FAULT || (is_adiv6(dap) && el->ack == JTAG_ACK_OK)) { + log_dap_cmd(dap, "LOG", el); } else if (el->ack == JTAG_ACK_WAIT) { found_wait = 1; break; } else { LOG_ERROR("Invalid ACK (%1x) in DAP response", el->ack); - log_dap_cmd("ERR", el); + log_dap_cmd(dap, "ERR", el); retval = ERROR_JTAG_DEVICE_ERROR; goto done; } @@ -436,14 +465,15 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) if (found_wait && el != list_first_entry(&dap->cmd_journal, struct dap_cmd, lh)) { prev = list_entry(el->lh.prev, struct dap_cmd, lh); if (prev->rnw == DPAP_READ) { - log_dap_cmd("PND", prev); + log_dap_cmd(dap, "PND", prev); /* search for the next OK transaction, it contains * the result of the previous READ */ tmp = el; list_for_each_entry_from(tmp, &dap->cmd_journal, lh) { - if (tmp->ack == JTAG_ACK_OK_FAULT) { + /* The following check covers OK and FAULT ACKs for both ADIv5 and ADIv6 */ + if (tmp->ack == JTAG_ACK_OK_FAULT || (is_adiv6(dap) && tmp->ack == JTAG_ACK_OK)) { /* recover the read value */ - log_dap_cmd("FND", tmp); + log_dap_cmd(dap, "FND", tmp); if (el->invalue != el->invalue_buf) { uint32_t invalue = le_to_h_u32(tmp->invalue); memcpy(el->invalue, &invalue, sizeof(uint32_t)); @@ -454,7 +484,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) } if (prev) { - log_dap_cmd("LST", el); + log_dap_cmd(dap, "LST", el); /* * At this point we're sure that no previous @@ -476,8 +506,9 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) retval = adi_jtag_dp_scan_cmd_sync(dap, tmp, NULL); if (retval != ERROR_OK) break; - if (tmp->ack == JTAG_ACK_OK_FAULT) { - log_dap_cmd("FND", tmp); + /* The following check covers OK and FAULT ACKs for both ADIv5 and ADIv6 */ + if (tmp->ack == JTAG_ACK_OK_FAULT || (is_adiv6(dap) && tmp->ack == JTAG_ACK_OK)) { + log_dap_cmd(dap, "FND", tmp); if (el->invalue != el->invalue_buf) { uint32_t invalue = le_to_h_u32(tmp->invalue); memcpy(el->invalue, &invalue, sizeof(uint32_t)); @@ -486,7 +517,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) } if (tmp->ack != JTAG_ACK_WAIT) { LOG_ERROR("Invalid ACK (%1x) in DAP response", tmp->ack); - log_dap_cmd("ERR", tmp); + log_dap_cmd(dap, "ERR", tmp); retval = ERROR_JTAG_DEVICE_ERROR; break; } @@ -495,9 +526,12 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) if (retval == ERROR_OK) { /* timeout happened */ - if (tmp->ack != JTAG_ACK_OK_FAULT) { + if (tmp->ack == JTAG_ACK_WAIT) { LOG_ERROR("Timeout during WAIT recovery"); - dap->select = DP_SELECT_INVALID; + dap->select_valid = false; + dap->select1_valid = false; + /* Keep dap->select unchanged, the same AP and AP bank + * is likely going to be used further */ jtag_ap_q_abort(dap, NULL); /* clear the sticky overrun condition */ adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, @@ -523,7 +557,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) /* move all remaining transactions over to the replay list */ list_for_each_entry_safe_from(el, tmp, &dap->cmd_journal, lh) { - log_dap_cmd("REP", el); + log_dap_cmd(dap, "REP", el); list_move_tail(&el->lh, &replay_list); } @@ -532,7 +566,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) /* check for overrun condition in the last batch of transactions */ if (found_wait) { - LOG_INFO("DAP transaction stalled (WAIT) - slowing down"); + LOG_INFO("DAP transaction stalled (WAIT) - slowing down and resending"); /* clear the sticky overrun condition */ retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, DP_CTRL_STAT, DPAP_WRITE, @@ -543,15 +577,21 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) /* restore SELECT register first */ if (!list_empty(&replay_list)) { el = list_first_entry(&replay_list, struct dap_cmd, lh); + + uint8_t out_value_buf[4]; + buf_set_u32(out_value_buf, 0, 32, (uint32_t)(el->dp_select)); + tmp = dap_cmd_new(dap, JTAG_DP_DPACC, - DP_SELECT, DPAP_WRITE, (uint8_t *)&el->dp_select, NULL, 0); + DP_SELECT, DPAP_WRITE, out_value_buf, NULL, 0); if (!tmp) { retval = ERROR_JTAG_DEVICE_ERROR; goto done; } list_add(&tmp->lh, &replay_list); - dap->select = DP_SELECT_INVALID; + /* TODO: ADIv6 DP SELECT1 handling */ + + dap->select_valid = false; } list_for_each_entry_safe(el, tmp, &replay_list, lh) { @@ -560,8 +600,8 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) retval = adi_jtag_dp_scan_cmd_sync(dap, el, NULL); if (retval != ERROR_OK) break; - log_dap_cmd("REC", el); - if (el->ack == JTAG_ACK_OK_FAULT) { + log_dap_cmd(dap, "REC", el); + if (el->ack == JTAG_ACK_OK_FAULT || (is_adiv6(dap) && el->ack == JTAG_ACK_OK)) { if (el->invalue != el->invalue_buf) { uint32_t invalue = le_to_h_u32(el->invalue); memcpy(el->invalue, &invalue, sizeof(uint32_t)); @@ -570,11 +610,11 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) } if (el->ack != JTAG_ACK_WAIT) { LOG_ERROR("Invalid ACK (%1x) in DAP response", el->ack); - log_dap_cmd("ERR", el); + log_dap_cmd(dap, "ERR", el); retval = ERROR_JTAG_DEVICE_ERROR; break; } - LOG_INFO("DAP transaction stalled during replay (WAIT) - resending"); + LOG_DEBUG("DAP transaction stalled during replay (WAIT) - resending"); /* clear the sticky overrun condition */ retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, DP_CTRL_STAT, DPAP_WRITE, @@ -584,9 +624,12 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) } while (timeval_ms() - time_now < 1000); if (retval == ERROR_OK) { - if (el->ack != JTAG_ACK_OK_FAULT) { + if (el->ack == JTAG_ACK_WAIT) { LOG_ERROR("Timeout during WAIT recovery"); - dap->select = DP_SELECT_INVALID; + dap->select_valid = false; + dap->select1_valid = false; + /* Keep dap->select unchanged, the same AP and AP bank + * is likely going to be used further */ jtag_ap_q_abort(dap, NULL); /* clear the sticky overrun condition */ adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, @@ -640,10 +683,10 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap) if (ctrlstat & SSTICKYORUN) LOG_DEBUG("JTAG-DP STICKY OVERRUN"); - /* Clear Sticky Error Bits */ + /* Clear Sticky Error and Sticky Overrun Bits */ retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, DP_CTRL_STAT, DPAP_WRITE, - dap->dp_ctrl_stat | SSTICKYERR, NULL, 0); + dap->dp_ctrl_stat | SSTICKYERR | SSTICKYORUN, NULL, 0); if (retval != ERROR_OK) goto done; @@ -719,18 +762,60 @@ static int jtag_dp_q_write(struct adiv5_dap *dap, unsigned reg, return retval; } -/** Select the AP register bank matching bits 7:4 of reg. */ +/** Select the AP register bank */ static int jtag_ap_q_bankselect(struct adiv5_ap *ap, unsigned reg) { + int retval; struct adiv5_dap *dap = ap->dap; - uint32_t sel = ((uint32_t)ap->ap_num << 24) | (reg & 0x000000F0); + uint64_t sel; - if (sel == dap->select) - return ERROR_OK; + if (is_adiv6(dap)) + sel = ap->ap_num | (reg & 0x00000FF0); + else + sel = (ap->ap_num << 24) | (reg & ADIV5_DP_SELECT_APBANK); - dap->select = sel; + uint64_t sel_diff = (sel ^ dap->select) & SELECT_AP_MASK; - return jtag_dp_q_write(dap, DP_SELECT, sel); + bool set_select = !dap->select_valid || (sel_diff & 0xffffffffull); + bool set_select1 = is_adiv6(dap) && dap->asize > 32 + && (!dap->select1_valid + || sel_diff & (0xffffffffull << 32)); + + if (set_select && set_select1) { + /* Prepare DP bank for DP_SELECT1 now to save one write */ + sel |= (DP_SELECT1 >> 4) & DP_SELECT_DPBANK; + } else { + /* Use the DP part of dap->select regardless of dap->select_valid: + * if !dap->select_valid + * dap->select contains a speculative value likely going to be used + * in the following swd_queue_dp_bankselect(). + * Moreover dap->select_valid should never be false here as a DP bank + * is always selected before selecting an AP bank */ + sel |= dap->select & DP_SELECT_DPBANK; + } + + if (set_select) { + LOG_DEBUG_IO("AP BANK SELECT: %" PRIx32, (uint32_t)sel); + + retval = jtag_dp_q_write(dap, DP_SELECT, (uint32_t)sel); + if (retval != ERROR_OK) { + dap->select_valid = false; + return retval; + } + } + + if (set_select1) { + LOG_DEBUG_IO("AP BANK SELECT1: %" PRIx32, (uint32_t)(sel >> 32)); + + retval = jtag_dp_q_write(dap, DP_SELECT1, (uint32_t)(sel >> 32)); + if (retval != ERROR_OK) { + dap->select1_valid = false; + return retval; + } + } + + dap->select = sel; + return ERROR_OK; } static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg, diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index 6835042437..6d6f287b05 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * * Copyright (C) 2010 by David Brownell - * - * 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/>. ***************************************************************************/ /** @@ -24,11 +13,12 @@ * is a transport level interface, with "target/arm_adi_v5.[hc]" code * understanding operation semantics, shared with the JTAG transport. * - * Single-DAP support only. + * Single DAP and multidrop-SWD support. * * for details, see "ARM IHI 0031A" * ARM Debug Interface v5 Architecture Specification * especially section 5.3 for SWD protocol + * and "ARM IHI 0074C" ARM Debug Interface Architecture Specification ADIv6.0 * * On many chips (most current Cortex-M3 parts) SWD is a run-time alternative * to JTAG. Boards may support one or both. There are also SWD-only chips, @@ -58,6 +48,8 @@ static bool do_sync; static struct adiv5_dap *swd_multidrop_selected_dap; +static bool swd_multidrop_in_swd_state; + static int swd_queue_dp_write_inner(struct adiv5_dap *dap, unsigned int reg, uint32_t data); @@ -109,27 +101,31 @@ static inline int check_sync(struct adiv5_dap *dap) return do_sync ? swd_run_inner(dap) : ERROR_OK; } -/** Select the DP register bank matching bits 7:4 of reg. */ +/** Select the DP register bank */ static int swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned int reg) { - /* Only register address 4 is banked. */ - if ((reg & 0xf) != 4) + /* Only register address 0 (ADIv6 only) and 4 are banked. */ + if ((reg & 0xf) > 4) return ERROR_OK; - uint32_t select_dp_bank = (reg & 0x000000F0) >> 4; - uint32_t sel = select_dp_bank - | (dap->select & (DP_SELECT_APSEL | DP_SELECT_APBANK)); + uint32_t sel = (reg >> 4) & DP_SELECT_DPBANK; - if (sel == dap->select) + /* DP register 0 is not mapped according to ADIv5 + * whereas ADIv6 ensures DPBANKSEL = 0 after line reset */ + if ((dap->select_valid || ((reg & 0xf) == 0 && dap->select_dpbanksel_valid)) + && (sel == (dap->select & DP_SELECT_DPBANK))) return ERROR_OK; - dap->select = sel; + /* Use the AP part of dap->select regardless of dap->select_valid: + * if !dap->select_valid + * dap->select contains a speculative value likely going to be used + * in the following swd_queue_ap_bankselect() */ + sel |= (uint32_t)(dap->select & SELECT_AP_MASK); - int retval = swd_queue_dp_write_inner(dap, DP_SELECT, sel); - if (retval != ERROR_OK) - dap->select = DP_SELECT_INVALID; + LOG_DEBUG_IO("DP BANK SELECT: %" PRIx32, sel); - return retval; + /* dap->select cache gets updated in the following call */ + return swd_queue_dp_write_inner(dap, DP_SELECT, sel); } static int swd_queue_dp_read_inner(struct adiv5_dap *dap, unsigned int reg, @@ -157,24 +153,31 @@ static int swd_queue_dp_write_inner(struct adiv5_dap *dap, unsigned int reg, swd_finish_read(dap); if (reg == DP_SELECT) { - dap->select = data & (DP_SELECT_APSEL | DP_SELECT_APBANK | DP_SELECT_DPBANK); + dap->select = data | (dap->select & (0xffffffffull << 32)); swd->write_reg(swd_cmd(false, false, reg), data, 0); retval = check_sync(dap); - if (retval != ERROR_OK) - dap->select = DP_SELECT_INVALID; + dap->select_valid = (retval == ERROR_OK); + dap->select_dpbanksel_valid = dap->select_valid; return retval; } + if (reg == DP_SELECT1) + dap->select = ((uint64_t)data << 32) | (dap->select & 0xffffffffull); + retval = swd_queue_dp_bankselect(dap, reg); - if (retval != ERROR_OK) - return retval; + if (retval == ERROR_OK) { + swd->write_reg(swd_cmd(false, false, reg), data, 0); - swd->write_reg(swd_cmd(false, false, reg), data, 0); + retval = check_sync(dap); + } - return check_sync(dap); + if (reg == DP_SELECT1) + dap->select1_valid = (retval == ERROR_OK); + + return retval; } @@ -186,7 +189,26 @@ static int swd_multidrop_select_inner(struct adiv5_dap *dap, uint32_t *dpidr_ptr assert(dap_is_multidrop(dap)); - swd_send_sequence(dap, LINE_RESET); + /* Send JTAG_TO_DORMANT and DORMANT_TO_SWD just once + * and then use shorter LINE_RESET until communication fails */ + if (!swd_multidrop_in_swd_state) { + swd_send_sequence(dap, JTAG_TO_DORMANT); + swd_send_sequence(dap, DORMANT_TO_SWD); + } else { + swd_send_sequence(dap, LINE_RESET); + } + + /* + * Zero dap->select and set dap->select_dpbanksel_valid + * to skip the write to DP_SELECT before DPIDR read, avoiding + * the protocol error. + * Clear the other validity flags because the rest of the DP + * SELECT and SELECT1 registers is unknown after line reset. + */ + dap->select = 0; + dap->select_dpbanksel_valid = true; + dap->select_valid = false; + dap->select1_valid = false; retval = swd_queue_dp_write_inner(dap, DP_TARGETSEL, dap->multidrop_targetsel); if (retval != ERROR_OK) @@ -233,6 +255,7 @@ static int swd_multidrop_select_inner(struct adiv5_dap *dap, uint32_t *dpidr_ptr LOG_DEBUG_IO("Selected DP_TARGETSEL 0x%08" PRIx32, dap->multidrop_targetsel); swd_multidrop_selected_dap = dap; + swd_multidrop_in_swd_state = true; if (dpidr_ptr) *dpidr_ptr = dpidr; @@ -267,6 +290,8 @@ static int swd_multidrop_select(struct adiv5_dap *dap) LOG_DEBUG("Failed to select multidrop %s, retrying...", adiv5_dap_name(dap)); + /* we going to retry localy, do not ask for full reconnect */ + dap->do_reconnect = false; } return retval; @@ -280,8 +305,9 @@ static int swd_connect_multidrop(struct adiv5_dap *dap) int64_t timeout = timeval_ms() + 500; do { - swd_send_sequence(dap, JTAG_TO_DORMANT); - swd_send_sequence(dap, DORMANT_TO_SWD); + /* Do not make any assumptions about SWD state in case of reconnect */ + if (dap->do_reconnect) + swd_multidrop_in_swd_state = false; /* Clear link state, including the SELECT cache. */ dap->do_reconnect = false; @@ -292,6 +318,7 @@ static int swd_connect_multidrop(struct adiv5_dap *dap) if (retval == ERROR_OK) break; + swd_multidrop_in_swd_state = false; alive_sleep(1); } while (timeval_ms() < timeout); @@ -302,6 +329,7 @@ static int swd_connect_multidrop(struct adiv5_dap *dap) return retval; } + swd_multidrop_in_swd_state = true; LOG_INFO("SWD DPIDR 0x%08" PRIx32 ", DLPIDR 0x%08" PRIx32, dpidr, dlpidr); @@ -326,6 +354,22 @@ static int swd_connect_single(struct adiv5_dap *dap) dap->do_reconnect = false; dap_invalidate_cache(dap); + /* The sequences to enter in SWD (JTAG_TO_SWD and DORMANT_TO_SWD) end + * with a SWD line reset sequence (50 clk with SWDIO high). + * From ARM IHI 0031F ADIv5.2 and ARM IHI 0074C ADIv6.0, + * chapter B4.3.3 "Connection and line reset sequence": + * - DPv3 (ADIv6) only: line reset sets DP_SELECT_DPBANK to zero; + * - read of DP_DPIDR takes the connection out of reset; + * - write of DP_TARGETSEL keeps the connection in reset; + * - other accesses return protocol error (SWDIO not driven by target). + * + * dap_invalidate_cache() sets dap->select to zero and all validity + * flags to invalid. Set dap->select_dpbanksel_valid only + * to skip the write to DP_SELECT, avoiding the protocol error. + * Read DP_DPIDR to get out of reset. + */ + dap->select_dpbanksel_valid = true; + retval = swd_queue_dp_read_inner(dap, DP_DPIDR, &dpidr); if (retval == ERROR_OK) { retval = swd_run_inner(dap); @@ -362,6 +406,13 @@ static int swd_connect_single(struct adiv5_dap *dap) return retval; } +static int swd_pre_connect(struct adiv5_dap *dap) +{ + swd_multidrop_in_swd_state = false; + + return ERROR_OK; +} + static int swd_connect(struct adiv5_dap *dap) { int status; @@ -470,24 +521,55 @@ static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, return swd_queue_dp_write_inner(dap, reg, data); } -/** Select the AP register bank matching bits 7:4 of reg. */ +/** Select the AP register bank */ static int swd_queue_ap_bankselect(struct adiv5_ap *ap, unsigned reg) { + int retval; struct adiv5_dap *dap = ap->dap; - uint32_t sel = ((uint32_t)ap->ap_num << 24) - | (reg & 0x000000F0) - | (dap->select & DP_SELECT_DPBANK); + uint64_t sel; - if (sel == dap->select) - return ERROR_OK; + if (is_adiv6(dap)) + sel = ap->ap_num | (reg & 0x00000FF0); + else + sel = (ap->ap_num << 24) | (reg & ADIV5_DP_SELECT_APBANK); - dap->select = sel; + uint64_t sel_diff = (sel ^ dap->select) & SELECT_AP_MASK; - int retval = swd_queue_dp_write_inner(dap, DP_SELECT, sel); - if (retval != ERROR_OK) - dap->select = DP_SELECT_INVALID; + bool set_select = !dap->select_valid || (sel_diff & 0xffffffffull); + bool set_select1 = is_adiv6(dap) && dap->asize > 32 + && (!dap->select1_valid + || sel_diff & (0xffffffffull << 32)); - return retval; + if (set_select && set_select1) { + /* Prepare DP bank for DP_SELECT1 now to save one write */ + sel |= (DP_SELECT1 & 0x000000f0) >> 4; + } else { + /* Use the DP part of dap->select regardless of dap->select_valid: + * if !dap->select_valid + * dap->select contains a speculative value likely going to be used + * in the following swd_queue_dp_bankselect(). + * Moreover dap->select_valid should never be false here as a DP bank + * is always selected before selecting an AP bank */ + sel |= dap->select & DP_SELECT_DPBANK; + } + + if (set_select) { + LOG_DEBUG_IO("AP BANK SELECT: %" PRIx32, (uint32_t)sel); + + retval = swd_queue_dp_write(dap, DP_SELECT, (uint32_t)sel); + if (retval != ERROR_OK) + return retval; + } + + if (set_select1) { + LOG_DEBUG_IO("AP BANK SELECT1: %" PRIx32, (uint32_t)(sel >> 32)); + + retval = swd_queue_dp_write(dap, DP_SELECT1, (uint32_t)(sel >> 32)); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; } static int swd_queue_ap_read(struct adiv5_ap *ap, unsigned reg, @@ -566,7 +648,12 @@ static void swd_quit(struct adiv5_dap *dap) done = true; if (dap_is_multidrop(dap)) { + /* Emit the switch seq to dormant state regardless the state mirrored + * in swd_multidrop_in_swd_state. Doing so ensures robust operation + * in the case the variable is out of sync. + * Sending SWD_TO_DORMANT makes no change if the DP is already dormant. */ swd->switch_seq(SWD_TO_DORMANT); + swd_multidrop_in_swd_state = false; /* Revisit! * Leaving DPs in dormant state was tested and offers some safety * against DPs mismatch in case of unintentional use of non-multidrop SWD. @@ -587,6 +674,7 @@ static void swd_quit(struct adiv5_dap *dap) } const struct dap_ops swd_dap_ops = { + .pre_connect_init = swd_pre_connect, .connect = swd_connect, .send_sequence = swd_send_sequence, .queue_dp_read = swd_queue_dp_read, @@ -608,9 +696,17 @@ static const struct command_registration swd_commands[] = { * REVISIT can we verify "just one SWD DAP" here/early? */ .name = "newdap", - .jim_handler = jim_jtag_newtap, + .handler = handle_jtag_newtap, .mode = COMMAND_CONFIG, - .help = "declare a new SWD DAP" + .help = "declare a new SWD DAP", + .usage = "basename dap_type ['-irlen' count] " + "['-enable'|'-disable'] " + "['-expected_id' number] " + "['-ignore-version'] " + "['-ignore-bypass'] " + "['-ircapture' number] " + "['-ir-bypass' number] " + "['-mask' number]", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/algorithm.c b/src/target/algorithm.c index 9fc9386048..64abffc7b6 100644 --- a/src/target/algorithm.c +++ b/src/target/algorithm.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/algorithm.h b/src/target/algorithm.h index 0fc49d0694..25f1a66ab5 100644 --- a/src/target/algorithm.h +++ b/src/target/algorithm.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ALGORITHM_H diff --git a/src/target/arc.c b/src/target/arc.c index 471f16a989..72e4d918de 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -1,11 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Mischa Jonker <mischa.jonker@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * - * * - * SPDX-License-Identifier: GPL-2.0-or-later * ***************************************************************************/ @@ -50,6 +50,13 @@ static int arc_remove_watchpoint(struct target *target, struct watchpoint *watchpoint); +static int arc_enable_watchpoints(struct target *target); +static int arc_enable_breakpoints(struct target *target); +static int arc_unset_breakpoint(struct target *target, + struct breakpoint *breakpoint); +static int arc_set_breakpoint(struct target *target, + struct breakpoint *breakpoint); +static int arc_single_step_core(struct target *target); void arc_reg_data_type_add(struct target *target, struct arc_reg_data_type *data_type) @@ -93,7 +100,7 @@ struct reg *arc_reg_get_by_name(struct reg_cache *first, * * @param target Target for which to reset caches states. */ -int arc_reset_caches_states(struct target *target) +static int arc_reset_caches_states(struct target *target) { struct arc_common *arc = target_to_arc(target); @@ -283,7 +290,7 @@ static int arc_set_register(struct reg *reg, uint8_t *buf) return ERROR_OK; } -const struct reg_arch_type arc_reg_type = { +static const struct reg_arch_type arc_reg_type = { .get = arc_get_register, .set = arc_set_register, }; @@ -748,6 +755,29 @@ static int arc_examine(struct target *target) return ERROR_OK; } +static int arc_exit_debug(struct target *target) +{ + uint32_t value; + struct arc_common *arc = target_to_arc(target); + + /* Do read-modify-write sequence, or DEBUG.UB will be reset unintentionally. */ + CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, &value)); + value |= SET_CORE_FORCE_HALT; /* set the HALT bit */ + CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, value)); + alive_sleep(1); + + target->state = TARGET_HALTED; + CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); + + if (debug_level >= LOG_LVL_DEBUG) { + LOG_DEBUG("core stopped (halted) debug-reg: 0x%08" PRIx32, value); + CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value)); + LOG_DEBUG("core STATUS32: 0x%08" PRIx32, value); + } + + return ERROR_OK; +} + static int arc_halt(struct target *target) { uint32_t value, irq_state; @@ -846,21 +876,17 @@ static int arc_save_context(struct target *target) memset(aux_addrs, 0xff, aux_regs_size); for (i = 0; i < MIN(arc->num_core_regs, regs_to_scan); i++) { - struct reg *reg = &(reg_list[i]); + struct reg *reg = reg_list + i; struct arc_reg_desc *arc_reg = reg->arch_info; - if (!reg->valid && reg->exist) { - core_addrs[core_cnt] = arc_reg->arch_num; - core_cnt += 1; - } + if (!reg->valid && reg->exist) + core_addrs[core_cnt++] = arc_reg->arch_num; } for (i = arc->num_core_regs; i < regs_to_scan; i++) { - struct reg *reg = &(reg_list[i]); + struct reg *reg = reg_list + i; struct arc_reg_desc *arc_reg = reg->arch_info; - if (!reg->valid && reg->exist) { - aux_addrs[aux_cnt] = arc_reg->arch_num; - aux_cnt += 1; - } + if (!reg->valid && reg->exist) + aux_addrs[aux_cnt++] = arc_reg->arch_num; } /* Read data from target. */ @@ -884,30 +910,30 @@ static int arc_save_context(struct target *target) /* Parse core regs */ core_cnt = 0; for (i = 0; i < MIN(arc->num_core_regs, regs_to_scan); i++) { - struct reg *reg = &(reg_list[i]); + struct reg *reg = reg_list + i; struct arc_reg_desc *arc_reg = reg->arch_info; if (!reg->valid && reg->exist) { target_buffer_set_u32(target, reg->value, core_values[core_cnt]); - core_cnt += 1; reg->valid = true; reg->dirty = false; LOG_DEBUG("Get core register regnum=%u, name=%s, value=0x%08" PRIx32, i, arc_reg->name, core_values[core_cnt]); + core_cnt++; } } /* Parse aux regs */ aux_cnt = 0; for (i = arc->num_core_regs; i < regs_to_scan; i++) { - struct reg *reg = &(reg_list[i]); + struct reg *reg = reg_list + i; struct arc_reg_desc *arc_reg = reg->arch_info; if (!reg->valid && reg->exist) { target_buffer_set_u32(target, reg->value, aux_values[aux_cnt]); - aux_cnt += 1; reg->valid = true; reg->dirty = false; LOG_DEBUG("Get aux register regnum=%u, name=%s, value=0x%08" PRIx32, i, arc_reg->name, aux_values[aux_cnt]); + aux_cnt++; } } @@ -1253,7 +1279,7 @@ static int arc_resume(struct target *target, int current, target_addr_t address, uint32_t value; struct reg *pc = &arc->core_and_aux_cache->reg_list[arc->pc_index_in_cache]; - LOG_DEBUG("current:%i, address:0x%08" TARGET_PRIxADDR ", handle_breakpoints(not supported yet):%i," + LOG_DEBUG("current:%i, address:0x%08" TARGET_PRIxADDR ", handle_breakpoints:%i," " debug_execution:%i", current, address, handle_breakpoints, debug_execution); /* We need to reset ARC cache variables so caches @@ -1262,15 +1288,22 @@ static int arc_resume(struct target *target, int current, target_addr_t address, CHECK_RETVAL(arc_reset_caches_states(target)); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } + if (!debug_execution) { + /* (gdb) continue = execute until we hit break/watch-point */ + target_free_all_working_areas(target); + CHECK_RETVAL(arc_enable_breakpoints(target)); + CHECK_RETVAL(arc_enable_watchpoints(target)); + } + /* current = 1: continue on current PC, otherwise continue at <address> */ if (!current) { target_buffer_set_u32(target, pc->value, address); - pc->dirty = 1; - pc->valid = 1; + pc->dirty = true; + pc->valid = true; LOG_DEBUG("Changing the value of current PC to 0x%08" TARGET_PRIxADDR, address); } @@ -1285,12 +1318,25 @@ static int arc_resume(struct target *target, int current, target_addr_t address, resume_pc, pc->dirty, pc->valid); /* check if GDB tells to set our PC where to continue from */ - if ((pc->valid == 1) && (resume_pc == target_buffer_get_u32(target, pc->value))) { + if (pc->valid && resume_pc == target_buffer_get_u32(target, pc->value)) { value = target_buffer_get_u32(target, pc->value); LOG_DEBUG("resume Core (when start-core) with PC @:0x%08" PRIx32, value); CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_PC_REG, value)); } + /* the front-end may request us not to handle breakpoints here */ + if (handle_breakpoints) { + /* Single step past breakpoint at current address */ + struct breakpoint *breakpoint = breakpoint_find(target, resume_pc); + if (breakpoint) { + LOG_DEBUG("skipping past breakpoint at 0x%08" TARGET_PRIxADDR, + breakpoint->address); + CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint)); + CHECK_RETVAL(arc_single_step_core(target)); + CHECK_RETVAL(arc_set_breakpoint(target, breakpoint)); + } + } + /* Restore IRQ state if not in debug_execution*/ if (!debug_execution) CHECK_RETVAL(arc_enable_interrupts(target, arc->irq_state)); @@ -1401,7 +1447,7 @@ static int arc_target_create(struct target *target, Jim_Interp *interp) * little endian, so different type of conversion should be done. * Middle endian: instruction "aabbccdd", stored as "bbaaddcc" */ -int arc_write_instruction_u32(struct target *target, uint32_t address, +static int arc_write_instruction_u32(struct target *target, uint32_t address, uint32_t instr) { uint8_t value_buf[4]; @@ -1428,7 +1474,7 @@ int arc_write_instruction_u32(struct target *target, uint32_t address, * case of little endian ARC instructions are in middle endian format, so * different type of conversion should be done. */ -int arc_read_instruction_u32(struct target *target, uint32_t address, +static int arc_read_instruction_u32(struct target *target, uint32_t address, uint32_t *value) { uint8_t value_buf[4]; @@ -1577,9 +1623,6 @@ static int arc_set_breakpoint(struct target *target, return ERROR_FAIL; } - /* core instruction cache is now invalid. */ - CHECK_RETVAL(arc_cache_invalidate(target)); - return ERROR_OK; } @@ -1662,12 +1705,22 @@ static int arc_unset_breakpoint(struct target *target, return ERROR_FAIL; } - /* core instruction cache is now invalid. */ - CHECK_RETVAL(arc_cache_invalidate(target)); - return retval; } +static int arc_enable_breakpoints(struct target *target) +{ + struct breakpoint *breakpoint = target->breakpoints; + + /* set any pending breakpoints */ + while (breakpoint) { + if (!breakpoint->is_set) + CHECK_RETVAL(arc_set_breakpoint(target, breakpoint)); + breakpoint = breakpoint->next; + } + + return ERROR_OK; +} static int arc_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { @@ -1675,7 +1728,7 @@ static int arc_add_breakpoint(struct target *target, struct breakpoint *breakpoi return arc_set_breakpoint(target, breakpoint); } else { - LOG_WARNING(" > core was not halted, please try again."); + LOG_TARGET_ERROR(target, "not halted (add breakpoint)"); return ERROR_TARGET_NOT_HALTED; } } @@ -1687,14 +1740,14 @@ static int arc_remove_breakpoint(struct target *target, if (breakpoint->is_set) CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint)); } else { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted (remove breakpoint)"); return ERROR_TARGET_NOT_HALTED; } return ERROR_OK; } -void arc_reset_actionpoints(struct target *target) +static void arc_reset_actionpoints(struct target *target) { struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; @@ -1905,11 +1958,25 @@ static int arc_unset_watchpoint(struct target *target, return retval; } +static int arc_enable_watchpoints(struct target *target) +{ + struct watchpoint *watchpoint = target->watchpoints; + + /* set any pending watchpoints */ + while (watchpoint) { + if (!watchpoint->is_set) + CHECK_RETVAL(arc_set_watchpoint(target, watchpoint)); + watchpoint = watchpoint->next; + } + + return ERROR_OK; +} + static int arc_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1922,7 +1989,7 @@ static int arc_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1965,7 +2032,7 @@ static int arc_hit_watchpoint(struct target *target, struct watchpoint **hit_wat /* Helper function which switches core to single_step mode by * doing aux r/w operations. */ -int arc_config_step(struct target *target, int enable_step) +static int arc_config_step(struct target *target, int enable_step) { uint32_t value; @@ -2001,7 +2068,23 @@ int arc_config_step(struct target *target, int enable_step) return ERROR_OK; } -int arc_step(struct target *target, int current, target_addr_t address, +static int arc_single_step_core(struct target *target) +{ + CHECK_RETVAL(arc_debug_entry(target)); + + /* disable interrupts while stepping */ + CHECK_RETVAL(arc_enable_interrupts(target, 0)); + + /* configure single step mode */ + CHECK_RETVAL(arc_config_step(target, 1)); + + /* exit debug mode */ + CHECK_RETVAL(arc_exit_debug(target)); + + return ERROR_OK; +} + +static int arc_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { /* get pointers to arch-specific information */ @@ -2010,15 +2093,15 @@ int arc_step(struct target *target, int current, target_addr_t address, struct reg *pc = &(arc->core_and_aux_cache->reg_list[arc->pc_index_in_cache]); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u32(pc->value, 0, 32, address); - pc->dirty = 1; - pc->valid = 1; + pc->dirty = true; + pc->valid = true; } LOG_DEBUG("Target steps one instruction from PC=0x%" PRIx32, @@ -2165,7 +2248,7 @@ int arc_cache_invalidate(struct target *target) * values directly from memory, bypassing cache, so if there are unflushed * lines debugger will read invalid values, which will cause a lot of troubles. * */ -int arc_dcache_flush(struct target *target) +static int arc_dcache_flush(struct target *target) { uint32_t value, dc_ctrl_value; bool has_to_set_dc_ctrl_im; diff --git a/src/target/arc.h b/src/target/arc.h index f0351bdf39..a351802ac6 100644 --- a/src/target/arc.h +++ b/src/target/arc.h @@ -1,11 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Mischa Jonker <mischa.jonker@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * - * * - * SPDX-License-Identifier: GPL-2.0-or-later * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARC_H @@ -27,7 +27,7 @@ #include "arc_cmd.h" #include "arc_mem.h" -#define ARC_COMMON_MAGIC 0xB32EB324 /* just a unique number */ +#define ARC_COMMON_MAGIC 0xB32EB324U /* just a unique number */ #define AUX_DEBUG_REG 0x5 #define AUX_PC_REG 0x6 @@ -183,7 +183,7 @@ struct arc_actionpoint { }; struct arc_common { - uint32_t common_magic; + unsigned int common_magic; struct arc_jtag jtag_info; @@ -253,16 +253,6 @@ struct arc_common { } \ } while (0) -#define JIM_CHECK_RETVAL(action) \ - do { \ - int __retval = (action); \ - if (__retval != JIM_OK) { \ - LOG_DEBUG("error while calling \"%s\"", \ - # action); \ - return __retval; \ - } \ - } while (0) - static inline struct arc_common *target_to_arc(struct target *target) { return target->arch_info; diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index 26c67c6db7..e7760b0378 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -1,11 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Mischa Jonker <mischa.jonker@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * - * * - * SPDX-License-Identifier: GPL-2.0-or-later * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -13,6 +13,7 @@ #endif #include "arc.h" +#include <helper/nvp.h> /* -------------------------------------------------------------------------- * @@ -22,14 +23,6 @@ * ------------------------------------------------------------------------- */ -static int arc_cmd_jim_get_uint32(struct jim_getopt_info *goi, uint32_t *value) -{ - jim_wide value_wide; - JIM_CHECK_RETVAL(jim_getopt_wide(goi, &value_wide)); - *value = (uint32_t)value_wide; - return JIM_OK; -} - enum add_reg_types { CFG_ADD_REG_TYPE_FLAG, CFG_ADD_REG_TYPE_STRUCT, @@ -40,7 +33,7 @@ enum add_reg_type_flags { CFG_ADD_REG_TYPE_FLAGS_FLAG, }; -static struct jim_nvp nvp_add_reg_type_flags_opts[] = { +static const struct nvp nvp_add_reg_type_flags_opts[] = { { .name = "-name", .value = CFG_ADD_REG_TYPE_FLAGS_NAME }, { .name = "-flag", .value = CFG_ADD_REG_TYPE_FLAGS_FLAG }, { .name = NULL, .value = -1 } @@ -62,113 +55,113 @@ static const char *validate_register(const struct arc_reg_desc * const reg, bool return NULL; } -/* Helper function to read the name of register type or register from - * configure files */ -static int jim_arc_read_reg_name_field(struct jim_getopt_info *goi, - const char **name, int *name_len) +static COMMAND_HELPER(arc_handle_add_reg_type_flags_ops, struct arc_reg_data_type *type) { - int e = JIM_OK; + struct reg_data_type_flags_field *fields = type->reg_type_flags_field; + struct arc_reg_bitfield *bitfields = type->bitfields; + struct reg_data_type_flags *flags = &type->data_type_flags; + unsigned int cur_field = 0; - if (!goi->argc) { - Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-name <name> ..."); - return JIM_ERR; - } - e = jim_getopt_string(goi, name, name_len); - return e; -} + while (CMD_ARGC) { + const struct nvp *n = nvp_name2value(nvp_add_reg_type_flags_opts, CMD_ARGV[0]); + CMD_ARGC--; + CMD_ARGV++; + switch (n->value) { + case CFG_ADD_REG_TYPE_FLAGS_NAME: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; -/* Helper function to read bitfields/flags of register type. */ -static int jim_arc_read_reg_type_field(struct jim_getopt_info *goi, const char **field_name, int *field_name_len, - struct arc_reg_bitfield *bitfields, int cur_field, int type) -{ - jim_wide start_pos, end_pos; + const char *name = CMD_ARGV[0]; + CMD_ARGC--; + CMD_ARGV++; + + if (strlen(name) >= REG_TYPE_MAX_NAME_LENGTH) { + command_print(CMD, "Reg type name is too big."); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + strcpy((void *)type->data_type.id, name); + break; - int e = JIM_OK; - if ((type == CFG_ADD_REG_TYPE_STRUCT && goi->argc < 3) || - (type == CFG_ADD_REG_TYPE_FLAG && goi->argc < 2)) { - Jim_SetResultFormatted(goi->interp, "Not enough arguments after -flag/-bitfield"); - return JIM_ERR; + case CFG_ADD_REG_TYPE_FLAGS_FLAG: + if (CMD_ARGC < 2) + return ERROR_COMMAND_ARGUMENT_INVALID; + + uint32_t val; + const char *field_name = CMD_ARGV[0]; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], val); + CMD_ARGC -= 2; + CMD_ARGV += 2; + bitfields[cur_field].bitfield.start = val; + bitfields[cur_field].bitfield.end = val; + + if (strlen(field_name) >= REG_TYPE_MAX_NAME_LENGTH) { + command_print(CMD, "Reg type field_name is too big."); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + fields[cur_field].name = bitfields[cur_field].name; + strcpy(bitfields[cur_field].name, field_name); + + fields[cur_field].bitfield = &bitfields[cur_field].bitfield; + if (cur_field > 0) + fields[cur_field - 1].next = &fields[cur_field]; + else + flags->fields = fields; + + cur_field += 1; + break; + + default: + nvp_unknown_command_print(CMD, nvp_add_reg_type_flags_opts, NULL, CMD_ARGV[-1]); + return ERROR_COMMAND_ARGUMENT_INVALID; } + } - e = jim_getopt_string(goi, field_name, field_name_len); - if (e != JIM_OK) - return e; - - /* read start position of bitfield/flag */ - e = jim_getopt_wide(goi, &start_pos); - if (e != JIM_OK) - return e; - - end_pos = start_pos; - - /* Check if any arguments remain, - * set bitfields[cur_field].end if flag is multibit */ - if (goi->argc > 0) - /* Check current argv[0], if it is equal to "-flag", - * than bitfields[cur_field].end remains start */ - if ((strcmp(Jim_String(goi->argv[0]), "-flag") && type == CFG_ADD_REG_TYPE_FLAG) - || (type == CFG_ADD_REG_TYPE_STRUCT)) { - e = jim_getopt_wide(goi, &end_pos); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi->interp, "Error reading end position"); - return e; - } - } - - bitfields[cur_field].bitfield.start = start_pos; - bitfields[cur_field].bitfield.end = end_pos; - if ((end_pos != start_pos) || (type == CFG_ADD_REG_TYPE_STRUCT)) - bitfields[cur_field].bitfield.type = REG_TYPE_INT; - return e; + if (!type->data_type.id) { + command_print(CMD, "-name is a required option"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + return ERROR_OK; } -static int jim_arc_add_reg_type_flags(Jim_Interp *interp, int argc, - Jim_Obj * const *argv) +COMMAND_HANDLER(arc_handle_add_reg_type_flags) { - struct jim_getopt_info goi; - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); + int retval; LOG_DEBUG("-"); - struct command_context *ctx; - struct target *target; - - ctx = current_command_context(interp); - assert(ctx); - target = get_current_target(ctx); + struct target *target = get_current_target(CMD_CTX); if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + command_print(CMD, "No current target"); + return ERROR_FAIL; } - int e = JIM_OK; - /* Check if the amount of arguments is not zero */ - if (goi.argc <= 0) { - Jim_SetResultFormatted(goi.interp, "The command has no arguments"); - return JIM_ERR; - } + if (CMD_ARGC == 0) + return ERROR_COMMAND_SYNTAX_ERROR; /* Estimate number of registers as (argc - 2)/3 as each -flag option has 2 * arguments while -name is required. */ - unsigned int fields_sz = (goi.argc - 2) / 3; - unsigned int cur_field = 0; + unsigned int fields_sz = (CMD_ARGC - 2) / 3; /* The maximum amount of bitfields is 32 */ if (fields_sz > 32) { - Jim_SetResultFormatted(goi.interp, "The amount of bitfields exceed 32"); - return JIM_ERR; + command_print(CMD, "The amount of bitfields exceed 32"); + return ERROR_COMMAND_ARGUMENT_INVALID; } struct arc_reg_data_type *type = calloc(1, sizeof(*type)); - struct reg_data_type_flags *flags = &type->data_type_flags; struct reg_data_type_flags_field *fields = calloc(fields_sz, sizeof(*fields)); - type->reg_type_flags_field = fields; struct arc_reg_bitfield *bitfields = calloc(fields_sz, sizeof(*bitfields)); - if (!(type && fields && bitfields)) { - Jim_SetResultFormatted(goi.interp, "Failed to allocate memory."); + if (!type || !fields || !bitfields) { + LOG_ERROR("Out of memory"); + retval = ERROR_FAIL; goto fail; } + struct reg_data_type_flags *flags = &type->data_type_flags; + type->reg_type_flags_field = fields; /* Initialize type */ type->bitfields = bitfields; @@ -178,92 +171,22 @@ static int jim_arc_add_reg_type_flags(Jim_Interp *interp, int argc, type->data_type.reg_type_flags = flags; flags->size = 4; /* For now ARC has only 32-bit registers */ - while (goi.argc > 0 && e == JIM_OK) { - struct jim_nvp *n; - e = jim_getopt_nvp(&goi, nvp_add_reg_type_flags_opts, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(&goi, nvp_add_reg_type_flags_opts, 0); - continue; - } - - switch (n->value) { - case CFG_ADD_REG_TYPE_FLAGS_NAME: - { - const char *name = NULL; - int name_len = 0; - - e = jim_arc_read_reg_name_field(&goi, &name, &name_len); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi.interp, "Unable to read reg name."); - goto fail; - } - - if (name_len > REG_TYPE_MAX_NAME_LENGTH) { - Jim_SetResultFormatted(goi.interp, "Reg type name is too big."); - goto fail; - } - - strncpy((void *)type->data_type.id, name, name_len); - if (!type->data_type.id) { - Jim_SetResultFormatted(goi.interp, "Unable to setup reg type name."); - goto fail; - } - - break; - } - - case CFG_ADD_REG_TYPE_FLAGS_FLAG: - { - const char *field_name = NULL; - int field_name_len = 0; - - e = jim_arc_read_reg_type_field(&goi, &field_name, &field_name_len, bitfields, - cur_field, CFG_ADD_REG_TYPE_FLAG); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi.interp, "Unable to add reg_type_flag field."); - goto fail; - } - - if (field_name_len > REG_TYPE_MAX_NAME_LENGTH) { - Jim_SetResultFormatted(goi.interp, "Reg type field_name_len is too big."); - goto fail; - } - - fields[cur_field].name = bitfields[cur_field].name; - strncpy(bitfields[cur_field].name, field_name, field_name_len); - if (!fields[cur_field].name) { - Jim_SetResultFormatted(goi.interp, "Unable to setup field name. "); - goto fail; - } - - fields[cur_field].bitfield = &(bitfields[cur_field].bitfield); - if (cur_field > 0) - fields[cur_field - 1].next = &(fields[cur_field]); - else - flags->fields = fields; - - cur_field += 1; - break; - } - } - } - - if (!type->data_type.id) { - Jim_SetResultFormatted(goi.interp, "-name is a required option"); + retval = CALL_COMMAND_HANDLER(arc_handle_add_reg_type_flags_ops, type); + if (retval != ERROR_OK) goto fail; - } arc_reg_data_type_add(target, type); LOG_DEBUG("added flags type {name=%s}", type->data_type.id); - return JIM_OK; + return ERROR_OK; + fail: free(type); free(fields); free(bitfields); - return JIM_ERR; + return retval; } /* Add struct register data type */ @@ -272,43 +195,30 @@ enum add_reg_type_struct { CFG_ADD_REG_TYPE_STRUCT_BITFIELD, }; -static struct jim_nvp nvp_add_reg_type_struct_opts[] = { +static const struct nvp nvp_add_reg_type_struct_opts[] = { { .name = "-name", .value = CFG_ADD_REG_TYPE_STRUCT_NAME }, { .name = "-bitfield", .value = CFG_ADD_REG_TYPE_STRUCT_BITFIELD }, { .name = NULL, .value = -1 } }; -static int jim_arc_set_aux_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(arc_handle_set_aux_reg) { + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; - struct command_context *context; - struct target *target; - uint32_t regnum; - uint32_t value; - - struct jim_getopt_info goi; - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); - - if (goi.argc != 2) { - Jim_SetResultFormatted(goi.interp, - "usage: %s <aux_reg_num> <aux_reg_value>", Jim_GetString(argv[0], NULL)); - return JIM_ERR; - } - - context = current_command_context(interp); - assert(context); - - target = get_current_target(context); + struct target *target = get_current_target(CMD_CTX); if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + command_print(CMD, "No current target"); + return ERROR_FAIL; } /* Register number */ - JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num)); + uint32_t regnum; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], regnum); /* Register value */ - JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &value)); + uint32_t value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); struct arc_common *arc = target_to_arc(target); assert(arc); @@ -318,121 +228,87 @@ static int jim_arc_set_aux_reg(Jim_Interp *interp, int argc, Jim_Obj * const *ar return ERROR_OK; } -static int jim_arc_get_aux_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(arc_handle_get_aux_reg) { - struct command_context *context; - struct target *target; - uint32_t regnum; - uint32_t value; - - struct jim_getopt_info goi; - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); - - if (goi.argc != 1) { - Jim_SetResultFormatted(goi.interp, - "usage: %s <aux_reg_num>", Jim_GetString(argv[0], NULL)); - return JIM_ERR; - } - - context = current_command_context(interp); - assert(context); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; - target = get_current_target(context); + struct target *target = get_current_target(CMD_CTX); if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + command_print(CMD, "No current target"); + return ERROR_FAIL; } /* Register number */ - JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num)); + uint32_t regnum; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], regnum); struct arc_common *arc = target_to_arc(target); assert(arc); + uint32_t value; CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, regnum, &value)); - Jim_SetResultInt(interp, value); + + command_print(CMD, "0x%" PRIx32, value); return ERROR_OK; } -static int jim_arc_get_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(arc_handle_get_core_reg) { - struct command_context *context; - struct target *target; - uint32_t regnum; - uint32_t value; - - struct jim_getopt_info goi; - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); - - if (goi.argc != 1) { - Jim_SetResultFormatted(goi.interp, - "usage: %s <core_reg_num>", Jim_GetString(argv[0], NULL)); - return JIM_ERR; - } - - context = current_command_context(interp); - assert(context); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; - target = get_current_target(context); + struct target *target = get_current_target(CMD_CTX); if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + command_print(CMD, "No current target"); + return ERROR_FAIL; } /* Register number */ - JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num)); + uint32_t regnum; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], regnum); if (regnum > CORE_REG_MAX_NUMBER || regnum == ARC_R61 || regnum == ARC_R62) { - Jim_SetResultFormatted(goi.interp, "Core register number %i " + command_print(CMD, "Core register number %i " "is invalid. Must less then 64 and not 61 and 62.", regnum); - return JIM_ERR; + return ERROR_COMMAND_ARGUMENT_INVALID; } struct arc_common *arc = target_to_arc(target); assert(arc); /* Read value */ + uint32_t value; CHECK_RETVAL(arc_jtag_read_core_reg_one(&arc->jtag_info, regnum, &value)); - Jim_SetResultInt(interp, value); + + command_print(CMD, "0x%" PRIx32, value); return ERROR_OK; } -static int jim_arc_set_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(arc_handle_set_core_reg) { - struct command_context *context; - struct target *target; - uint32_t regnum; - uint32_t value; - - struct jim_getopt_info goi; - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); - - if (goi.argc != 2) { - Jim_SetResultFormatted(goi.interp, - "usage: %s <core_reg_num> <core_reg_value>", Jim_GetString(argv[0], NULL)); - return JIM_ERR; - } - - context = current_command_context(interp); - assert(context); + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; - target = get_current_target(context); + struct target *target = get_current_target(CMD_CTX); if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + command_print(CMD, "No current target"); + return ERROR_FAIL; } /* Register number */ - JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, ®num)); + uint32_t regnum; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], regnum); if (regnum > CORE_REG_MAX_NUMBER || regnum == ARC_R61 || regnum == ARC_R62) { - Jim_SetResultFormatted(goi.interp, "Core register number %i " + command_print(CMD, "Core register number %i " "is invalid. Must less then 64 and not 61 and 62.", regnum); - return JIM_ERR; + return ERROR_COMMAND_ARGUMENT_INVALID; } /* Register value */ - JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &value)); + uint32_t value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); struct arc_common *arc = target_to_arc(target); assert(arc); @@ -445,7 +321,7 @@ static int jim_arc_set_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *a static const struct command_registration arc_jtag_command_group[] = { { .name = "get-aux-reg", - .jim_handler = jim_arc_get_aux_reg, + .handler = arc_handle_get_aux_reg, .mode = COMMAND_EXEC, .help = "Get AUX register by number. This command does a " "raw JTAG request that bypasses OpenOCD register cache " @@ -455,7 +331,7 @@ static const struct command_registration arc_jtag_command_group[] = { }, { .name = "set-aux-reg", - .jim_handler = jim_arc_set_aux_reg, + .handler = arc_handle_set_aux_reg, .mode = COMMAND_EXEC, .help = "Set AUX register by number. This command does a " "raw JTAG request that bypasses OpenOCD register cache " @@ -465,7 +341,7 @@ static const struct command_registration arc_jtag_command_group[] = { }, { .name = "get-core-reg", - .jim_handler = jim_arc_get_core_reg, + .handler = arc_handle_get_core_reg, .mode = COMMAND_EXEC, .help = "Get/Set core register by number. This command does a " "raw JTAG request that bypasses OpenOCD register cache " @@ -475,7 +351,7 @@ static const struct command_registration arc_jtag_command_group[] = { }, { .name = "set-core-reg", - .jim_handler = jim_arc_set_core_reg, + .handler = arc_handle_set_core_reg, .mode = COMMAND_EXEC, .help = "Get/Set core register by number. This command does a " "raw JTAG request that bypasses OpenOCD register cache " @@ -488,53 +364,117 @@ static const struct command_registration arc_jtag_command_group[] = { /* This function supports only bitfields. */ -static int jim_arc_add_reg_type_struct(Jim_Interp *interp, int argc, - Jim_Obj * const *argv) +static COMMAND_HELPER(arc_handle_add_reg_type_struct_opts, struct arc_reg_data_type *type) { - struct jim_getopt_info goi; - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); + struct reg_data_type_struct_field *fields = type->reg_type_struct_field; + struct arc_reg_bitfield *bitfields = type->bitfields; + struct reg_data_type_struct *struct_type = &type->data_type_struct; + unsigned int cur_field = 0; - LOG_DEBUG("-"); + while (CMD_ARGC) { + const struct nvp *n = nvp_name2value(nvp_add_reg_type_struct_opts, CMD_ARGV[0]); + CMD_ARGC--; + CMD_ARGV++; + switch (n->value) { + case CFG_ADD_REG_TYPE_STRUCT_NAME: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; - struct command_context *ctx; - struct target *target; + const char *name = CMD_ARGV[0]; + CMD_ARGC--; + CMD_ARGV++; - ctx = current_command_context(interp); - assert(ctx); - target = get_current_target(ctx); - if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + if (strlen(name) >= REG_TYPE_MAX_NAME_LENGTH) { + command_print(CMD, "Reg type name is too big."); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + strcpy((void *)type->data_type.id, name); + break; + + case CFG_ADD_REG_TYPE_STRUCT_BITFIELD: + if (CMD_ARGC < 3) + return ERROR_COMMAND_ARGUMENT_INVALID; + + uint32_t start_pos, end_pos; + const char *field_name = CMD_ARGV[0]; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], start_pos); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], end_pos); + CMD_ARGC -= 3; + CMD_ARGV += 3; + bitfields[cur_field].bitfield.start = start_pos; + bitfields[cur_field].bitfield.end = end_pos; + bitfields[cur_field].bitfield.type = REG_TYPE_INT; + + if (strlen(field_name) >= REG_TYPE_MAX_NAME_LENGTH) { + command_print(CMD, "Reg type field_name is too big."); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + fields[cur_field].name = bitfields[cur_field].name; + strcpy(bitfields[cur_field].name, field_name); + + fields[cur_field].bitfield = &bitfields[cur_field].bitfield; + fields[cur_field].use_bitfields = true; + if (cur_field > 0) + fields[cur_field - 1].next = &fields[cur_field]; + else + struct_type->fields = fields; + + cur_field += 1; + + break; + + default: + nvp_unknown_command_print(CMD, nvp_add_reg_type_struct_opts, NULL, CMD_ARGV[-1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } + + if (!type->data_type.id) { + command_print(CMD, "-name is a required option"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - int e = JIM_OK; + return ERROR_OK; +} - /* Check if the amount of arguments is not zero */ - if (goi.argc <= 0) { - Jim_SetResultFormatted(goi.interp, "The command has no arguments"); - return JIM_ERR; +COMMAND_HANDLER(arc_handle_add_reg_type_struct) +{ + int retval; + + LOG_DEBUG("-"); + + struct target *target = get_current_target(CMD_CTX); + if (!target) { + command_print(CMD, "No current target"); + return ERROR_FAIL; } + /* Check if the amount of arguments is not zero */ + if (CMD_ARGC == 0) + return ERROR_COMMAND_SYNTAX_ERROR; + /* Estimate number of registers as (argc - 2)/4 as each -bitfield option has 3 * arguments while -name is required. */ - unsigned int fields_sz = (goi.argc - 2) / 4; - unsigned int cur_field = 0; + unsigned int fields_sz = (CMD_ARGC - 2) / 4; /* The maximum amount of bitfields is 32 */ if (fields_sz > 32) { - Jim_SetResultFormatted(goi.interp, "The amount of bitfields exceed 32"); - return JIM_ERR; + command_print(CMD, "The amount of bitfields exceed 32"); + return ERROR_COMMAND_ARGUMENT_INVALID; } struct arc_reg_data_type *type = calloc(1, sizeof(*type)); - struct reg_data_type_struct *struct_type = &type->data_type_struct; struct reg_data_type_struct_field *fields = calloc(fields_sz, sizeof(*fields)); - type->reg_type_struct_field = fields; struct arc_reg_bitfield *bitfields = calloc(fields_sz, sizeof(*bitfields)); - if (!(type && fields && bitfields)) { - Jim_SetResultFormatted(goi.interp, "Failed to allocate memory."); + if (!type || !fields || !bitfields) { + LOG_ERROR("Out of memory"); + retval = ERROR_FAIL; goto fail; } + struct reg_data_type_struct *struct_type = &type->data_type_struct; + type->reg_type_struct_field = fields; /* Initialize type */ type->data_type.id = type->data_type_id; @@ -544,91 +484,22 @@ static int jim_arc_add_reg_type_struct(Jim_Interp *interp, int argc, type->data_type.reg_type_struct = struct_type; struct_type->size = 4; /* For now ARC has only 32-bit registers */ - while (goi.argc > 0 && e == JIM_OK) { - struct jim_nvp *n; - e = jim_getopt_nvp(&goi, nvp_add_reg_type_struct_opts, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(&goi, nvp_add_reg_type_struct_opts, 0); - continue; - } - - switch (n->value) { - case CFG_ADD_REG_TYPE_STRUCT_NAME: - { - const char *name = NULL; - int name_len = 0; - - e = jim_arc_read_reg_name_field(&goi, &name, &name_len); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi.interp, "Unable to read reg name."); - goto fail; - } - - if (name_len > REG_TYPE_MAX_NAME_LENGTH) { - Jim_SetResultFormatted(goi.interp, "Reg type name is too big."); - goto fail; - } - - strncpy((void *)type->data_type.id, name, name_len); - if (!type->data_type.id) { - Jim_SetResultFormatted(goi.interp, "Unable to setup reg type name."); - goto fail; - } - - break; - } - case CFG_ADD_REG_TYPE_STRUCT_BITFIELD: - { - const char *field_name = NULL; - int field_name_len = 0; - e = jim_arc_read_reg_type_field(&goi, &field_name, &field_name_len, bitfields, - cur_field, CFG_ADD_REG_TYPE_STRUCT); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi.interp, "Unable to add reg_type_struct field."); - goto fail; - } - - if (field_name_len > REG_TYPE_MAX_NAME_LENGTH) { - Jim_SetResultFormatted(goi.interp, "Reg type field_name_len is too big."); - goto fail; - } - - fields[cur_field].name = bitfields[cur_field].name; - strncpy(bitfields[cur_field].name, field_name, field_name_len); - if (!fields[cur_field].name) { - Jim_SetResultFormatted(goi.interp, "Unable to setup field name. "); - goto fail; - } - - fields[cur_field].bitfield = &(bitfields[cur_field].bitfield); - fields[cur_field].use_bitfields = true; - if (cur_field > 0) - fields[cur_field - 1].next = &(fields[cur_field]); - else - struct_type->fields = fields; - - cur_field += 1; - - break; - } - } - } - - if (!type->data_type.id) { - Jim_SetResultFormatted(goi.interp, "-name is a required option"); + retval = CALL_COMMAND_HANDLER(arc_handle_add_reg_type_struct_opts, type); + if (retval != ERROR_OK) goto fail; - } arc_reg_data_type_add(target, type); + LOG_DEBUG("added struct type {name=%s}", type->data_type.id); - return JIM_OK; + + return ERROR_OK; fail: - free(type); - free(fields); - free(bitfields); + free(type); + free(fields); + free(bitfields); - return JIM_ERR; + return retval; } /* Add register */ @@ -642,7 +513,7 @@ enum opts_add_reg { CFG_ADD_REG_GENERAL, }; -static struct jim_nvp opts_nvp_add_reg[] = { +static const struct nvp opts_nvp_add_reg[] = { { .name = "-name", .value = CFG_ADD_REG_NAME }, { .name = "-num", .value = CFG_ADD_REG_ARCH_NUM }, { .name = "-core", .value = CFG_ADD_REG_IS_CORE }, @@ -660,155 +531,133 @@ void free_reg_desc(struct arc_reg_desc *r) free(r); } -static int jim_arc_add_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +static COMMAND_HELPER(arc_handle_add_reg_do, struct arc_reg_desc *reg) { - struct jim_getopt_info goi; - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); - - struct arc_reg_desc *reg = calloc(1, sizeof(*reg)); - if (!reg) { - Jim_SetResultFormatted(goi.interp, "Failed to allocate memory."); - return JIM_ERR; - } - /* There is no architecture number that we could treat as invalid, so * separate variable required to ensure that arch num has been set. */ bool arch_num_set = false; const char *type_name = "int"; /* Default type */ - int type_name_len = strlen(type_name); - int e = ERROR_OK; /* At least we need to specify 4 parameters: name, number and gdb_feature, * which means there should be 6 arguments. Also there can be additional parameters * "-type <type>", "-g" and "-core" or "-bcr" which makes maximum 10 parameters. */ - if (goi.argc < 6 || goi.argc > 10) { - free_reg_desc(reg); - Jim_SetResultFormatted(goi.interp, - "Should be at least 6 arguments and not greater than 10: " - " -name <name> -num <num> -feature <gdb_feature> " - " [-type <type_name>] [-core|-bcr] [-g]."); - return JIM_ERR; - } + if (CMD_ARGC < 6 || CMD_ARGC > 10) + return ERROR_COMMAND_SYNTAX_ERROR; /* Parse options. */ - while (goi.argc > 0) { - struct jim_nvp *n; - e = jim_getopt_nvp(&goi, opts_nvp_add_reg, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(&goi, opts_nvp_add_reg, 0); - free_reg_desc(reg); - return e; - } - + while (CMD_ARGC) { + const struct nvp *n = nvp_name2value(opts_nvp_add_reg, CMD_ARGV[0]); + CMD_ARGC--; + CMD_ARGV++; switch (n->value) { - case CFG_ADD_REG_NAME: - { - const char *reg_name = NULL; - int reg_name_len = 0; - - e = jim_arc_read_reg_name_field(&goi, ®_name, ®_name_len); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi.interp, "Unable to read register name."); - free_reg_desc(reg); - return e; - } - - reg->name = strndup(reg_name, reg_name_len); - break; + case CFG_ADD_REG_NAME: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; + + reg->name = strdup(CMD_ARGV[0]); + if (!reg->name) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; } - case CFG_ADD_REG_IS_CORE: - reg->is_core = true; - break; - case CFG_ADD_REG_IS_BCR: - reg->is_bcr = true; - break; - case CFG_ADD_REG_ARCH_NUM: - { - jim_wide archnum; - - if (!goi.argc) { - free_reg_desc(reg); - Jim_WrongNumArgs(interp, goi.argc, goi.argv, "-num <int> ..."); - return JIM_ERR; - } - - e = jim_getopt_wide(&goi, &archnum); - if (e != JIM_OK) { - free_reg_desc(reg); - return e; - } - - reg->arch_num = archnum; - arch_num_set = true; - break; - } - case CFG_ADD_REG_GDB_FEATURE: - { - const char *feature = NULL; - int feature_len = 0; - - e = jim_arc_read_reg_name_field(&goi, &feature, &feature_len); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi.interp, "Unable to read gdb_feature."); - free_reg_desc(reg); - return e; - } - - reg->gdb_xml_feature = strndup(feature, feature_len); - break; + + CMD_ARGC--; + CMD_ARGV++; + break; + + case CFG_ADD_REG_IS_CORE: + reg->is_core = true; + break; + + case CFG_ADD_REG_IS_BCR: + reg->is_bcr = true; + break; + + case CFG_ADD_REG_ARCH_NUM: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], reg->arch_num); + CMD_ARGC--; + CMD_ARGV++; + + arch_num_set = true; + break; + + case CFG_ADD_REG_GDB_FEATURE: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; + + reg->gdb_xml_feature = strdup(CMD_ARGV[0]); + if (!reg->gdb_xml_feature) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; } - case CFG_ADD_REG_TYPE: - e = jim_arc_read_reg_name_field(&goi, &type_name, &type_name_len); - if (e != JIM_OK) { - Jim_SetResultFormatted(goi.interp, "Unable to read register type."); - free_reg_desc(reg); - return e; - } - - break; - case CFG_ADD_REG_GENERAL: - reg->is_general = true; - break; - default: - LOG_DEBUG("Error: Unknown parameter"); - free_reg_desc(reg); - return JIM_ERR; + + CMD_ARGC--; + CMD_ARGV++; + break; + + case CFG_ADD_REG_TYPE: + if (!CMD_ARGC) + return ERROR_COMMAND_ARGUMENT_INVALID; + + type_name = CMD_ARGV[0]; + CMD_ARGC--; + CMD_ARGV++; + break; + + case CFG_ADD_REG_GENERAL: + reg->is_general = true; + break; + + default: + nvp_unknown_command_print(CMD, opts_nvp_add_reg, NULL, CMD_ARGV[-1]); + return ERROR_COMMAND_ARGUMENT_INVALID; } } /* Check that required fields are set */ const char * const errmsg = validate_register(reg, arch_num_set); if (errmsg) { - Jim_SetResultFormatted(goi.interp, errmsg); - free_reg_desc(reg); - return JIM_ERR; + command_print(CMD, "%s", errmsg); + return ERROR_COMMAND_ARGUMENT_INVALID; } /* Add new register */ - struct command_context *ctx; - struct target *target; - - ctx = current_command_context(interp); - assert(ctx); - target = get_current_target(ctx); + struct target *target = get_current_target(CMD_CTX); if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - free_reg_desc(reg); - return JIM_ERR; + command_print(CMD, "No current target"); + return ERROR_FAIL; } reg->target = target; - e = arc_reg_add(target, reg, type_name, type_name_len); - if (e == ERROR_ARC_REGTYPE_NOT_FOUND) { - Jim_SetResultFormatted(goi.interp, + int retval = arc_reg_add(target, reg, type_name, strlen(type_name)); + if (retval == ERROR_ARC_REGTYPE_NOT_FOUND) { + command_print(CMD, "Cannot find type `%s' for register `%s'.", type_name, reg->name); + return retval; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(arc_handle_add_reg) +{ + struct arc_reg_desc *reg = calloc(1, sizeof(*reg)); + if (!reg) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + int retval = CALL_COMMAND_HANDLER(arc_handle_add_reg_do, reg); + if (retval != ERROR_OK) { free_reg_desc(reg); - return JIM_ERR; + return retval; } - return e; + return ERROR_OK; } /* arc set-reg-exists ($reg_name)+ @@ -818,7 +667,7 @@ COMMAND_HANDLER(arc_set_reg_exists) struct target * const target = get_current_target(CMD_CTX); if (!target) { command_print(CMD, "Unable to get current target."); - return JIM_ERR; + return ERROR_FAIL; } if (!CMD_ARGC) { @@ -838,64 +687,45 @@ COMMAND_HANDLER(arc_set_reg_exists) r->exist = true; } - return JIM_OK; + return ERROR_OK; } /* arc reg-field ($reg_name) ($reg_field) * Reads struct type register field */ -static int jim_arc_get_reg_field(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(arc_handle_get_reg_field) { - struct jim_getopt_info goi; - const char *reg_name, *field_name; - uint32_t value; - int retval; - - JIM_CHECK_RETVAL(jim_getopt_setup(&goi, interp, argc-1, argv+1)); - - LOG_DEBUG("Reading register field"); - if (goi.argc != 2) { - if (!goi.argc) - Jim_WrongNumArgs(interp, goi.argc, goi.argv, "<regname> <fieldname>"); - else if (goi.argc == 1) - Jim_WrongNumArgs(interp, goi.argc, goi.argv, "<fieldname>"); - else - Jim_WrongNumArgs(interp, goi.argc, goi.argv, "<regname> <fieldname>"); + if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; - } - - JIM_CHECK_RETVAL(jim_getopt_string(&goi, ®_name, NULL)); - JIM_CHECK_RETVAL(jim_getopt_string(&goi, &field_name, NULL)); - assert(reg_name); - assert(field_name); - struct command_context * const ctx = current_command_context(interp); - assert(ctx); - struct target * const target = get_current_target(ctx); + struct target *target = get_current_target(CMD_CTX); if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + command_print(CMD, "No current target"); + return ERROR_FAIL; } - retval = arc_reg_get_field(target, reg_name, field_name, &value); + const char *reg_name = CMD_ARGV[0]; + const char *field_name = CMD_ARGV[1]; + uint32_t value; + int retval = arc_reg_get_field(target, reg_name, field_name, &value); switch (retval) { case ERROR_OK: break; case ERROR_ARC_REGISTER_NOT_FOUND: - Jim_SetResultFormatted(goi.interp, + command_print(CMD, "Register `%s' has not been found.", reg_name); return ERROR_COMMAND_ARGUMENT_INVALID; case ERROR_ARC_REGISTER_IS_NOT_STRUCT: - Jim_SetResultFormatted(goi.interp, + command_print(CMD, "Register `%s' must have 'struct' type.", reg_name); return ERROR_COMMAND_ARGUMENT_INVALID; case ERROR_ARC_REGISTER_FIELD_NOT_FOUND: - Jim_SetResultFormatted(goi.interp, + command_print(CMD, "Field `%s' has not been found in register `%s'.", field_name, reg_name); return ERROR_COMMAND_ARGUMENT_INVALID; case ERROR_ARC_FIELD_IS_NOT_BITFIELD: - Jim_SetResultFormatted(goi.interp, + command_print(CMD, "Field `%s' is not a 'bitfield' field in a structure.", field_name); return ERROR_COMMAND_ARGUMENT_INVALID; @@ -904,9 +734,9 @@ static int jim_arc_get_reg_field(Jim_Interp *interp, int argc, Jim_Obj * const * return retval; } - Jim_SetResultInt(interp, value); + command_print(CMD, "0x%" PRIx32, value); - return JIM_OK; + return ERROR_OK; } COMMAND_HANDLER(arc_l1_cache_disable_auto_cmd) @@ -929,27 +759,17 @@ COMMAND_HANDLER(arc_l2_cache_disable_auto_cmd) &arc->has_l2cache, "target has l2 cache enabled"); } -static int jim_handle_actionpoints_num(Jim_Interp *interp, int argc, - Jim_Obj * const *argv) +COMMAND_HANDLER(arc_handle_actionpoints_num) { - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - LOG_DEBUG("-"); - if (goi.argc >= 2) { - Jim_WrongNumArgs(interp, goi.argc, goi.argv, "[<unsigned integer>]"); - return JIM_ERR; - } - - struct command_context *context = current_command_context(interp); - assert(context); - - struct target *target = get_current_target(context); + if (CMD_ARGC >= 2) + return ERROR_COMMAND_SYNTAX_ERROR; + struct target *target = get_current_target(CMD_CTX); if (!target) { - Jim_SetResultFormatted(goi.interp, "No current target"); - return JIM_ERR; + command_print(CMD, "No current target"); + return ERROR_FAIL; } struct arc_common *arc = target_to_arc(target); @@ -958,24 +778,24 @@ static int jim_handle_actionpoints_num(Jim_Interp *interp, int argc, * "actionpoint reset, initiated by arc_set_actionpoints_num. */ uint32_t ap_num = arc->actionpoints_num; - if (goi.argc == 1) { - JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &ap_num)); + if (CMD_ARGC == 1) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], ap_num); int e = arc_set_actionpoints_num(target, ap_num); if (e != ERROR_OK) { - Jim_SetResultFormatted(goi.interp, + command_print(CMD, "Failed to set number of actionpoints"); - return JIM_ERR; + return e; } } - Jim_SetResultInt(interp, ap_num); + command_print(CMD, "%" PRIu32, ap_num); - return JIM_OK; + return ERROR_OK; } /* ----- Exported target commands ------------------------------------------ */ -const struct command_registration arc_l2_cache_group_handlers[] = { +static const struct command_registration arc_l2_cache_group_handlers[] = { { .name = "auto", .handler = arc_l2_cache_disable_auto_cmd, @@ -986,7 +806,7 @@ const struct command_registration arc_l2_cache_group_handlers[] = { COMMAND_REGISTRATION_DONE }; -const struct command_registration arc_cache_group_handlers[] = { +static const struct command_registration arc_cache_group_handlers[] = { { .name = "auto", .handler = arc_l1_cache_disable_auto_cmd, @@ -1008,7 +828,7 @@ const struct command_registration arc_cache_group_handlers[] = { static const struct command_registration arc_core_command_handlers[] = { { .name = "add-reg-type-flags", - .jim_handler = jim_arc_add_reg_type_flags, + .handler = arc_handle_add_reg_type_flags, .mode = COMMAND_CONFIG, .usage = "-name <string> -flag <name> <position> " "[-flag <name> <position>]...", @@ -1018,7 +838,7 @@ static const struct command_registration arc_core_command_handlers[] = { }, { .name = "add-reg-type-struct", - .jim_handler = jim_arc_add_reg_type_struct, + .handler = arc_handle_add_reg_type_struct, .mode = COMMAND_CONFIG, .usage = "-name <string> -bitfield <name> <start> <end> " "[-bitfield <name> <start> <end>]...", @@ -1030,7 +850,7 @@ static const struct command_registration arc_core_command_handlers[] = { }, { .name = "add-reg", - .jim_handler = jim_arc_add_reg, + .handler = arc_handle_add_reg, .mode = COMMAND_CONFIG, .usage = "-name <string> -num <int> -feature <string> [-gdbnum <int>] " "[-core|-bcr] [-type <type_name>] [-g]", @@ -1049,7 +869,7 @@ static const struct command_registration arc_core_command_handlers[] = { }, { .name = "get-reg-field", - .jim_handler = jim_arc_get_reg_field, + .handler = arc_handle_get_reg_field, .mode = COMMAND_ANY, .usage = "<regname> <field_name>", .help = "Returns value of field in a register with 'struct' type.", @@ -1070,7 +890,7 @@ static const struct command_registration arc_core_command_handlers[] = { }, { .name = "num-actionpoints", - .jim_handler = jim_handle_actionpoints_num, + .handler = arc_handle_actionpoints_num, .mode = COMMAND_ANY, .usage = "[<unsigned integer>]", .help = "Prints or sets amount of actionpoints in the processor.", diff --git a/src/target/arc_cmd.h b/src/target/arc_cmd.h index b2264eb94a..f728bd5f82 100644 --- a/src/target/arc_cmd.h +++ b/src/target/arc_cmd.h @@ -1,11 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Mischa Jonker <mischa.jonker@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * - * * - * SPDX-License-Identifier: GPL-2.0-or-later * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARC_CMD_H diff --git a/src/target/arc_jtag.c b/src/target/arc_jtag.c index ca1a09649d..ddb4f62322 100644 --- a/src/target/arc_jtag.c +++ b/src/target/arc_jtag.c @@ -1,11 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Mischa Jonker <mischa.jonker@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * - * * - * SPDX-License-Identifier: GPL-2.0-or-later * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/arc_jtag.h b/src/target/arc_jtag.h index 99795f56ad..c2dc7b7ef9 100644 --- a/src/target/arc_jtag.h +++ b/src/target/arc_jtag.h @@ -1,11 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Mischa Jonker <mischa.jonker@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * - * * - * SPDX-License-Identifier: GPL-2.0-or-later * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARC_JTAG_H diff --git a/src/target/arc_mem.c b/src/target/arc_mem.c index 81d1ab2775..3264b663b6 100644 --- a/src/target/arc_mem.c +++ b/src/target/arc_mem.c @@ -1,11 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Mischa Jonker <mischa.jonker@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * - * * - * SPDX-License-Identifier: GPL-2.0-or-later * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -162,7 +162,7 @@ int arc_mem_write(struct target *target, target_addr_t address, uint32_t size, address, size, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/arc_mem.h b/src/target/arc_mem.h index 06e1c88d10..861823d227 100644 --- a/src/target/arc_mem.h +++ b/src/target/arc_mem.h @@ -1,10 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. * * Frank Dols <frank.dols@synopsys.com> * * Anton Kolesov <anton.kolesov@synopsys.com> * * Evgeniy Didin <didin@synopsys.com> * - * * - * SPDX-License-Identifier: GPL-2.0-or-later * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARC_MEM_H diff --git a/src/target/arm.h b/src/target/arm.h index 17327899b3..486666b5c6 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Copyright (C) 2005 by Dominic Rath * Dominic.Rath@gmx.de @@ -10,19 +12,6 @@ * * Copyright (C) 2018 by Liviu Ionescu * <ilg@livius.net> - * - * 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/>. */ #ifndef OPENOCD_TARGET_ARM_H @@ -69,6 +58,13 @@ enum arm_arch { ARM_ARCH_V8M, }; +/** Known ARM implementor IDs */ +enum arm_implementor { + ARM_IMPLEMENTOR_ARM = 0x41, + ARM_IMPLEMENTOR_INFINEON = 0x49, + ARM_IMPLEMENTOR_REALTEK = 0x72, +}; + /** * Represent state of an ARM core. * @@ -166,7 +162,7 @@ enum arm_vfp_version { ARM_VFP_V3, }; -#define ARM_COMMON_MAGIC 0x0A450A45 +#define ARM_COMMON_MAGIC 0x0A450A45U /** * Represents a generic ARM core, with standard application registers. @@ -176,7 +172,8 @@ enum arm_vfp_version { * registers as traditional ARM cores, and only support Thumb2 instructions. */ struct arm { - int common_magic; + unsigned int common_magic; + struct reg_cache *core_cache; /** Handle to the PC; valid in all core modes. */ @@ -234,12 +231,22 @@ struct arm { uint32_t crn, uint32_t crm, uint32_t *value); + /** Read coprocessor to two registers. */ + int (*mrrc)(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t *value); + /** Write coprocessor register. */ int (*mcr)(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value); + /** Write coprocessor from two registers. */ + int (*mcrr)(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t value); + void *arch_info; /** For targets conforming to ARM Debug Interface v5, @@ -250,7 +257,7 @@ struct arm { }; /** Convert target handle to generic ARM target state handle. */ -static inline struct arm *target_to_arm(struct target *target) +static inline struct arm *target_to_arm(const struct target *target) { assert(target); return target->arch_info; @@ -263,7 +270,7 @@ static inline bool is_arm(struct arm *arm) } struct arm_algorithm { - int common_magic; + unsigned int common_magic; enum arm_mode core_mode; enum arm_state core_state; @@ -283,13 +290,14 @@ void arm_free_reg_cache(struct arm *arm); struct reg_cache *armv8_build_reg_cache(struct target *target); extern const struct command_registration arm_command_handlers[]; +extern const struct command_registration arm_all_profiles_command_handlers[]; int arm_arch_state(struct target *target); -const char *arm_get_gdb_arch(struct target *target); +const char *arm_get_gdb_arch(const struct target *target); int arm_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); -const char *armv8_get_gdb_arch(struct target *target); +const char *armv8_get_gdb_arch(const struct target *target); int armv8_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); @@ -301,14 +309,14 @@ int armv4_5_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, - int timeout_ms, void *arch_info); + unsigned int timeout_ms, void *arch_info); int armv4_5_run_algorithm_inner(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, - int timeout_ms, void *arch_info, + unsigned int timeout_ms, void *arch_info, int (*run_it)(struct target *target, uint32_t exit_point, - int timeout_ms, void *arch_info)); + unsigned int timeout_ms, void *arch_info)); int arm_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); @@ -319,7 +327,4 @@ void arm_set_cpsr(struct arm *arm, uint32_t cpsr); struct reg *arm_reg_current(struct arm *arm, unsigned regnum); struct reg *armv8_reg_current(struct arm *arm, unsigned regnum); -extern struct reg arm_gdb_dummy_fp_reg; -extern struct reg arm_gdb_dummy_fps_reg; - #endif /* OPENOCD_TARGET_ARM_H */ diff --git a/src/target/arm11.c b/src/target/arm11.c index e3b0975fb3..50aaa86f12 100644 --- a/src/target/arm11.c +++ b/src/target/arm11.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2008 digenius technology GmbH. * * Michael Bruck * @@ -7,19 +9,6 @@ * Copyright (C) 2008 Georg Acher <acher@in.tum.de> * * * * Copyright (C) 2009 David Brownell * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -460,7 +449,7 @@ static int arm11_resume(struct target *target, int current, if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -562,7 +551,7 @@ static int arm11_step(struct target *target, int current, target_state_name(target)); if (target->state != TARGET_HALTED) { - LOG_WARNING("target was not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -809,7 +798,7 @@ static int arm11_read_memory_inner(struct target *target, int retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target was not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -907,7 +896,7 @@ static int arm11_write_memory_inner(struct target *target, int retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target was not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/arm11.h b/src/target/arm11.h index 77cc2236d7..1f56f7bba4 100644 --- a/src/target/arm11.h +++ b/src/target/arm11.h @@ -1,21 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2008 digenius technology GmbH. * * Michael Bruck * * * * Copyright (C) 2008 Georg Acher <acher@in.tum.de> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM11_H diff --git a/src/target/arm11_dbgtap.c b/src/target/arm11_dbgtap.c index fc35414df4..b670bd7f78 100644 --- a/src/target/arm11_dbgtap.c +++ b/src/target/arm11_dbgtap.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2008 digenius technology GmbH. * * Michael Bruck * * * * Copyright (C) 2008,2009 Oyvind Harboe oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/arm11_dbgtap.h b/src/target/arm11_dbgtap.h index c6b20a8954..eeb174a8ba 100644 --- a/src/target/arm11_dbgtap.h +++ b/src/target/arm11_dbgtap.h @@ -1,21 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2008 digenius technology GmbH. * * Michael Bruck * * * * Copyright (C) 2008,2009 Oyvind Harboe oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM11_DBGTAP_H diff --git a/src/target/arm720t.c b/src/target/arm720t.c index db75011cb7..beab632c25 100644 --- a/src/target/arm720t.c +++ b/src/target/arm720t.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2009 by Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -252,8 +241,8 @@ static int arm720t_arch_state(struct target *target) static int arm720_mmu(struct target *target, int *enabled) { if (target->state != TARGET_HALTED) { - LOG_ERROR("%s: target not halted", __func__); - return ERROR_TARGET_INVALID; + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; } *enabled = target_to_arm720(target)->armv4_5_mmu.mmu_enabled; diff --git a/src/target/arm720t.h b/src/target/arm720t.h index 31dad9c76c..65bd78ff08 100644 --- a/src/target/arm720t.h +++ b/src/target/arm720t.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM720T_H @@ -22,11 +11,12 @@ #include "arm7tdmi.h" #include "armv4_5_mmu.h" -#define ARM720T_COMMON_MAGIC 0xa720a720 +#define ARM720T_COMMON_MAGIC 0xa720a720U struct arm720t_common { + unsigned int common_magic; + struct arm7_9_common arm7_9_common; - uint32_t common_magic; struct armv4_5_mmu_common armv4_5_mmu; uint32_t cp15_control_reg; uint32_t fsr_reg; diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index da047c3d02..ad814e0541 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -12,19 +14,6 @@ * hontor@126.com * * * * Copyright (C) 2009 by David Brownell * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -195,7 +184,7 @@ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *break breakpoint->type); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -462,11 +451,12 @@ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watch struct arm7_9_common *arm7_9 = target_to_arm7_9(target); int rw_mask = 1; uint32_t mask; + const uint32_t wp_data_mask = watchpoint->mask; mask = watchpoint->length - 1; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -480,8 +470,8 @@ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watch watchpoint->address); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], - watchpoint->mask); - if (watchpoint->mask != 0xffffffffu) + wp_data_mask); + if (wp_data_mask != (uint32_t)WATCHPOINT_IGNORE_DATA_VALUE_MASK) embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_VALUE], watchpoint->value); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], @@ -499,8 +489,8 @@ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watch watchpoint->address); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], - watchpoint->mask); - if (watchpoint->mask != 0xffffffffu) + wp_data_mask); + if (wp_data_mask != (uint32_t)WATCHPOINT_IGNORE_DATA_VALUE_MASK) embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_VALUE], watchpoint->value); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], @@ -535,7 +525,7 @@ static int arm7_9_unset_watchpoint(struct target *target, struct watchpoint *wat struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1270,7 +1260,7 @@ static int arm7_9_debug_entry(struct target *target) return retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1401,7 +1391,7 @@ static int arm7_9_full_context(struct target *target) LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1517,7 +1507,7 @@ static int arm7_9_restore_context(struct target *target) LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1564,7 +1554,6 @@ static int arm7_9_restore_context(struct target *target) if (dirty) { uint32_t mask = 0x0; - int num_regs = 0; uint32_t regs[16]; if (mode_change) { @@ -1587,7 +1576,6 @@ static int arm7_9_restore_context(struct target *target) if (reg->dirty) { regs[j] = buf_get_u32(reg->value, 0, 32); mask |= 1 << j; - num_regs++; reg->dirty = false; reg->valid = true; LOG_DEBUG("writing register %i mode %s " @@ -1722,7 +1710,7 @@ int arm7_9_resume(struct target *target, LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1920,7 +1908,7 @@ int arm7_9_step(struct target *target, int current, target_addr_t address, int h int err, retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2131,7 +2119,7 @@ int arm7_9_read_memory(struct target *target, address, size, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2304,7 +2292,7 @@ int arm7_9_write_memory(struct target *target, #endif if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2531,7 +2519,7 @@ static const uint8_t *dcc_buffer; static int arm7_9_dcc_completion(struct target *target, uint32_t exit_point, - int timeout_ms, + unsigned int timeout_ms, void *arch_info) { int retval = ERROR_OK; diff --git a/src/target/arm7_9_common.h b/src/target/arm7_9_common.h index 4961212bb8..92d0fd51a2 100644 --- a/src/target/arm7_9_common.h +++ b/src/target/arm7_9_common.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -10,19 +12,6 @@ * * * Copyright (C) 2008 by Hongtao Zheng * * hontor@126.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM7_9_COMMON_H @@ -31,14 +20,15 @@ #include "arm.h" #include "arm_jtag.h" -#define ARM7_9_COMMON_MAGIC 0x0a790a79 /**< */ +#define ARM7_9_COMMON_MAGIC 0x0a790a79U /**< */ /** * Structure for items that are common between both ARM7 and ARM9 targets. */ struct arm7_9_common { + unsigned int common_magic; + struct arm arm; - uint32_t common_magic; struct arm_jtag jtag_info; /**< JTAG information for target */ struct reg_cache *eice_cache; /**< Embedded ICE register cache */ diff --git a/src/target/arm7tdmi.c b/src/target/arm7tdmi.c index b0348392f0..393d3b46af 100644 --- a/src/target/arm7tdmi.c +++ b/src/target/arm7tdmi.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/arm7tdmi.h b/src/target/arm7tdmi.h index 3cc3d4a7b4..369a514b4e 100644 --- a/src/target/arm7tdmi.h +++ b/src/target/arm7tdmi.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM7TDMI_H diff --git a/src/target/arm920t.c b/src/target/arm920t.c index a6d626eeea..53b4d9d15f 100644 --- a/src/target/arm920t.c +++ b/src/target/arm920t.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -544,8 +533,8 @@ int arm920t_arch_state(struct target *target) static int arm920_mmu(struct target *target, int *enabled) { if (target->state != TARGET_HALTED) { - LOG_ERROR("%s: target not halted", __func__); - return ERROR_TARGET_INVALID; + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; } *enabled = target_to_arm920(target)->armv4_5_mmu.mmu_enabled; @@ -1466,9 +1455,9 @@ COMMAND_HANDLER(arm920t_handle_cp15_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for " + command_print(CMD, "Error: target must be stopped for " "\"%s\" command", CMD_NAME); - return ERROR_OK; + return ERROR_TARGET_NOT_HALTED; } /* one argument, read a register. diff --git a/src/target/arm920t.h b/src/target/arm920t.h index 2e3b08ca3a..eba768ffff 100644 --- a/src/target/arm920t.h +++ b/src/target/arm920t.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM920T_H @@ -22,11 +11,12 @@ #include "arm9tdmi.h" #include "armv4_5_mmu.h" -#define ARM920T_COMMON_MAGIC 0xa920a920 +#define ARM920T_COMMON_MAGIC 0xa920a920U struct arm920t_common { + unsigned int common_magic; + struct arm7_9_common arm7_9_common; - uint32_t common_magic; struct armv4_5_mmu_common armv4_5_mmu; uint32_t cp15_control_reg; uint32_t d_fsr; diff --git a/src/target/arm926ejs.c b/src/target/arm926ejs.c index ea0927be6d..add90c9978 100644 --- a/src/target/arm926ejs.c +++ b/src/target/arm926ejs.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008,2009 by Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -765,8 +754,8 @@ static int arm926ejs_mmu(struct target *target, int *enabled) struct arm926ejs_common *arm926ejs = target_to_arm926(target); if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_INVALID; + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; } *enabled = arm926ejs->armv4_5_mmu.mmu_enabled; return ERROR_OK; diff --git a/src/target/arm926ejs.h b/src/target/arm926ejs.h index 0cd523af9c..479128e615 100644 --- a/src/target/arm926ejs.h +++ b/src/target/arm926ejs.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM926EJS_H @@ -22,11 +11,12 @@ #include "arm9tdmi.h" #include "armv4_5_mmu.h" -#define ARM926EJS_COMMON_MAGIC 0xa926a926 +#define ARM926EJS_COMMON_MAGIC 0xa926a926U struct arm926ejs_common { + unsigned int common_magic; + struct arm7_9_common arm7_9_common; - uint32_t common_magic; struct armv4_5_mmu_common armv4_5_mmu; int (*read_cp15)(struct target *target, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t *value); diff --git a/src/target/arm946e.c b/src/target/arm946e.c index 036e8bad7f..03f7e443fb 100644 --- a/src/target/arm946e.c +++ b/src/target/arm946e.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2010 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -55,7 +44,7 @@ static int arm946e_post_debug_entry(struct target *target); static void arm946e_pre_restore_context(struct target *target); static int arm946e_read_cp15(struct target *target, int reg_addr, uint32_t *value); -int arm946e_init_arch_info(struct target *target, +static int arm946e_init_arch_info(struct target *target, struct arm946e_common *arm946e, struct jtag_tap *tap) { @@ -184,7 +173,7 @@ static int arm946e_read_cp15(struct target *target, int reg_addr, uint32_t *valu return ERROR_OK; } -int arm946e_write_cp15(struct target *target, int reg_addr, uint32_t value) +static int arm946e_write_cp15(struct target *target, int reg_addr, uint32_t value) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); @@ -585,7 +574,7 @@ COMMAND_HANDLER(arm946e_handle_cp15) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); return ERROR_TARGET_NOT_HALTED; } @@ -635,7 +624,7 @@ COMMAND_HANDLER(arm946e_handle_idcache) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); return ERROR_TARGET_NOT_HALTED; } @@ -731,7 +720,7 @@ static const struct command_registration arm946e_exec_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -const struct command_registration arm946e_command_handlers[] = { +static const struct command_registration arm946e_command_handlers[] = { { .chain = arm9tdmi_command_handlers, }, diff --git a/src/target/arm946e.h b/src/target/arm946e.h index ee1ef3235f..0196c2b378 100644 --- a/src/target/arm946e.h +++ b/src/target/arm946e.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2010 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM946E_H @@ -27,11 +16,12 @@ #include "arm9tdmi.h" -#define ARM946E_COMMON_MAGIC 0x20f920f9 +#define ARM946E_COMMON_MAGIC 0x20f920f9U struct arm946e_common { + unsigned int common_magic; + struct arm7_9_common arm7_9_common; - int common_magic; uint32_t cp15_control_reg; uint32_t cp15_cache_info; }; @@ -42,10 +32,4 @@ static inline struct arm946e_common *target_to_arm946(struct target *target) arm7_9_common.arm); } -int arm946e_init_arch_info(struct target *target, - struct arm946e_common *arm946e, struct jtag_tap *tap); -int arm946e_write_cp15(struct target *target, int reg_addr, uint32_t value); - -extern const struct command_registration arm946e_command_handlers[]; - #endif /* OPENOCD_TARGET_ARM946E_H */ diff --git a/src/target/arm966e.c b/src/target/arm966e.c index b6d3e50e3f..8598d29d9b 100644 --- a/src/target/arm966e.c +++ b/src/target/arm966e.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -185,8 +174,8 @@ COMMAND_HANDLER(arm966e_handle_cp15_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } /* one or more argument, access a single register (write if second argument is given */ diff --git a/src/target/arm966e.h b/src/target/arm966e.h index aa2e9bb270..be2b3391e8 100644 --- a/src/target/arm966e.h +++ b/src/target/arm966e.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM966E_H @@ -24,11 +13,12 @@ #include "arm9tdmi.h" -#define ARM966E_COMMON_MAGIC 0x20f920f9 +#define ARM966E_COMMON_MAGIC 0x20f920f9U struct arm966e_common { + unsigned int common_magic; + struct arm7_9_common arm7_9_common; - int common_magic; uint32_t cp15_control_reg; }; diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c index 2a32f1127b..3bacfaefdf 100644 --- a/src/target/arm9tdmi.c +++ b/src/target/arm9tdmi.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Hongtao Zheng * * hontor@126.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -68,7 +57,7 @@ static const struct arm9tdmi_vector { {"dabt", ARM9TDMI_DABT_VECTOR}, {"irq", ARM9TDMI_IRQ_VECTOR}, {"fiq", ARM9TDMI_FIQ_VECTOR}, - {0, 0}, + {NULL, 0}, }; int arm9tdmi_examine_debug_reason(struct target *target) diff --git a/src/target/arm9tdmi.h b/src/target/arm9tdmi.h index 56946f78af..d2a27849e7 100644 --- a/src/target/arm9tdmi.h +++ b/src/target/arm9tdmi.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM9TDMI_H diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 8d6d6618bc..ff12658c83 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * @@ -14,19 +16,6 @@ * andreas.fritiofson@gmail.com * * * * Copyright (C) 2019-2021, Ampere Computing LLC * - * * - * 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/>. * ***************************************************************************/ /** @@ -61,7 +50,8 @@ /* * Relevant specifications from ARM include: * - * ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031E + * ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031F + * ARM(tm) Debug Interface v6 Architecture Specification ARM IHI 0074C * CoreSight(tm) v1.0 Architecture Specification ARM IHI 0029B * * CoreSight(tm) DAP-Lite TRM, ARM DDI 0316D @@ -107,7 +97,7 @@ static int mem_ap_setup_csw(struct adiv5_ap *ap, uint32_t csw) if (csw != ap->csw_value) { /* LOG_DEBUG("DAP: Set CSW %x",csw); */ - int retval = dap_queue_ap_write(ap, MEM_AP_REG_CSW, csw); + int retval = dap_queue_ap_write(ap, MEM_AP_REG_CSW(ap->dap), csw); if (retval != ERROR_OK) { ap->csw_value = 0; return retval; @@ -121,11 +111,11 @@ static int mem_ap_setup_tar(struct adiv5_ap *ap, target_addr_t tar) { if (!ap->tar_valid || tar != ap->tar_value) { /* LOG_DEBUG("DAP: Set TAR %x",tar); */ - int retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR, (uint32_t)(tar & 0xffffffffUL)); + int retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR(ap->dap), (uint32_t)(tar & 0xffffffffUL)); if (retval == ERROR_OK && is_64bit_ap(ap)) { /* See if bits 63:32 of tar is different from last setting */ - if ((ap->tar_value >> 32) != (tar >> 32)) - retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR64, (uint32_t)(tar >> 32)); + if (!ap->tar_valid || (ap->tar_value >> 32) != (tar >> 32)) + retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR64(ap->dap), (uint32_t)(tar >> 32)); } if (retval != ERROR_OK) { ap->tar_valid = false; @@ -142,9 +132,9 @@ static int mem_ap_read_tar(struct adiv5_ap *ap, target_addr_t *tar) uint32_t lower; uint32_t upper = 0; - int retval = dap_queue_ap_read(ap, MEM_AP_REG_TAR, &lower); + int retval = dap_queue_ap_read(ap, MEM_AP_REG_TAR(ap->dap), &lower); if (retval == ERROR_OK && is_64bit_ap(ap)) - retval = dap_queue_ap_read(ap, MEM_AP_REG_TAR64, &upper); + retval = dap_queue_ap_read(ap, MEM_AP_REG_TAR64(ap->dap), &upper); if (retval != ERROR_OK) { ap->tar_valid = false; @@ -175,6 +165,12 @@ static uint32_t mem_ap_get_tar_increment(struct adiv5_ap *ap) return 2; case CSW_32BIT: return 4; + case CSW_64BIT: + return 8; + case CSW_128BIT: + return 16; + case CSW_256BIT: + return 32; default: return 0; } @@ -252,7 +248,7 @@ int mem_ap_read_u32(struct adiv5_ap *ap, target_addr_t address, if (retval != ERROR_OK) return retval; - return dap_queue_ap_read(ap, MEM_AP_REG_BD0 | (address & 0xC), value); + return dap_queue_ap_read(ap, MEM_AP_REG_BD0(ap->dap) | (address & 0xC), value); } /** @@ -304,7 +300,7 @@ int mem_ap_write_u32(struct adiv5_ap *ap, target_addr_t address, if (retval != ERROR_OK) return retval; - return dap_queue_ap_write(ap, MEM_AP_REG_BD0 | (address & 0xC), + return dap_queue_ap_write(ap, MEM_AP_REG_BD0(ap->dap) | (address & 0xC), value); } @@ -330,12 +326,145 @@ int mem_ap_write_atomic_u32(struct adiv5_ap *ap, target_addr_t address, return dap_run(ap->dap); } +/** + * Queue transactions setting up transfer parameters for the + * currently selected MEM-AP. If transfer size or packing + * has not been probed, run the queue, read back CSW and check if the requested + * transfer mode is supported. + * + * @param ap The MEM-AP. + * @param size Transfer width in bytes. Corresponding CSW.Size will be set. + * @param address Transfer address, MEM-AP TAR will be set to this value. + * @param addrinc TAR will be autoincremented. + * @param pack Try to setup packed transfer. + * @param this_size Points to a variable set to the size of single transfer + * or to 4 when transferring packed bytes or halfwords + * + * @return ERROR_OK if the transaction was properly queued, else a fault code. + */ +static int mem_ap_setup_transfer_verify_size_packing(struct adiv5_ap *ap, + unsigned int size, target_addr_t address, + bool addrinc, bool pack, unsigned int *this_size) +{ + int retval; + uint32_t csw_size; + + switch (size) { + case 1: + csw_size = CSW_8BIT; + break; + case 2: + csw_size = CSW_16BIT; + break; + case 4: + csw_size = CSW_32BIT; + break; + case 8: + csw_size = CSW_64BIT; + break; + case 16: + csw_size = CSW_128BIT; + break; + case 32: + csw_size = CSW_256BIT; + break; + default: + LOG_ERROR("Size %u not supported", size); + return ERROR_TARGET_SIZE_NOT_SUPPORTED; + } + + if (!addrinc || size >= 4 + || (ap->packed_transfers_probed && !ap->packed_transfers_supported) + || max_tar_block_size(ap->tar_autoincr_block, address) < 4) + pack = false; + + uint32_t csw_addrinc = pack ? CSW_ADDRINC_PACKED : + addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF; + retval = mem_ap_setup_csw(ap, csw_size | csw_addrinc); + if (retval != ERROR_OK) + return retval; + + bool do_probe = !(ap->csw_size_probed_mask & size) + || (pack && !ap->packed_transfers_probed); + if (do_probe) { + uint32_t csw_readback; + retval = dap_queue_ap_read(ap, MEM_AP_REG_CSW(ap->dap), &csw_readback); + if (retval != ERROR_OK) + return retval; + + retval = dap_run(ap->dap); + if (retval != ERROR_OK) + return retval; + + bool size_supported = ((csw_readback & CSW_SIZE_MASK) == csw_size); + LOG_DEBUG("AP#0x%" PRIx64 " probed size %u: %s", ap->ap_num, size, + size_supported ? "supported" : "not supported"); + ap->csw_size_probed_mask |= size; + if (size_supported) { + ap->csw_size_supported_mask |= size; + if (pack && !ap->packed_transfers_probed) { + ap->packed_transfers_probed = true; + ap->packed_transfers_supported = + ((csw_readback & CSW_ADDRINC_MASK) == csw_addrinc); + LOG_DEBUG("probed packing: %s", + ap->packed_transfers_supported ? "supported" : "not supported"); + } + } + } + + if (!(ap->csw_size_supported_mask & size)) { + LOG_ERROR("Size %u not supported", size); + return ERROR_TARGET_SIZE_NOT_SUPPORTED; + } + + if (pack && !ap->packed_transfers_supported) + return ERROR_TARGET_PACKING_NOT_SUPPORTED; + + *this_size = pack ? 4 : size; + + return mem_ap_setup_tar(ap, address); +} + +/** + * Queue transactions setting up transfer parameters for the + * currently selected MEM-AP. If transfer size or packing + * has not been probed, run the queue, read back CSW and check if the requested + * transfer mode is supported. + * If packing is not supported fallback and prepare CSW for unpacked transfer. + * + * @param ap The MEM-AP. + * @param size Transfer width in bytes. Corresponding CSW.Size will be set. + * @param address Transfer address, MEM-AP TAR will be set to this value. + * @param addrinc TAR will be autoincremented. + * @param pack Try to setup packed transfer. + * @param this_size Points to a variable set to the size of single transfer + * or to 4 when transferring packed bytes or halfwords + * + * @return ERROR_OK if the transaction was properly queued, else a fault code. + */ +static int mem_ap_setup_transfer_verify_size_packing_fallback(struct adiv5_ap *ap, + unsigned int size, target_addr_t address, + bool addrinc, bool pack, unsigned int *this_size) +{ + int retval = mem_ap_setup_transfer_verify_size_packing(ap, + size, address, + addrinc, pack, this_size); + if (retval == ERROR_TARGET_PACKING_NOT_SUPPORTED) { + /* Retry without packing */ + retval = mem_ap_setup_transfer_verify_size_packing(ap, + size, address, + addrinc, false, this_size); + } + return retval; +} + /** * Synchronous write of a block of memory, using a specific access size. * * @param ap The MEM-AP to access. * @param buffer The data buffer to write. No particular alignment is assumed. - * @param size Which access size to use, in bytes. 1, 2 or 4. + * @param size Which access size to use, in bytes. 1, 2, or 4. + * If large data extension is available also accepts sizes 8, 16, 32. * @param count The number of writes to do (in size units, not bytes). * @param address Address to be written; it must be writable by the currently selected MEM-AP. * @param addrinc Whether the target address should be increased for each write or not. This @@ -347,9 +476,6 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz { struct adiv5_dap *dap = ap->dap; size_t nbytes = size * count; - const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF; - uint32_t csw_size; - target_addr_t addr_xor; int retval = ERROR_OK; /* TI BE-32 Quirks mode: @@ -364,83 +490,85 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz * To make writes of size < 4 work as expected, we xor a value with the address before * setting the TAP, and we set the TAP after every transfer rather then relying on * address increment. */ - - if (size == 4) { - csw_size = CSW_32BIT; - addr_xor = 0; - } else if (size == 2) { - csw_size = CSW_16BIT; - addr_xor = dap->ti_be_32_quirks ? 2 : 0; - } else if (size == 1) { - csw_size = CSW_8BIT; - addr_xor = dap->ti_be_32_quirks ? 3 : 0; - } else { - return ERROR_TARGET_UNALIGNED_ACCESS; + target_addr_t ti_be_addr_xor = 0; + target_addr_t ti_be_lane_xor = 0; + if (dap->ti_be_32_quirks) { + ti_be_lane_xor = 3; + switch (size) { + case 1: + ti_be_addr_xor = 3; + break; + case 2: + ti_be_addr_xor = 2; + break; + case 4: + break; + default: + LOG_ERROR("Write more than 32 bits not supported with ti_be_32_quirks"); + return ERROR_TARGET_SIZE_NOT_SUPPORTED; + } } if (ap->unaligned_access_bad && (address % size != 0)) return ERROR_TARGET_UNALIGNED_ACCESS; - while (nbytes > 0) { - uint32_t this_size = size; - - /* Select packed transfer if possible */ - if (addrinc && ap->packed_transfers && nbytes >= 4 - && max_tar_block_size(ap->tar_autoincr_block, address) >= 4) { - this_size = 4; - retval = mem_ap_setup_csw(ap, csw_size | CSW_ADDRINC_PACKED); - } else { - retval = mem_ap_setup_csw(ap, csw_size | csw_addrincr); - } - - if (retval != ERROR_OK) - break; + /* Nuvoton NPCX quirks prevent packed writes */ + bool pack = !dap->nu_npcx_quirks; - retval = mem_ap_setup_tar(ap, address ^ addr_xor); + while (nbytes > 0) { + unsigned int this_size; + retval = mem_ap_setup_transfer_verify_size_packing_fallback(ap, + size, address ^ ti_be_addr_xor, + addrinc, pack && nbytes >= 4, &this_size); if (retval != ERROR_OK) return retval; /* How many source bytes each transfer will consume, and their location in the DRW, * depends on the type of transfer and alignment. See ARM document IHI0031C. */ - uint32_t outvalue = 0; uint32_t drw_byte_idx = address; - if (dap->ti_be_32_quirks) { - switch (this_size) { - case 4: - outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor); - outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor); - outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx++ & 3) ^ addr_xor); - outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ (drw_byte_idx & 3) ^ addr_xor); - break; - case 2: - outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (drw_byte_idx++ & 3) ^ addr_xor); - outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ (drw_byte_idx & 3) ^ addr_xor); - break; - case 1: - outvalue |= (uint32_t)*buffer++ << 8 * (0 ^ (drw_byte_idx & 3) ^ addr_xor); - break; - } - } else { - switch (this_size) { - case 4: - outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3); - outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3); - /* fallthrough */ - case 2: - outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx++ & 3); - /* fallthrough */ - case 1: - outvalue |= (uint32_t)*buffer++ << 8 * (drw_byte_idx & 3); + unsigned int drw_ops = DIV_ROUND_UP(this_size, 4); + + while (drw_ops--) { + uint32_t outvalue = 0; + if (dap->nu_npcx_quirks && this_size <= 2) { + switch (this_size) { + case 2: + { + /* Alternate low and high byte to all byte lanes */ + uint32_t low = *buffer++; + uint32_t high = *buffer++; + outvalue |= low << 8 * (drw_byte_idx++ & 3); + outvalue |= high << 8 * (drw_byte_idx++ & 3); + outvalue |= low << 8 * (drw_byte_idx++ & 3); + outvalue |= high << 8 * (drw_byte_idx & 3); + } + break; + case 1: + { + /* Mirror output byte to all byte lanes */ + uint32_t data = *buffer++; + outvalue |= data; + outvalue |= data << 8; + outvalue |= data << 16; + outvalue |= data << 24; + } + } + } else { + unsigned int drw_bytes = MIN(this_size, 4); + while (drw_bytes--) + outvalue |= (uint32_t)*buffer++ << + 8 * ((drw_byte_idx++ & 3) ^ ti_be_lane_xor); } - } - - nbytes -= this_size; - retval = dap_queue_ap_write(ap, MEM_AP_REG_DRW, outvalue); + retval = dap_queue_ap_write(ap, MEM_AP_REG_DRW(dap), outvalue); + if (retval != ERROR_OK) + break; + } if (retval != ERROR_OK) break; mem_ap_update_tar_cache(ap); + nbytes -= this_size; if (addrinc) address += this_size; } @@ -465,7 +593,8 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz * * @param ap The MEM-AP to access. * @param buffer The data buffer to receive the data. No particular alignment is assumed. - * @param size Which access size to use, in bytes. 1, 2 or 4. + * @param size Which access size to use, in bytes. 1, 2, or 4. + * If large data extension is available also accepts sizes 8, 16, 32. * @param count The number of reads to do (in size units, not bytes). * @param adr Address to be read; it must be readable by the currently selected MEM-AP. * @param addrinc Whether the target address should be increased after each read or not. This @@ -477,8 +606,6 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint { struct adiv5_dap *dap = ap->dap; size_t nbytes = size * count; - const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : CSW_ADDRINC_OFF; - uint32_t csw_size; target_addr_t address = adr; int retval = ERROR_OK; @@ -487,16 +614,12 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint * They read from the physical address requested, but with DRW byte-reversed. * For example, a byte read from address 0 will place the result in the high bytes of DRW. * Also, packed 8-bit and 16-bit transfers seem to sometimes return garbage in some bytes, - * so avoid them. */ + * so avoid them (ap->packed_transfers is forced to false in mem_ap_init). */ - if (size == 4) - csw_size = CSW_32BIT; - else if (size == 2) - csw_size = CSW_16BIT; - else if (size == 1) - csw_size = CSW_8BIT; - else - return ERROR_TARGET_UNALIGNED_ACCESS; + if (dap->ti_be_32_quirks && size > 4) { + LOG_ERROR("Read more than 32 bits not supported with ti_be_32_quirks"); + return ERROR_TARGET_SIZE_NOT_SUPPORTED; + } if (ap->unaligned_access_bad && (adr % size != 0)) return ERROR_TARGET_UNALIGNED_ACCESS; @@ -504,7 +627,8 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint /* Allocate buffer to hold the sequence of DRW reads that will be made. This is a significant * over-allocation if packed transfers are going to be used, but determining the real need at * this point would be messy. */ - uint32_t *read_buf = calloc(count, sizeof(uint32_t)); + uint32_t *read_buf = calloc(count, MAX(sizeof(uint32_t), size)); + /* Multiplication count * sizeof(uint32_t) may overflow, calloc() is safe */ uint32_t *read_ptr = read_buf; if (!read_buf) { @@ -516,26 +640,20 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint * useful bytes it contains, and their location in the word, depends on the type of transfer * and alignment. */ while (nbytes > 0) { - uint32_t this_size = size; - - /* Select packed transfer if possible */ - if (addrinc && ap->packed_transfers && nbytes >= 4 - && max_tar_block_size(ap->tar_autoincr_block, address) >= 4) { - this_size = 4; - retval = mem_ap_setup_csw(ap, csw_size | CSW_ADDRINC_PACKED); - } else { - retval = mem_ap_setup_csw(ap, csw_size | csw_addrincr); - } + unsigned int this_size; + retval = mem_ap_setup_transfer_verify_size_packing_fallback(ap, + size, address, + addrinc, nbytes >= 4, &this_size); if (retval != ERROR_OK) break; - retval = mem_ap_setup_tar(ap, address); - if (retval != ERROR_OK) - break; - retval = dap_queue_ap_read(ap, MEM_AP_REG_DRW, read_ptr++); - if (retval != ERROR_OK) - break; + unsigned int drw_ops = DIV_ROUND_UP(this_size, 4); + while (drw_ops--) { + retval = dap_queue_ap_read(ap, MEM_AP_REG_DRW(dap), read_ptr++); + if (retval != ERROR_OK) + break; + } nbytes -= this_size; if (addrinc) @@ -554,7 +672,9 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint /* If something failed, read TAR to find out how much data was successfully read, so we can * at least give the caller what we have. */ - if (retval != ERROR_OK) { + if (retval == ERROR_TARGET_SIZE_NOT_SUPPORTED) { + nbytes = 0; + } else if (retval != ERROR_OK) { target_addr_t tar; if (mem_ap_read_tar(ap, &tar) == ERROR_OK) { /* TAR is incremented after failed transfer on some devices (eg Cortex-M4) */ @@ -567,39 +687,28 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint } } + target_addr_t ti_be_lane_xor = dap->ti_be_32_quirks ? 3 : 0; + /* Replay loop to populate caller's buffer from the correct word and byte lane */ while (nbytes > 0) { - uint32_t this_size = size; + /* Convert transfers longer than 32-bit on word-at-a-time basis */ + unsigned int this_size = MIN(size, 4); - if (addrinc && ap->packed_transfers && nbytes >= 4 + if (size < 4 && addrinc && ap->packed_transfers_supported && nbytes >= 4 && max_tar_block_size(ap->tar_autoincr_block, address) >= 4) { - this_size = 4; + this_size = 4; /* Packed read of 4 bytes or 2 halfwords */ } - if (dap->ti_be_32_quirks) { - switch (this_size) { - case 4: - *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); - *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); - /* fallthrough */ - case 2: - *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); - /* fallthrough */ - case 1: - *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); - } - } else { - switch (this_size) { - case 4: - *buffer++ = *read_ptr >> 8 * (address++ & 3); - *buffer++ = *read_ptr >> 8 * (address++ & 3); - /* fallthrough */ - case 2: - *buffer++ = *read_ptr >> 8 * (address++ & 3); - /* fallthrough */ - case 1: - *buffer++ = *read_ptr >> 8 * (address++ & 3); - } + switch (this_size) { + case 4: + *buffer++ = *read_ptr >> 8 * ((address++ & 3) ^ ti_be_lane_xor); + *buffer++ = *read_ptr >> 8 * ((address++ & 3) ^ ti_be_lane_xor); + /* fallthrough */ + case 2: + *buffer++ = *read_ptr >> 8 * ((address++ & 3) ^ ti_be_lane_xor); + /* fallthrough */ + case 1: + *buffer++ = *read_ptr >> 8 * ((address++ & 3) ^ ti_be_lane_xor); } read_ptr++; @@ -646,7 +755,11 @@ int mem_ap_write_buf_noincr(struct adiv5_ap *ap, */ void dap_invalidate_cache(struct adiv5_dap *dap) { - dap->select = DP_SELECT_INVALID; + dap->select = 0; /* speculate the first AP access will select AP 0, bank 0 */ + dap->select_valid = false; + dap->select1_valid = false; + dap->select_dpbanksel_valid = false; + dap->last_read = NULL; int i; @@ -774,13 +887,13 @@ int dap_dp_init_or_reconnect(struct adiv5_dap *dap) int mem_ap_init(struct adiv5_ap *ap) { /* check that we support packed transfers */ - uint32_t csw, cfg; + uint32_t cfg; int retval; struct adiv5_dap *dap = ap->dap; /* Set ap->cfg_reg before calling mem_ap_setup_transfer(). */ /* mem_ap_setup_transfer() needs to know if the MEM_AP supports LPAE. */ - retval = dap_queue_ap_read(ap, MEM_AP_REG_CFG, &cfg); + retval = dap_queue_ap_read(ap, MEM_AP_REG_CFG(dap), &cfg); if (retval != ERROR_OK) return retval; @@ -791,30 +904,23 @@ int mem_ap_init(struct adiv5_ap *ap) ap->cfg_reg = cfg; ap->tar_valid = false; ap->csw_value = 0; /* force csw and tar write */ - retval = mem_ap_setup_transfer(ap, CSW_8BIT | CSW_ADDRINC_PACKED, 0); - if (retval != ERROR_OK) - return retval; - - retval = dap_queue_ap_read(ap, MEM_AP_REG_CSW, &csw); - if (retval != ERROR_OK) - return retval; - retval = dap_run(dap); - if (retval != ERROR_OK) - return retval; + /* CSW 32-bit size must be supported (IHI 0031F and 0074D). */ + ap->csw_size_supported_mask = BIT(CSW_32BIT); + ap->csw_size_probed_mask = BIT(CSW_32BIT); - if (csw & CSW_ADDRINC_PACKED) - ap->packed_transfers = true; - else - ap->packed_transfers = false; + /* Suppress probing sizes longer than 32 bit if AP has no large data extension */ + if (!(cfg & MEM_AP_REG_CFG_LD)) + ap->csw_size_probed_mask |= BIT(CSW_64BIT) | BIT(CSW_128BIT) | BIT(CSW_256BIT); - /* Packed transfers on TI BE-32 processors do not work correctly in + /* Both IHI 0031F and 0074D state: Implementations that support transfers + * smaller than a word must support packed transfers. Unfortunately at least + * Cortex-M0 and Cortex-M0+ do not comply with this rule. + * Probe for packed transfers except we know they are broken. + * Packed transfers on TI BE-32 processors do not work correctly in * many cases. */ - if (dap->ti_be_32_quirks) - ap->packed_transfers = false; - - LOG_DEBUG("MEM_AP Packed Transfers: %s", - ap->packed_transfers ? "enabled" : "disabled"); + ap->packed_transfers_supported = false; + ap->packed_transfers_probed = dap->ti_be_32_quirks ? true : false; /* The ARM ADI spec leaves implementation-defined whether unaligned * memory accesses work, only work partially, or cause a sticky error. @@ -893,6 +999,57 @@ static const char *class_description[16] = { [0xF] = "CoreLink, PrimeCell or System component", }; +#define ARCH_ID(architect, archid) ( \ + (((architect) << ARM_CS_C9_DEVARCH_ARCHITECT_SHIFT) & ARM_CS_C9_DEVARCH_ARCHITECT_MASK) | \ + (((archid) << ARM_CS_C9_DEVARCH_ARCHID_SHIFT) & ARM_CS_C9_DEVARCH_ARCHID_MASK) \ +) + +static const struct { + uint32_t arch_id; + const char *description; +} class0x9_devarch[] = { + /* keep same unsorted order as in ARM IHI0029E */ + { ARCH_ID(ARM_ID, 0x0A00), "RAS architecture" }, + { ARCH_ID(ARM_ID, 0x1A01), "Instrumentation Trace Macrocell (ITM) architecture" }, + { ARCH_ID(ARM_ID, 0x1A02), "DWT architecture" }, + { ARCH_ID(ARM_ID, 0x1A03), "Flash Patch and Breakpoint unit (FPB) architecture" }, + { ARCH_ID(ARM_ID, 0x2A04), "Processor debug architecture (ARMv8-M)" }, + { ARCH_ID(ARM_ID, 0x6A05), "Processor debug architecture (ARMv8-R)" }, + { ARCH_ID(ARM_ID, 0x0A10), "PC sample-based profiling" }, + { ARCH_ID(ARM_ID, 0x4A13), "Embedded Trace Macrocell (ETM) architecture" }, + { ARCH_ID(ARM_ID, 0x1A14), "Cross Trigger Interface (CTI) architecture" }, + { ARCH_ID(ARM_ID, 0x6A15), "Processor debug architecture (v8.0-A)" }, + { ARCH_ID(ARM_ID, 0x7A15), "Processor debug architecture (v8.1-A)" }, + { ARCH_ID(ARM_ID, 0x8A15), "Processor debug architecture (v8.2-A)" }, + { ARCH_ID(ARM_ID, 0x2A16), "Processor Performance Monitor (PMU) architecture" }, + { ARCH_ID(ARM_ID, 0x0A17), "Memory Access Port v2 architecture" }, + { ARCH_ID(ARM_ID, 0x0A27), "JTAG Access Port v2 architecture" }, + { ARCH_ID(ARM_ID, 0x0A31), "Basic trace router" }, + { ARCH_ID(ARM_ID, 0x0A37), "Power requestor" }, + { ARCH_ID(ARM_ID, 0x0A47), "Unknown Access Port v2 architecture" }, + { ARCH_ID(ARM_ID, 0x0A50), "HSSTP architecture" }, + { ARCH_ID(ARM_ID, 0x0A63), "System Trace Macrocell (STM) architecture" }, + { ARCH_ID(ARM_ID, 0x0A75), "CoreSight ELA architecture" }, + { ARCH_ID(ARM_ID, 0x0AF7), "CoreSight ROM architecture" }, +}; + +#define DEVARCH_ID_MASK (ARM_CS_C9_DEVARCH_ARCHITECT_MASK | ARM_CS_C9_DEVARCH_ARCHID_MASK) +#define DEVARCH_MEM_AP ARCH_ID(ARM_ID, 0x0A17) +#define DEVARCH_ROM_C_0X9 ARCH_ID(ARM_ID, 0x0AF7) +#define DEVARCH_UNKNOWN_V2 ARCH_ID(ARM_ID, 0x0A47) + +static const char *class0x9_devarch_description(uint32_t devarch) +{ + if (!(devarch & ARM_CS_C9_DEVARCH_PRESENT)) + return "not present"; + + for (unsigned int i = 0; i < ARRAY_SIZE(class0x9_devarch); i++) + if ((devarch & DEVARCH_ID_MASK) == class0x9_devarch[i].arch_id) + return class0x9_devarch[i].description; + + return "unknown"; +} + static const struct { enum ap_type type; const char *description; @@ -917,22 +1074,57 @@ static const char *ap_type_to_description(enum ap_type type) return "Unknown"; } +bool is_ap_num_valid(struct adiv5_dap *dap, uint64_t ap_num) +{ + if (!dap) + return false; + + /* no autodetection, by now, so uninitialized is equivalent to ADIv5 for + * backward compatibility */ + if (!is_adiv6(dap)) { + if (ap_num > DP_APSEL_MAX) + return false; + return true; + } + + if (is_adiv6(dap)) { + if (ap_num & 0x0fffULL) + return false; + if (dap->asize != 0) + if (ap_num & ((~0ULL) << dap->asize)) + return false; + return true; + } + + return false; +} + /* * This function checks the ID for each access port to find the requested Access Port type + * It also calls dap_get_ap() to increment the AP refcount */ -int dap_find_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_ap **ap_out) +int dap_find_get_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_ap **ap_out) { - int ap_num; + if (is_adiv6(dap)) { + /* TODO: scan the ROM table and detect the AP available */ + LOG_DEBUG("On ADIv6 we cannot scan all the possible AP"); + return ERROR_FAIL; + } /* Maximum AP number is 255 since the SELECT register is 8 bits */ - for (ap_num = 0; ap_num <= DP_APSEL_MAX; ap_num++) { + for (unsigned int ap_num = 0; ap_num <= DP_APSEL_MAX; ap_num++) { + struct adiv5_ap *ap = dap_get_ap(dap, ap_num); + if (!ap) + continue; /* read the IDR register of the Access Port */ uint32_t id_val = 0; - int retval = dap_queue_ap_read(dap_ap(dap, ap_num), AP_REG_IDR, &id_val); - if (retval != ERROR_OK) + int retval = dap_queue_ap_read(ap, AP_REG_IDR(dap), &id_val); + if (retval != ERROR_OK) { + dap_put_ap(ap); return retval; + } retval = dap_run(dap); @@ -944,16 +1136,97 @@ int dap_find_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_a ap_type_to_description(type_to_find), ap_num, id_val); - *ap_out = &dap->ap[ap_num]; + *ap_out = ap; return ERROR_OK; } + dap_put_ap(ap); } LOG_DEBUG("No %s found", ap_type_to_description(type_to_find)); return ERROR_FAIL; } -int dap_get_debugbase(struct adiv5_ap *ap, +static inline bool is_ap_in_use(struct adiv5_ap *ap) +{ + return ap->refcount > 0 || ap->config_ap_never_release; +} + +static struct adiv5_ap *_dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num) +{ + if (!is_ap_num_valid(dap, ap_num)) { + LOG_ERROR("Invalid AP#0x%" PRIx64, ap_num); + return NULL; + } + if (is_adiv6(dap)) { + for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) { + struct adiv5_ap *ap = &dap->ap[i]; + if (is_ap_in_use(ap) && ap->ap_num == ap_num) { + ++ap->refcount; + return ap; + } + } + for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) { + struct adiv5_ap *ap = &dap->ap[i]; + if (!is_ap_in_use(ap)) { + ap->ap_num = ap_num; + ++ap->refcount; + return ap; + } + } + LOG_ERROR("No more AP available!"); + return NULL; + } + + /* ADIv5 */ + struct adiv5_ap *ap = &dap->ap[ap_num]; + ap->ap_num = ap_num; + ++ap->refcount; + return ap; +} + +/* Return AP with specified ap_num. Increment AP refcount */ +struct adiv5_ap *dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num) +{ + struct adiv5_ap *ap = _dap_get_ap(dap, ap_num); + if (ap) + LOG_DEBUG("refcount AP#0x%" PRIx64 " get %u", ap_num, ap->refcount); + return ap; +} + +/* Return AP with specified ap_num. Increment AP refcount and keep it non-zero */ +struct adiv5_ap *dap_get_config_ap(struct adiv5_dap *dap, uint64_t ap_num) +{ + struct adiv5_ap *ap = _dap_get_ap(dap, ap_num); + if (ap) { + ap->config_ap_never_release = true; + LOG_DEBUG("refcount AP#0x%" PRIx64 " get_config %u", ap_num, ap->refcount); + } + return ap; +} + +/* Decrement AP refcount and release the AP when refcount reaches zero */ +int dap_put_ap(struct adiv5_ap *ap) +{ + if (ap->refcount == 0) { + LOG_ERROR("BUG: refcount AP#0x%" PRIx64 " put underflow", ap->ap_num); + return ERROR_FAIL; + } + + --ap->refcount; + + LOG_DEBUG("refcount AP#0x%" PRIx64 " put %u", ap->ap_num, ap->refcount); + if (!is_ap_in_use(ap)) { + /* defaults from dap_instance_init() */ + ap->ap_num = DP_APSEL_INVALID; + ap->memaccess_tck = 255; + ap->tar_autoincr_block = (1 << 10); + ap->csw_default = CSW_AHB_DEFAULT; + ap->cfg_reg = MEM_AP_REG_CFG_INVALID; + } + return ERROR_OK; +} + +static int dap_get_debugbase(struct adiv5_ap *ap, target_addr_t *dbgbase, uint32_t *apid) { struct adiv5_dap *dap = ap->dap; @@ -961,19 +1234,19 @@ int dap_get_debugbase(struct adiv5_ap *ap, uint32_t baseptr_upper, baseptr_lower; if (ap->cfg_reg == MEM_AP_REG_CFG_INVALID) { - retval = dap_queue_ap_read(ap, MEM_AP_REG_CFG, &ap->cfg_reg); + retval = dap_queue_ap_read(ap, MEM_AP_REG_CFG(dap), &ap->cfg_reg); if (retval != ERROR_OK) return retval; } - retval = dap_queue_ap_read(ap, MEM_AP_REG_BASE, &baseptr_lower); + retval = dap_queue_ap_read(ap, MEM_AP_REG_BASE(dap), &baseptr_lower); if (retval != ERROR_OK) return retval; - retval = dap_queue_ap_read(ap, AP_REG_IDR, apid); + retval = dap_queue_ap_read(ap, AP_REG_IDR(dap), apid); if (retval != ERROR_OK) return retval; /* MEM_AP_REG_BASE64 is defined as 'RES0'; can be read and then ignored on 32 bits AP */ if (ap->cfg_reg == MEM_AP_REG_CFG_INVALID || is_64bit_ap(ap)) { - retval = dap_queue_ap_read(ap, MEM_AP_REG_BASE64, &baseptr_upper); + retval = dap_queue_ap_read(ap, MEM_AP_REG_BASE64(dap), &baseptr_upper); if (retval != ERROR_OK) return retval; } @@ -989,109 +1262,151 @@ int dap_get_debugbase(struct adiv5_ap *ap, return ERROR_OK; } -int dap_lookup_cs_component(struct adiv5_ap *ap, - target_addr_t dbgbase, uint8_t type, target_addr_t *addr, int32_t *idx) +int adiv6_dap_read_baseptr(struct command_invocation *cmd, struct adiv5_dap *dap, uint64_t *baseptr) { - uint32_t romentry, entry_offset = 0, devtype; - target_addr_t component_base; + uint32_t baseptr_lower, baseptr_upper = 0; int retval; - dbgbase &= 0xFFFFFFFFFFFFF000ull; - *addr = 0; - - do { - retval = mem_ap_read_atomic_u32(ap, dbgbase | - entry_offset, &romentry); + if (dap->asize > 32) { + retval = dap_queue_dp_read(dap, DP_BASEPTR1, &baseptr_upper); if (retval != ERROR_OK) return retval; + } - component_base = dbgbase + (target_addr_t)(romentry & ARM_CS_ROMENTRY_OFFSET_MASK); - - if (romentry & ARM_CS_ROMENTRY_PRESENT) { - uint32_t c_cid1; - retval = mem_ap_read_atomic_u32(ap, component_base + ARM_CS_CIDR1, &c_cid1); - if (retval != ERROR_OK) { - LOG_ERROR("Can't read component with base address " TARGET_ADDR_FMT - ", the corresponding core might be turned off", component_base); - return retval; - } - unsigned int class = (c_cid1 & ARM_CS_CIDR1_CLASS_MASK) >> ARM_CS_CIDR1_CLASS_SHIFT; - if (class == ARM_CS_CLASS_0X1_ROM_TABLE) { - retval = dap_lookup_cs_component(ap, component_base, - type, addr, idx); - if (retval == ERROR_OK) - break; - if (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) - return retval; - } + retval = dap_dp_read_atomic(dap, DP_BASEPTR0, &baseptr_lower); + if (retval != ERROR_OK) + return retval; - retval = mem_ap_read_atomic_u32(ap, component_base + ARM_CS_C9_DEVTYPE, &devtype); - if (retval != ERROR_OK) - return retval; - if ((devtype & ARM_CS_C9_DEVTYPE_MASK) == type) { - if (!*idx) { - *addr = component_base; - break; - } else - (*idx)--; - } - } - entry_offset += 4; - } while ((romentry > 0) && (entry_offset < 0xf00)); + if ((baseptr_lower & DP_BASEPTR0_VALID) != DP_BASEPTR0_VALID) { + command_print(cmd, "System root table not present"); + return ERROR_FAIL; + } - if (!*addr) - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + baseptr_lower &= ~0x0fff; + *baseptr = (((uint64_t)baseptr_upper) << 32) | baseptr_lower; return ERROR_OK; } -static int dap_read_part_id(struct adiv5_ap *ap, target_addr_t component_base, uint32_t *cid, uint64_t *pid) +/** + * Method to access the CoreSight component. + * On ADIv5, CoreSight components are on the bus behind a MEM-AP. + * On ADIv6, CoreSight components can either be on the bus behind a MEM-AP + * or directly in the AP. + */ +enum coresight_access_mode { + CS_ACCESS_AP, + CS_ACCESS_MEM_AP, +}; + +/** Holds registers and coordinates of a CoreSight component */ +struct cs_component_vals { + struct adiv5_ap *ap; + target_addr_t component_base; + uint64_t pid; + uint32_t cid; + uint32_t devarch; + uint32_t devid; + uint32_t devtype_memtype; + enum coresight_access_mode mode; +}; + +/** + * Helper to read CoreSight component's registers, either on the bus + * behind a MEM-AP or directly in the AP. + * + * @param mode Method to access the component (AP or MEM-AP). + * @param ap Pointer to AP containing the component. + * @param component_base On MEM-AP access method, base address of the component. + * @param reg Offset of the component's register to read. + * @param value Pointer to the store the read value. + * + * @return ERROR_OK on success, else a fault code. + */ +static int dap_queue_read_reg(enum coresight_access_mode mode, struct adiv5_ap *ap, + uint64_t component_base, unsigned int reg, uint32_t *value) +{ + if (mode == CS_ACCESS_AP) + return dap_queue_ap_read(ap, reg, value); + + /* mode == CS_ACCESS_MEM_AP */ + return mem_ap_read_u32(ap, component_base + reg, value); +} + +/** + * Read the CoreSight registers needed during ROM Table Parsing (RTP). + * + * @param mode Method to access the component (AP or MEM-AP). + * @param ap Pointer to AP containing the component. + * @param component_base On MEM-AP access method, base address of the component. + * @param v Pointer to the struct holding the value of registers. + * + * @return ERROR_OK on success, else a fault code. + */ +static int rtp_read_cs_regs(enum coresight_access_mode mode, struct adiv5_ap *ap, + target_addr_t component_base, struct cs_component_vals *v) { assert(IS_ALIGNED(component_base, ARM_CS_ALIGN)); - assert(ap && cid && pid); + assert(ap && v); uint32_t cid0, cid1, cid2, cid3; uint32_t pid0, pid1, pid2, pid3, pid4; - int retval; + int retval = ERROR_OK; - /* IDs are in last 4K section */ - retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR0, &pid0); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR1, &pid1); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR2, &pid2); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR3, &pid3); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR4, &pid4); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR0, &cid0); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR1, &cid1); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR2, &cid2); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR3, &cid3); - if (retval != ERROR_OK) - return retval; + v->ap = ap; + v->component_base = component_base; + v->mode = mode; - retval = dap_run(ap->dap); - if (retval != ERROR_OK) - return retval; + /* sort by offset to gain speed */ - *cid = (cid3 & 0xff) << 24 - | (cid2 & 0xff) << 16 - | (cid1 & 0xff) << 8 - | (cid0 & 0xff); - *pid = (uint64_t)(pid4 & 0xff) << 32 + /* + * Registers DEVARCH, DEVID and DEVTYPE are valid on Class 0x9 devices + * only, but are at offset above 0xf00, so can be read on any device + * without triggering error. Read them for eventual use on Class 0x9. + */ + if (retval == ERROR_OK) + retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_C9_DEVARCH, &v->devarch); + + if (retval == ERROR_OK) + retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_C9_DEVID, &v->devid); + + /* Same address as ARM_CS_C1_MEMTYPE */ + if (retval == ERROR_OK) + retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_C9_DEVTYPE, &v->devtype_memtype); + + if (retval == ERROR_OK) + retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR4, &pid4); + + if (retval == ERROR_OK) + retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR0, &pid0); + if (retval == ERROR_OK) + retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR1, &pid1); + if (retval == ERROR_OK) + retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR2, &pid2); + if (retval == ERROR_OK) + retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR3, &pid3); + + if (retval == ERROR_OK) + retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR0, &cid0); + if (retval == ERROR_OK) + retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR1, &cid1); + if (retval == ERROR_OK) + retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR2, &cid2); + if (retval == ERROR_OK) + retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR3, &cid3); + + if (retval == ERROR_OK) + retval = dap_run(ap->dap); + if (retval != ERROR_OK) { + LOG_DEBUG("Failed read CoreSight registers"); + return retval; + } + + v->cid = (cid3 & 0xff) << 24 + | (cid2 & 0xff) << 16 + | (cid1 & 0xff) << 8 + | (cid0 & 0xff); + v->pid = (uint64_t)(pid4 & 0xff) << 32 | (pid3 & 0xff) << 24 | (pid2 & 0xff) << 16 | (pid1 & 0xff) << 8 @@ -1397,48 +1712,427 @@ static int dap_devtype_display(struct command_invocation *cmd, uint32_t devtype) return ERROR_OK; } -static int dap_rom_display(struct command_invocation *cmd, - struct adiv5_ap *ap, target_addr_t dbgbase, int depth) +/** + * Actions/operations to be executed while parsing ROM tables. + */ +struct rtp_ops { + /** + * Executed at the start of a new AP, typically to print the AP header. + * @param ap Pointer to AP. + * @param depth The current depth level of ROM table. + * @param priv Pointer to private data. + * @return ERROR_OK on success, else a fault code. + */ + int (*ap_header)(struct adiv5_ap *ap, int depth, void *priv); + /** + * Executed at the start of a new MEM-AP, typically to print the MEM-AP header. + * @param retval Error encountered while reading AP. + * @param ap Pointer to AP. + * @param dbgbase Value of MEM-AP Debug Base Address register. + * @param apid Value of MEM-AP IDR Identification Register. + * @param depth The current depth level of ROM table. + * @param priv Pointer to private data. + * @return ERROR_OK on success, else a fault code. + */ + int (*mem_ap_header)(int retval, struct adiv5_ap *ap, uint64_t dbgbase, + uint32_t apid, int depth, void *priv); + /** + * Executed when a CoreSight component is parsed, typically to print + * information on the component. + * @param retval Error encountered while reading component's registers. + * @param v Pointer to a container of the component's registers. + * @param depth The current depth level of ROM table. + * @param priv Pointer to private data. + * @return ERROR_OK on success, else a fault code. + */ + int (*cs_component)(int retval, struct cs_component_vals *v, int depth, void *priv); + /** + * Executed for each entry of a ROM table, typically to print the entry + * and information about validity or end-of-table mark. + * @param retval Error encountered while reading the ROM table entry. + * @param depth The current depth level of ROM table. + * @param offset The offset of the entry in the ROM table. + * @param romentry The value of the ROM table entry. + * @param priv Pointer to private data. + * @return ERROR_OK on success, else a fault code. + */ + int (*rom_table_entry)(int retval, int depth, unsigned int offset, uint64_t romentry, + void *priv); + /** + * Private data + */ + void *priv; +}; + +/** + * Wrapper around struct rtp_ops::ap_header. + */ +static int rtp_ops_ap_header(const struct rtp_ops *ops, + struct adiv5_ap *ap, int depth) +{ + if (ops->ap_header) + return ops->ap_header(ap, depth, ops->priv); + + return ERROR_OK; +} + +/** + * Wrapper around struct rtp_ops::mem_ap_header. + * Input parameter @a retval is propagated. + */ +static int rtp_ops_mem_ap_header(const struct rtp_ops *ops, + int retval, struct adiv5_ap *ap, uint64_t dbgbase, uint32_t apid, int depth) +{ + if (!ops->mem_ap_header) + return retval; + + int retval1 = ops->mem_ap_header(retval, ap, dbgbase, apid, depth, ops->priv); + if (retval != ERROR_OK) + return retval; + return retval1; +} + +/** + * Wrapper around struct rtp_ops::cs_component. + * Input parameter @a retval is propagated. + */ +static int rtp_ops_cs_component(const struct rtp_ops *ops, + int retval, struct cs_component_vals *v, int depth) { + if (!ops->cs_component) + return retval; + + int retval1 = ops->cs_component(retval, v, depth, ops->priv); + if (retval != ERROR_OK) + return retval; + return retval1; +} + +/** + * Wrapper around struct rtp_ops::rom_table_entry. + * Input parameter @a retval is propagated. + */ +static int rtp_ops_rom_table_entry(const struct rtp_ops *ops, + int retval, int depth, unsigned int offset, uint64_t romentry) +{ + if (!ops->rom_table_entry) + return retval; + + int retval1 = ops->rom_table_entry(retval, depth, offset, romentry, ops->priv); + if (retval != ERROR_OK) + return retval; + return retval1; +} + +/* Broken ROM tables can have circular references. Stop after a while */ +#define ROM_TABLE_MAX_DEPTH (16) + +/** + * Value used only during lookup of a CoreSight component in ROM table. + * Return CORESIGHT_COMPONENT_FOUND when component is found. + * Return ERROR_OK when component is not found yet. + * Return any other ERROR_* in case of error. + */ +#define CORESIGHT_COMPONENT_FOUND (1) + +static int rtp_ap(const struct rtp_ops *ops, struct adiv5_ap *ap, int depth); +static int rtp_cs_component(enum coresight_access_mode mode, const struct rtp_ops *ops, + struct adiv5_ap *ap, target_addr_t dbgbase, bool *is_mem_ap, int depth); + +static int rtp_rom_loop(enum coresight_access_mode mode, const struct rtp_ops *ops, + struct adiv5_ap *ap, target_addr_t base_address, int depth, + unsigned int width, unsigned int max_entries) +{ + /* ADIv6 AP ROM table provide offset from current AP */ + if (mode == CS_ACCESS_AP) + base_address = ap->ap_num; + + assert(IS_ALIGNED(base_address, ARM_CS_ALIGN)); + + unsigned int offset = 0; + while (max_entries--) { + uint64_t romentry; + uint32_t romentry_low, romentry_high; + target_addr_t component_base; + unsigned int saved_offset = offset; + + int retval = dap_queue_read_reg(mode, ap, base_address, offset, &romentry_low); + offset += 4; + if (retval == ERROR_OK && width == 64) { + retval = dap_queue_read_reg(mode, ap, base_address, offset, &romentry_high); + offset += 4; + } + if (retval == ERROR_OK) + retval = dap_run(ap->dap); + if (retval != ERROR_OK) { + LOG_DEBUG("Failed read ROM table entry"); + return retval; + } + + if (width == 64) { + romentry = (((uint64_t)romentry_high) << 32) | romentry_low; + component_base = base_address + + ((((uint64_t)romentry_high) << 32) | (romentry_low & ARM_CS_ROMENTRY_OFFSET_MASK)); + } else { + romentry = romentry_low; + /* "romentry" is signed */ + component_base = base_address + (int32_t)(romentry_low & ARM_CS_ROMENTRY_OFFSET_MASK); + if (!is_64bit_ap(ap)) + component_base = (uint32_t)component_base; + } + retval = rtp_ops_rom_table_entry(ops, retval, depth, saved_offset, romentry); + if (retval != ERROR_OK) + return retval; + + if (romentry == 0) { + /* End of ROM table */ + break; + } + + if (!(romentry & ARM_CS_ROMENTRY_PRESENT)) + continue; + + /* Recurse */ + if (mode == CS_ACCESS_AP) { + struct adiv5_ap *next_ap = dap_get_ap(ap->dap, component_base); + if (!next_ap) { + LOG_DEBUG("Wrong AP # 0x%" PRIx64, component_base); + continue; + } + retval = rtp_ap(ops, next_ap, depth + 1); + dap_put_ap(next_ap); + } else { + /* mode == CS_ACCESS_MEM_AP */ + retval = rtp_cs_component(mode, ops, ap, component_base, NULL, depth + 1); + } + if (retval == CORESIGHT_COMPONENT_FOUND) + return CORESIGHT_COMPONENT_FOUND; + if (retval != ERROR_OK) { + /* TODO: do we need to send an ABORT before continuing? */ + LOG_DEBUG("Ignore error parsing CoreSight component"); + continue; + } + } + + return ERROR_OK; +} + +static int rtp_cs_component(enum coresight_access_mode mode, const struct rtp_ops *ops, + struct adiv5_ap *ap, target_addr_t base_address, bool *is_mem_ap, int depth) +{ + struct cs_component_vals v; int retval; - uint64_t pid; - uint32_t cid; - char tabs[16] = ""; - if (depth > 16) { + assert(IS_ALIGNED(base_address, ARM_CS_ALIGN)); + + if (is_mem_ap) + *is_mem_ap = false; + + if (depth > ROM_TABLE_MAX_DEPTH) + retval = ERROR_FAIL; + else + retval = rtp_read_cs_regs(mode, ap, base_address, &v); + + retval = rtp_ops_cs_component(ops, retval, &v, depth); + if (retval == CORESIGHT_COMPONENT_FOUND) + return CORESIGHT_COMPONENT_FOUND; + if (retval != ERROR_OK) + return ERROR_OK; /* Don't abort recursion */ + + if (!is_valid_arm_cs_cidr(v.cid)) + return ERROR_OK; /* Don't abort recursion */ + + const unsigned int class = ARM_CS_CIDR_CLASS(v.cid); + + if (class == ARM_CS_CLASS_0X1_ROM_TABLE) + return rtp_rom_loop(mode, ops, ap, base_address, depth, 32, 960); + + if (class == ARM_CS_CLASS_0X9_CS_COMPONENT) { + if ((v.devarch & ARM_CS_C9_DEVARCH_PRESENT) == 0) + return ERROR_OK; + + if (is_mem_ap) { + if ((v.devarch & DEVARCH_ID_MASK) == DEVARCH_MEM_AP) + *is_mem_ap = true; + + /* SoC-600 APv1 Adapter */ + if ((v.devarch & DEVARCH_ID_MASK) == DEVARCH_UNKNOWN_V2 && + ARM_CS_PIDR_DESIGNER(v.pid) == ARM_ID && + ARM_CS_PIDR_PART(v.pid) == 0x9e5) + *is_mem_ap = true; + } + + /* quit if not ROM table */ + if ((v.devarch & DEVARCH_ID_MASK) != DEVARCH_ROM_C_0X9) + return ERROR_OK; + + if ((v.devid & ARM_CS_C9_DEVID_FORMAT_MASK) == ARM_CS_C9_DEVID_FORMAT_64BIT) + return rtp_rom_loop(mode, ops, ap, base_address, depth, 64, 256); + else + return rtp_rom_loop(mode, ops, ap, base_address, depth, 32, 512); + } + + /* Class other than 0x1 and 0x9 */ + return ERROR_OK; +} + +static int rtp_ap(const struct rtp_ops *ops, struct adiv5_ap *ap, int depth) +{ + uint32_t apid; + target_addr_t dbgbase, invalid_entry; + + int retval = rtp_ops_ap_header(ops, ap, depth); + if (retval != ERROR_OK || depth > ROM_TABLE_MAX_DEPTH) + return ERROR_OK; /* Don't abort recursion */ + + if (is_adiv6(ap->dap)) { + bool is_mem_ap; + retval = rtp_cs_component(CS_ACCESS_AP, ops, ap, 0, &is_mem_ap, depth); + if (retval == CORESIGHT_COMPONENT_FOUND) + return CORESIGHT_COMPONENT_FOUND; + if (retval != ERROR_OK) + return ERROR_OK; /* Don't abort recursion */ + + if (!is_mem_ap) + return ERROR_OK; + /* Continue for an ADIv6 MEM-AP or SoC-600 APv1 Adapter */ + } + + /* Now we read ROM table ID registers, ref. ARM IHI 0029B sec */ + retval = dap_get_debugbase(ap, &dbgbase, &apid); + if (retval != ERROR_OK) + return retval; + retval = rtp_ops_mem_ap_header(ops, retval, ap, dbgbase, apid, depth); + if (retval != ERROR_OK) + return retval; + + if (apid == 0) + return ERROR_FAIL; + + /* NOTE: a MEM-AP may have a single CoreSight component that's + * not a ROM table ... or have no such components at all. + */ + const unsigned int class = (apid & AP_REG_IDR_CLASS_MASK) >> AP_REG_IDR_CLASS_SHIFT; + + if (class == AP_REG_IDR_CLASS_MEM_AP) { + if (is_64bit_ap(ap)) + invalid_entry = 0xFFFFFFFFFFFFFFFFull; + else + invalid_entry = 0xFFFFFFFFul; + + if (dbgbase != invalid_entry && (dbgbase & 0x3) != 0x2) { + retval = rtp_cs_component(CS_ACCESS_MEM_AP, ops, ap, + dbgbase & 0xFFFFFFFFFFFFF000ull, NULL, depth); + if (retval == CORESIGHT_COMPONENT_FOUND) + return CORESIGHT_COMPONENT_FOUND; + } + } + + return ERROR_OK; +} + +/* Actions for command "dap info" */ + +static int dap_info_ap_header(struct adiv5_ap *ap, int depth, void *priv) +{ + struct command_invocation *cmd = priv; + + if (depth > ROM_TABLE_MAX_DEPTH) { + command_print(cmd, "\tTables too deep"); + return ERROR_FAIL; + } + + command_print(cmd, "%sAP # 0x%" PRIx64, (depth) ? "\t\t" : "", ap->ap_num); + return ERROR_OK; +} + +static int dap_info_mem_ap_header(int retval, struct adiv5_ap *ap, + target_addr_t dbgbase, uint32_t apid, int depth, void *priv) +{ + struct command_invocation *cmd = priv; + target_addr_t invalid_entry; + char tabs[17] = ""; + + if (retval != ERROR_OK) { + command_print(cmd, "\t\tCan't read MEM-AP, the corresponding core might be turned off"); + return retval; + } + + if (depth > ROM_TABLE_MAX_DEPTH) { command_print(cmd, "\tTables too deep"); return ERROR_FAIL; } if (depth) - snprintf(tabs, sizeof(tabs), "[L%02d] ", depth); + snprintf(tabs, sizeof(tabs), "\t[L%02d] ", depth); - target_addr_t base_addr = dbgbase & 0xFFFFFFFFFFFFF000ull; - command_print(cmd, "\t\tComponent base address " TARGET_ADDR_FMT, base_addr); + command_print(cmd, "\t\tAP ID register 0x%8.8" PRIx32, apid); + if (apid == 0) { + command_print(cmd, "\t\tNo AP found at this AP#0x%" PRIx64, ap->ap_num); + return ERROR_FAIL; + } + + command_print(cmd, "\t\tType is %s", ap_type_to_description(apid & AP_TYPE_MASK)); + + /* NOTE: a MEM-AP may have a single CoreSight component that's + * not a ROM table ... or have no such components at all. + */ + const unsigned int class = (apid & AP_REG_IDR_CLASS_MASK) >> AP_REG_IDR_CLASS_SHIFT; + + if (class == AP_REG_IDR_CLASS_MEM_AP) { + if (is_64bit_ap(ap)) + invalid_entry = 0xFFFFFFFFFFFFFFFFull; + else + invalid_entry = 0xFFFFFFFFul; + + command_print(cmd, "%sMEM-AP BASE " TARGET_ADDR_FMT, tabs, dbgbase); + + if (dbgbase == invalid_entry || (dbgbase & 0x3) == 0x2) { + command_print(cmd, "\t\tNo ROM table present"); + } else { + if (dbgbase & 0x01) + command_print(cmd, "\t\tValid ROM table present"); + else + command_print(cmd, "\t\tROM table in legacy format"); + } + } + + return ERROR_OK; +} + +static int dap_info_cs_component(int retval, struct cs_component_vals *v, int depth, void *priv) +{ + struct command_invocation *cmd = priv; + + if (depth > ROM_TABLE_MAX_DEPTH) { + command_print(cmd, "\tTables too deep"); + return ERROR_FAIL; + } + + if (v->mode == CS_ACCESS_MEM_AP) + command_print(cmd, "\t\tComponent base address " TARGET_ADDR_FMT, v->component_base); - retval = dap_read_part_id(ap, base_addr, &cid, &pid); if (retval != ERROR_OK) { command_print(cmd, "\t\tCan't read component, the corresponding core might be turned off"); - return ERROR_OK; /* Don't abort recursion */ + return retval; } - if (!is_valid_arm_cs_cidr(cid)) { - command_print(cmd, "\t\tInvalid CID 0x%08" PRIx32, cid); + if (!is_valid_arm_cs_cidr(v->cid)) { + command_print(cmd, "\t\tInvalid CID 0x%08" PRIx32, v->cid); return ERROR_OK; /* Don't abort recursion */ } /* component may take multiple 4K pages */ - uint32_t size = ARM_CS_PIDR_SIZE(pid); + uint32_t size = ARM_CS_PIDR_SIZE(v->pid); if (size > 0) - command_print(cmd, "\t\tStart address " TARGET_ADDR_FMT, base_addr - 0x1000 * size); + command_print(cmd, "\t\tStart address " TARGET_ADDR_FMT, v->component_base - 0x1000 * size); - command_print(cmd, "\t\tPeripheral ID 0x%010" PRIx64, pid); + command_print(cmd, "\t\tPeripheral ID 0x%010" PRIx64, v->pid); - const unsigned int class = (cid & ARM_CS_CIDR_CLASS_MASK) >> ARM_CS_CIDR_CLASS_SHIFT; - const unsigned int part_num = ARM_CS_PIDR_PART(pid); - unsigned int designer_id = ARM_CS_PIDR_DESIGNER(pid); + const unsigned int part_num = ARM_CS_PIDR_PART(v->pid); + unsigned int designer_id = ARM_CS_PIDR_DESIGNER(v->pid); - if (pid & ARM_CS_PIDR_JEDEC) { + if (v->pid & ARM_CS_PIDR_JEDEC) { /* JEP106 code */ command_print(cmd, "\t\tDesigner is 0x%03x, %s", designer_id, jep106_manufacturer(designer_id)); @@ -1451,103 +2145,165 @@ static int dap_rom_display(struct command_invocation *cmd, const struct dap_part_nums *partnum = pidr_to_part_num(designer_id, part_num); command_print(cmd, "\t\tPart is 0x%03x, %s %s", part_num, partnum->type, partnum->full); + + const unsigned int class = ARM_CS_CIDR_CLASS(v->cid); command_print(cmd, "\t\tComponent class is 0x%x, %s", class, class_description[class]); if (class == ARM_CS_CLASS_0X1_ROM_TABLE) { - uint32_t memtype; - retval = mem_ap_read_atomic_u32(ap, base_addr + ARM_CS_C1_MEMTYPE, &memtype); - if (retval != ERROR_OK) - return retval; - - if (memtype & ARM_CS_C1_MEMTYPE_SYSMEM_MASK) + if (v->devtype_memtype & ARM_CS_C1_MEMTYPE_SYSMEM_MASK) command_print(cmd, "\t\tMEMTYPE system memory present on bus"); else command_print(cmd, "\t\tMEMTYPE system memory not present: dedicated debug bus"); + return ERROR_OK; + } - /* Read ROM table entries from base address until we get 0x00000000 or reach the reserved area */ - for (uint16_t entry_offset = 0; entry_offset < 0xF00; entry_offset += 4) { - uint32_t romentry; - retval = mem_ap_read_atomic_u32(ap, base_addr | entry_offset, &romentry); - if (retval != ERROR_OK) - return retval; - command_print(cmd, "\t%sROMTABLE[0x%x] = 0x%" PRIx32 "", - tabs, entry_offset, romentry); - if (romentry & ARM_CS_ROMENTRY_PRESENT) { - /* Recurse. "romentry" is signed */ - retval = dap_rom_display(cmd, ap, base_addr + (int32_t)(romentry & ARM_CS_ROMENTRY_OFFSET_MASK), - depth + 1); - if (retval != ERROR_OK) - return retval; - } else if (romentry != 0) { - command_print(cmd, "\t\tComponent not present"); - } else { - command_print(cmd, "\t%s\tEnd of ROM table", tabs); - break; - } + if (class == ARM_CS_CLASS_0X9_CS_COMPONENT) { + dap_devtype_display(cmd, v->devtype_memtype); + + /* REVISIT also show ARM_CS_C9_DEVID */ + + if ((v->devarch & ARM_CS_C9_DEVARCH_PRESENT) == 0) + return ERROR_OK; + + unsigned int architect_id = ARM_CS_C9_DEVARCH_ARCHITECT(v->devarch); + unsigned int revision = ARM_CS_C9_DEVARCH_REVISION(v->devarch); + command_print(cmd, "\t\tDev Arch is 0x%08" PRIx32 ", %s \"%s\" rev.%u", v->devarch, + jep106_manufacturer(architect_id), class0x9_devarch_description(v->devarch), + revision); + + if ((v->devarch & DEVARCH_ID_MASK) == DEVARCH_ROM_C_0X9) { + command_print(cmd, "\t\tType is ROM table"); + + if (v->devid & ARM_CS_C9_DEVID_SYSMEM_MASK) + command_print(cmd, "\t\tMEMTYPE system memory present on bus"); + else + command_print(cmd, "\t\tMEMTYPE system memory not present: dedicated debug bus"); } - } else if (class == ARM_CS_CLASS_0X9_CS_COMPONENT) { - uint32_t devtype; - retval = mem_ap_read_atomic_u32(ap, base_addr + ARM_CS_C9_DEVTYPE, &devtype); - if (retval != ERROR_OK) - return retval; + return ERROR_OK; + } - retval = dap_devtype_display(cmd, devtype); - if (retval != ERROR_OK) - return retval; + /* Class other than 0x1 and 0x9 */ + return ERROR_OK; +} - /* REVISIT also show ARM_CS_C9_DEVID */ +static int dap_info_rom_table_entry(int retval, int depth, + unsigned int offset, uint64_t romentry, void *priv) +{ + struct command_invocation *cmd = priv; + char tabs[16] = ""; + + if (depth) + snprintf(tabs, sizeof(tabs), "[L%02d] ", depth); + + if (retval != ERROR_OK) { + command_print(cmd, "\t%sROMTABLE[0x%x] Read error", tabs, offset); + command_print(cmd, "\t\tUnable to continue"); + command_print(cmd, "\t%s\tStop parsing of ROM table", tabs); + return retval; + } + + command_print(cmd, "\t%sROMTABLE[0x%x] = 0x%08" PRIx64, + tabs, offset, romentry); + + if (romentry == 0) { + command_print(cmd, "\t%s\tEnd of ROM table", tabs); + return ERROR_OK; + } + + if (!(romentry & ARM_CS_ROMENTRY_PRESENT)) { + command_print(cmd, "\t\tComponent not present"); + return ERROR_OK; } return ERROR_OK; } -int dap_info_command(struct command_invocation *cmd, - struct adiv5_ap *ap) +int dap_info_command(struct command_invocation *cmd, struct adiv5_ap *ap) { - int retval; - uint32_t apid; - target_addr_t dbgbase; - target_addr_t dbgaddr; + struct rtp_ops dap_info_ops = { + .ap_header = dap_info_ap_header, + .mem_ap_header = dap_info_mem_ap_header, + .cs_component = dap_info_cs_component, + .rom_table_entry = dap_info_rom_table_entry, + .priv = cmd, + }; + + return rtp_ap(&dap_info_ops, ap, 0); +} + +/* Actions for dap_lookup_cs_component() */ + +struct dap_lookup_data { + /* input */ + unsigned int idx; + unsigned int type; + /* output */ + uint64_t component_base; + uint64_t ap_num; +}; + +static int dap_lookup_cs_component_cs_component(int retval, + struct cs_component_vals *v, int depth, void *priv) +{ + struct dap_lookup_data *lookup = priv; - /* Now we read ROM table ID registers, ref. ARM IHI 0029B sec */ - retval = dap_get_debugbase(ap, &dbgbase, &apid); if (retval != ERROR_OK) return retval; - command_print(cmd, "AP ID register 0x%8.8" PRIx32, apid); - if (apid == 0) { - command_print(cmd, "No AP found at this ap 0x%x", ap->ap_num); - return ERROR_FAIL; - } + if (!is_valid_arm_cs_cidr(v->cid)) + return ERROR_OK; - command_print(cmd, "\tType is %s", ap_type_to_description(apid & AP_TYPE_MASK)); + const unsigned int class = ARM_CS_CIDR_CLASS(v->cid); + if (class != ARM_CS_CLASS_0X9_CS_COMPONENT) + return ERROR_OK; - /* NOTE: a MEM-AP may have a single CoreSight component that's - * not a ROM table ... or have no such components at all. - */ - const unsigned int class = (apid & AP_REG_IDR_CLASS_MASK) >> AP_REG_IDR_CLASS_SHIFT; + if ((v->devtype_memtype & ARM_CS_C9_DEVTYPE_MASK) != lookup->type) + return ERROR_OK; - if (class == AP_REG_IDR_CLASS_MEM_AP) { - if (is_64bit_ap(ap)) - dbgaddr = 0xFFFFFFFFFFFFFFFFull; - else - dbgaddr = 0xFFFFFFFFul; + if (lookup->idx) { + /* search for next one */ + --lookup->idx; + return ERROR_OK; + } - command_print(cmd, "MEM-AP BASE " TARGET_ADDR_FMT, dbgbase); + /* Found! */ + lookup->component_base = v->component_base; + lookup->ap_num = v->ap->ap_num; + return CORESIGHT_COMPONENT_FOUND; +} - if (dbgbase == dbgaddr || (dbgbase & 0x3) == 0x2) { - command_print(cmd, "\tNo ROM table present"); - } else { - if (dbgbase & 0x01) - command_print(cmd, "\tValid ROM table present"); - else - command_print(cmd, "\tROM table in legacy format"); +int dap_lookup_cs_component(struct adiv5_ap *ap, uint8_t type, + target_addr_t *addr, int32_t core_id) +{ + struct dap_lookup_data lookup = { + .type = type, + .idx = core_id, + }; + struct rtp_ops dap_lookup_cs_component_ops = { + .ap_header = NULL, + .mem_ap_header = NULL, + .cs_component = dap_lookup_cs_component_cs_component, + .rom_table_entry = NULL, + .priv = &lookup, + }; - dap_rom_display(cmd, ap, dbgbase & 0xFFFFFFFFFFFFF000ull, 0); + int retval = rtp_ap(&dap_lookup_cs_component_ops, ap, 0); + if (retval == CORESIGHT_COMPONENT_FOUND) { + if (lookup.ap_num != ap->ap_num) { + /* TODO: handle search from root ROM table */ + LOG_DEBUG("CS lookup ended in AP # 0x%" PRIx64 ". Ignore it", lookup.ap_num); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } + LOG_DEBUG("CS lookup found at 0x%" PRIx64, lookup.component_base); + *addr = lookup.component_base; + return ERROR_OK; } - - return ERROR_OK; + if (retval != ERROR_OK) { + LOG_DEBUG("CS lookup error %d", retval); + return retval; + } + LOG_DEBUG("CS lookup not found"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } enum adiv5_cfg_param { @@ -1566,8 +2322,10 @@ static const struct jim_nvp nvp_config_opts[] = { }; static int adiv5_jim_spot_configure(struct jim_getopt_info *goi, - struct adiv5_dap **dap_p, int *ap_num_p, uint32_t *base_p) + struct adiv5_dap **dap_p, uint64_t *ap_num_p, uint32_t *base_p) { + assert(dap_p && ap_num_p); + if (!goi->argc) return JIM_OK; @@ -1619,11 +2377,13 @@ static int adiv5_jim_spot_configure(struct jim_getopt_info *goi, case CFG_AP_NUM: if (goi->isconfigure) { + /* jim_wide is a signed 64 bits int, ap_num is unsigned with max 52 bits */ jim_wide ap_num; e = jim_getopt_wide(goi, &ap_num); if (e != JIM_OK) return e; - if (ap_num < 0 || ap_num > DP_APSEL_MAX) { + /* we still don't know dap->adi_version */ + if (ap_num < 0 || (ap_num > DP_APSEL_MAX && (ap_num & 0xfff))) { Jim_SetResultString(goi->interp, "Invalid AP number!", -1); return JIM_ERR; } @@ -1672,6 +2432,10 @@ int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi) pc = (struct adiv5_private_config *)target->private_config; if (!pc) { pc = calloc(1, sizeof(struct adiv5_private_config)); + if (!pc) { + LOG_ERROR("Out of memory"); + return JIM_ERR; + } pc->ap_num = DP_APSEL_INVALID; target->private_config = pc; } @@ -1724,15 +2488,27 @@ int adiv5_mem_ap_spot_init(struct adiv5_mem_ap_spot *p) COMMAND_HANDLER(handle_dap_info_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); - uint32_t apsel; + uint64_t apsel; switch (CMD_ARGC) { case 0: apsel = dap->apsel; break; case 1: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); - if (apsel > DP_APSEL_MAX) { + if (!strcmp(CMD_ARGV[0], "root")) { + if (!is_adiv6(dap)) { + command_print(CMD, "Option \"root\" not allowed with ADIv5 DAP"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + int retval = adiv6_dap_read_baseptr(CMD, dap, &apsel); + if (retval != ERROR_OK) { + command_print(CMD, "Failed reading DAP baseptr"); + return retval; + } + break; + } + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); + if (!is_ap_num_valid(dap, apsel)) { command_print(CMD, "Invalid AP number"); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -1741,13 +2517,22 @@ COMMAND_HANDLER(handle_dap_info_command) return ERROR_COMMAND_SYNTAX_ERROR; } - return dap_info_command(CMD, &dap->ap[apsel]); + struct adiv5_ap *ap = dap_get_ap(dap, apsel); + if (!ap) { + command_print(CMD, "Cannot get AP"); + return ERROR_FAIL; + } + + int retval = dap_info_command(CMD, ap); + dap_put_ap(ap); + return retval; } COMMAND_HANDLER(dap_baseaddr_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); - uint32_t apsel, baseaddr_lower, baseaddr_upper; + uint64_t apsel; + uint32_t baseaddr_lower, baseaddr_upper; struct adiv5_ap *ap; target_addr_t baseaddr; int retval; @@ -1759,9 +2544,8 @@ COMMAND_HANDLER(dap_baseaddr_command) apsel = dap->apsel; break; case 1: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); - /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel > DP_APSEL_MAX) { + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); + if (!is_ap_num_valid(dap, apsel)) { command_print(CMD, "Invalid AP number"); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -1776,19 +2560,25 @@ COMMAND_HANDLER(dap_baseaddr_command) * use the ID register to verify it's a MEM-AP. */ - ap = dap_ap(dap, apsel); - retval = dap_queue_ap_read(ap, MEM_AP_REG_BASE, &baseaddr_lower); + ap = dap_get_ap(dap, apsel); + if (!ap) { + command_print(CMD, "Cannot get AP"); + return ERROR_FAIL; + } + + retval = dap_queue_ap_read(ap, MEM_AP_REG_BASE(dap), &baseaddr_lower); if (retval == ERROR_OK && ap->cfg_reg == MEM_AP_REG_CFG_INVALID) - retval = dap_queue_ap_read(ap, MEM_AP_REG_CFG, &ap->cfg_reg); + retval = dap_queue_ap_read(ap, MEM_AP_REG_CFG(dap), &ap->cfg_reg); if (retval == ERROR_OK && (ap->cfg_reg == MEM_AP_REG_CFG_INVALID || is_64bit_ap(ap))) { /* MEM_AP_REG_BASE64 is defined as 'RES0'; can be read and then ignored on 32 bits AP */ - retval = dap_queue_ap_read(ap, MEM_AP_REG_BASE64, &baseaddr_upper); + retval = dap_queue_ap_read(ap, MEM_AP_REG_BASE64(dap), &baseaddr_upper); } if (retval == ERROR_OK) retval = dap_run(dap); + dap_put_ap(ap); if (retval != ERROR_OK) return retval; @@ -1804,22 +2594,35 @@ COMMAND_HANDLER(dap_baseaddr_command) COMMAND_HANDLER(dap_memaccess_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); + struct adiv5_ap *ap; uint32_t memaccess_tck; switch (CMD_ARGC) { case 0: - memaccess_tck = dap->ap[dap->apsel].memaccess_tck; + ap = dap_get_ap(dap, dap->apsel); + if (!ap) { + command_print(CMD, "Cannot get AP"); + return ERROR_FAIL; + } + memaccess_tck = ap->memaccess_tck; break; case 1: + ap = dap_get_config_ap(dap, dap->apsel); + if (!ap) { + command_print(CMD, "Cannot get AP"); + return ERROR_FAIL; + } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], memaccess_tck); + ap->memaccess_tck = memaccess_tck; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } - dap->ap[dap->apsel].memaccess_tck = memaccess_tck; + + dap_put_ap(ap); command_print(CMD, "memory bus access delay set to %" PRIu32 " tck", - dap->ap[dap->apsel].memaccess_tck); + memaccess_tck); return ERROR_OK; } @@ -1827,16 +2630,15 @@ COMMAND_HANDLER(dap_memaccess_command) COMMAND_HANDLER(dap_apsel_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); - uint32_t apsel; + uint64_t apsel; switch (CMD_ARGC) { case 0: - command_print(CMD, "%" PRIu32, dap->apsel); + command_print(CMD, "0x%" PRIx64, dap->apsel); return ERROR_OK; case 1: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); - /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel > DP_APSEL_MAX) { + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); + if (!is_ap_num_valid(dap, apsel)) { command_print(CMD, "Invalid AP number"); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -1852,14 +2654,19 @@ COMMAND_HANDLER(dap_apsel_command) COMMAND_HANDLER(dap_apcsw_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); - uint32_t apcsw = dap->ap[dap->apsel].csw_default; + struct adiv5_ap *ap; uint32_t csw_val, csw_mask; switch (CMD_ARGC) { case 0: - command_print(CMD, "ap %" PRIu32 " selected, csw 0x%8.8" PRIx32, - dap->apsel, apcsw); - return ERROR_OK; + ap = dap_get_ap(dap, dap->apsel); + if (!ap) { + command_print(CMD, "Cannot get AP"); + return ERROR_FAIL; + } + command_print(CMD, "AP#0x%" PRIx64 " selected, csw 0x%8.8" PRIx32, + dap->apsel, ap->csw_default); + break; case 1: if (strcmp(CMD_ARGV[0], "default") == 0) csw_val = CSW_AHB_DEFAULT; @@ -1870,7 +2677,12 @@ COMMAND_HANDLER(dap_apcsw_command) LOG_ERROR("CSW value cannot include 'Size' and 'AddrInc' bit-fields"); return ERROR_COMMAND_ARGUMENT_INVALID; } - apcsw = csw_val; + ap = dap_get_config_ap(dap, dap->apsel); + if (!ap) { + command_print(CMD, "Cannot get AP"); + return ERROR_FAIL; + } + ap->csw_default = csw_val; break; case 2: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], csw_val); @@ -1879,14 +2691,19 @@ COMMAND_HANDLER(dap_apcsw_command) LOG_ERROR("CSW mask cannot include 'Size' and 'AddrInc' bit-fields"); return ERROR_COMMAND_ARGUMENT_INVALID; } - apcsw = (apcsw & ~csw_mask) | (csw_val & csw_mask); + ap = dap_get_config_ap(dap, dap->apsel); + if (!ap) { + command_print(CMD, "Cannot get AP"); + return ERROR_FAIL; + } + ap->csw_default = (ap->csw_default & ~csw_mask) | (csw_val & csw_mask); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } - dap->ap[dap->apsel].csw_default = apcsw; + dap_put_ap(ap); - return 0; + return ERROR_OK; } @@ -1894,7 +2711,8 @@ COMMAND_HANDLER(dap_apcsw_command) COMMAND_HANDLER(dap_apid_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); - uint32_t apsel, apid; + uint64_t apsel; + uint32_t apid; int retval; switch (CMD_ARGC) { @@ -1902,9 +2720,8 @@ COMMAND_HANDLER(dap_apid_command) apsel = dap->apsel; break; case 1: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); - /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel > DP_APSEL_MAX) { + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); + if (!is_ap_num_valid(dap, apsel)) { command_print(CMD, "Invalid AP number"); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -1913,10 +2730,18 @@ COMMAND_HANDLER(dap_apid_command) return ERROR_COMMAND_SYNTAX_ERROR; } - retval = dap_queue_ap_read(dap_ap(dap, apsel), AP_REG_IDR, &apid); - if (retval != ERROR_OK) + struct adiv5_ap *ap = dap_get_ap(dap, apsel); + if (!ap) { + command_print(CMD, "Cannot get AP"); + return ERROR_FAIL; + } + retval = dap_queue_ap_read(ap, AP_REG_IDR(dap), &apid); + if (retval != ERROR_OK) { + dap_put_ap(ap); return retval; + } retval = dap_run(dap); + dap_put_ap(ap); if (retval != ERROR_OK) return retval; @@ -1928,38 +2753,47 @@ COMMAND_HANDLER(dap_apid_command) COMMAND_HANDLER(dap_apreg_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); - uint32_t apsel, reg, value; - struct adiv5_ap *ap; + uint64_t apsel; + uint32_t reg, value; int retval; if (CMD_ARGC < 2 || CMD_ARGC > 3) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); - /* AP address is in bits 31:24 of DP_SELECT */ - if (apsel > DP_APSEL_MAX) { + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); + if (!is_ap_num_valid(dap, apsel)) { command_print(CMD, "Invalid AP number"); return ERROR_COMMAND_ARGUMENT_INVALID; } - ap = dap_ap(dap, apsel); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg); - if (reg >= 256 || (reg & 3)) { - command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)"); - return ERROR_COMMAND_ARGUMENT_INVALID; + if (is_adiv6(dap)) { + if (reg >= 4096 || (reg & 3)) { + command_print(CMD, "Invalid reg value (should be less than 4096 and 4 bytes aligned)"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } else { /* ADI version 5 */ + if (reg >= 256 || (reg & 3)) { + command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } + + struct adiv5_ap *ap = dap_get_ap(dap, apsel); + if (!ap) { + command_print(CMD, "Cannot get AP"); + return ERROR_FAIL; } if (CMD_ARGC == 3) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); - switch (reg) { - case MEM_AP_REG_CSW: + /* see if user supplied register address is a match for the CSW or TAR register */ + if (reg == MEM_AP_REG_CSW(dap)) { ap->csw_value = 0; /* invalid, in case write fails */ retval = dap_queue_ap_write(ap, reg, value); if (retval == ERROR_OK) ap->csw_value = value; - break; - case MEM_AP_REG_TAR: + } else if (reg == MEM_AP_REG_TAR(dap)) { retval = dap_queue_ap_write(ap, reg, value); if (retval == ERROR_OK) ap->tar_value = (ap->tar_value & ~0xFFFFFFFFull) | value; @@ -1970,8 +2804,7 @@ COMMAND_HANDLER(dap_apreg_command) /* if tar_valid is false. */ ap->tar_valid = false; } - break; - case MEM_AP_REG_TAR64: + } else if (reg == MEM_AP_REG_TAR64(dap)) { retval = dap_queue_ap_write(ap, reg, value); if (retval == ERROR_OK) ap->tar_value = (ap->tar_value & 0xFFFFFFFFull) | (((target_addr_t)value) << 32); @@ -1979,10 +2812,8 @@ COMMAND_HANDLER(dap_apreg_command) /* See above comment for the MEM_AP_REG_TAR failed write case */ ap->tar_valid = false; } - break; - default: + } else { retval = dap_queue_ap_write(ap, reg, value); - break; } } else { retval = dap_queue_ap_read(ap, reg, &value); @@ -1990,6 +2821,8 @@ COMMAND_HANDLER(dap_apreg_command) if (retval == ERROR_OK) retval = dap_run(dap); + dap_put_ap(ap); + if (retval != ERROR_OK) return retval; @@ -2039,14 +2872,21 @@ COMMAND_HANDLER(dap_ti_be_32_quirks_command) "TI BE-32 quirks mode"); } +COMMAND_HANDLER(dap_nu_npcx_quirks_command) +{ + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); + return CALL_COMMAND_HANDLER(handle_command_parse_bool, &dap->nu_npcx_quirks, + "Nuvoton NPCX quirks mode"); +} + const struct command_registration dap_instance_commands[] = { { .name = "info", .handler = handle_dap_info_command, .mode = COMMAND_EXEC, - .help = "display ROM table for MEM-AP " - "(default currently selected AP)", - .usage = "[ap_num]", + .help = "display ROM table for specified MEM-AP (default currently selected AP) " + "or the ADIv6 root ROM table", + .usage = "[ap_num | 'root']", }, { .name = "apsel", @@ -2111,5 +2951,12 @@ const struct command_registration dap_instance_commands[] = { .help = "set/get quirks mode for TI TMS450/TMS570 processors", .usage = "[enable]", }, + { + .name = "nu_npcx_quirks", + .handler = dap_nu_npcx_quirks_command, + .mode = COMMAND_CONFIG, + .help = "set/get quirks mode for Nuvoton NPCX controllers", + .usage = "[enable]", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index 5c598f16e3..60c161f3ca 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * @@ -5,18 +7,7 @@ * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * - * 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/>. * + * Copyright (C) 2019-2021, Ampere Computing LLC * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM_ADI_V5_H @@ -53,11 +44,15 @@ */ #define DP_DPIDR BANK_REG(0x0, 0x0) /* DPv1+: ro */ #define DP_ABORT BANK_REG(0x0, 0x0) /* DPv1+: SWD: wo */ +#define DP_DPIDR1 BANK_REG(0x1, 0x0) /* DPv3: ro */ +#define DP_BASEPTR0 BANK_REG(0x2, 0x0) /* DPv3: ro */ +#define DP_BASEPTR1 BANK_REG(0x3, 0x0) /* DPv3: ro */ #define DP_CTRL_STAT BANK_REG(0x0, 0x4) /* DPv0+: rw */ #define DP_DLCR BANK_REG(0x1, 0x4) /* DPv1+: SWD: rw */ #define DP_TARGETID BANK_REG(0x2, 0x4) /* DPv2: ro */ #define DP_DLPIDR BANK_REG(0x3, 0x4) /* DPv2: ro */ #define DP_EVENTSTAT BANK_REG(0x4, 0x4) /* DPv2: ro */ +#define DP_SELECT1 BANK_REG(0x5, 0x4) /* DPv3: ro */ #define DP_RESEND BANK_REG(0x0, 0x8) /* DPv1+: SWD: ro */ #define DP_SELECT BANK_REG(0x0, 0x8) /* DPv0+: JTAG: rw; SWD: wo */ #define DP_RDBUFF BANK_REG(0x0, 0xC) /* DPv0+: ro */ @@ -76,6 +71,13 @@ #define WDERRCLR (1UL << 3) /* SWD-only */ #define ORUNERRCLR (1UL << 4) /* SWD-only */ +/* Fields of register DP_DPIDR1 */ +#define DP_DPIDR1_ASIZE_MASK (0x7F) +#define DP_DPIDR1_ERRMODE BIT(7) + +/* Fields of register DP_BASEPTR0 */ +#define DP_BASEPTR0_VALID BIT(0) + /* Fields of the DP's CTRL/STAT register */ #define CORUNDETECT (1UL << 0) #define SSTICKYORUN (1UL << 1) @@ -95,41 +97,77 @@ #define DP_DLPIDR_PROTVSN 1u -#define DP_SELECT_APSEL 0xFF000000 -#define DP_SELECT_APBANK 0x000000F0 -#define DP_SELECT_DPBANK 0x0000000F -#define DP_SELECT_INVALID 0x00FFFF00 /* Reserved bits one */ +#define ADIV5_DP_SELECT_APSEL 0xFF000000 +#define ADIV5_DP_SELECT_APBANK 0x000000F0 +#define DP_SELECT_DPBANK 0x0000000F +/* + * Mask of AP ADDR in select cache, concatenating DP SELECT and DP_SELECT1. + * In case of ADIv5, the mask contains both APSEL and APBANKSEL fields. + */ +#define SELECT_AP_MASK (~(uint64_t)DP_SELECT_DPBANK) -#define DP_APSEL_MAX (255) -#define DP_APSEL_INVALID (-1) +#define DP_APSEL_MAX (255) /* Strict limit for ADIv5, number of AP buffers for ADIv6 */ +#define DP_APSEL_INVALID 0xF00 /* more than DP_APSEL_MAX and not ADIv6 aligned 4k */ -#define DP_TARGETSEL_INVALID 0xFFFFFFFFU -#define DP_TARGETSEL_DPID_MASK 0x0FFFFFFFU +#define DP_TARGETSEL_INVALID 0xFFFFFFFFU +#define DP_TARGETSEL_DPID_MASK 0x0FFFFFFFU #define DP_TARGETSEL_INSTANCEID_MASK 0xF0000000U #define DP_TARGETSEL_INSTANCEID_SHIFT 28 /* MEM-AP register addresses */ -#define MEM_AP_REG_CSW 0x00 -#define MEM_AP_REG_TAR 0x04 -#define MEM_AP_REG_TAR64 0x08 /* RW: Large Physical Address Extension */ -#define MEM_AP_REG_DRW 0x0C /* RW: Data Read/Write register */ -#define MEM_AP_REG_BD0 0x10 /* RW: Banked Data register 0-3 */ -#define MEM_AP_REG_BD1 0x14 -#define MEM_AP_REG_BD2 0x18 -#define MEM_AP_REG_BD3 0x1C -#define MEM_AP_REG_MBT 0x20 /* --: Memory Barrier Transfer register */ -#define MEM_AP_REG_BASE64 0xF0 /* RO: Debug Base Address (LA) register */ -#define MEM_AP_REG_CFG 0xF4 /* RO: Configuration register */ -#define MEM_AP_REG_BASE 0xF8 /* RO: Debug Base Address register */ +#define ADIV5_MEM_AP_REG_CSW (0x00) +#define ADIV5_MEM_AP_REG_TAR (0x04) +#define ADIV5_MEM_AP_REG_TAR64 (0x08) /* RW: Large Physical Address Extension */ +#define ADIV5_MEM_AP_REG_DRW (0x0C) /* RW: Data Read/Write register */ +#define ADIV5_MEM_AP_REG_BD0 (0x10) /* RW: Banked Data register 0-3 */ +#define ADIV5_MEM_AP_REG_BD1 (0x14) +#define ADIV5_MEM_AP_REG_BD2 (0x18) +#define ADIV5_MEM_AP_REG_BD3 (0x1C) +#define ADIV5_MEM_AP_REG_MBT (0x20) /* --: Memory Barrier Transfer register */ +#define ADIV5_MEM_AP_REG_BASE64 (0xF0) /* RO: Debug Base Address (LA) register */ +#define ADIV5_MEM_AP_REG_CFG (0xF4) /* RO: Configuration register */ +#define ADIV5_MEM_AP_REG_BASE (0xF8) /* RO: Debug Base Address register */ + +#define ADIV6_MEM_AP_REG_CSW (0xD00 + ADIV5_MEM_AP_REG_CSW) +#define ADIV6_MEM_AP_REG_TAR (0xD00 + ADIV5_MEM_AP_REG_TAR) +#define ADIV6_MEM_AP_REG_TAR64 (0xD00 + ADIV5_MEM_AP_REG_TAR64) +#define ADIV6_MEM_AP_REG_DRW (0xD00 + ADIV5_MEM_AP_REG_DRW) +#define ADIV6_MEM_AP_REG_BD0 (0xD00 + ADIV5_MEM_AP_REG_BD0) +#define ADIV6_MEM_AP_REG_BD1 (0xD00 + ADIV5_MEM_AP_REG_BD1) +#define ADIV6_MEM_AP_REG_BD2 (0xD00 + ADIV5_MEM_AP_REG_BD2) +#define ADIV6_MEM_AP_REG_BD3 (0xD00 + ADIV5_MEM_AP_REG_BD3) +#define ADIV6_MEM_AP_REG_MBT (0xD00 + ADIV5_MEM_AP_REG_MBT) +#define ADIV6_MEM_AP_REG_BASE64 (0xD00 + ADIV5_MEM_AP_REG_BASE64) +#define ADIV6_MEM_AP_REG_CFG (0xD00 + ADIV5_MEM_AP_REG_CFG) +#define ADIV6_MEM_AP_REG_BASE (0xD00 + ADIV5_MEM_AP_REG_BASE) + +#define MEM_AP_REG_CSW(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_CSW : ADIV5_MEM_AP_REG_CSW) +#define MEM_AP_REG_TAR(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_TAR : ADIV5_MEM_AP_REG_TAR) +#define MEM_AP_REG_TAR64(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_TAR64 : ADIV5_MEM_AP_REG_TAR64) +#define MEM_AP_REG_DRW(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_DRW : ADIV5_MEM_AP_REG_DRW) +#define MEM_AP_REG_BD0(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_BD0 : ADIV5_MEM_AP_REG_BD0) +#define MEM_AP_REG_BD1(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_BD1 : ADIV5_MEM_AP_REG_BD1) +#define MEM_AP_REG_BD2(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_BD2 : ADIV5_MEM_AP_REG_BD2) +#define MEM_AP_REG_BD3(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_BD3 : ADIV5_MEM_AP_REG_BD3) +#define MEM_AP_REG_MBT(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_MBT : ADIV5_MEM_AP_REG_MBT) +#define MEM_AP_REG_BASE64(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_BASE64 : ADIV5_MEM_AP_REG_BASE64) +#define MEM_AP_REG_CFG(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_CFG : ADIV5_MEM_AP_REG_CFG) +#define MEM_AP_REG_BASE(dap) (is_adiv6(dap) ? ADIV6_MEM_AP_REG_BASE : ADIV5_MEM_AP_REG_BASE) + /* Generic AP register address */ -#define AP_REG_IDR 0xFC /* RO: Identification Register */ +#define ADIV5_AP_REG_IDR (0xFC) /* RO: Identification Register */ +#define ADIV6_AP_REG_IDR (0xD00 + ADIV5_AP_REG_IDR) +#define AP_REG_IDR(dap) (is_adiv6(dap) ? ADIV6_AP_REG_IDR : ADIV5_AP_REG_IDR) /* Fields of the MEM-AP's CSW register */ #define CSW_SIZE_MASK 7 #define CSW_8BIT 0 #define CSW_16BIT 1 #define CSW_32BIT 2 +#define CSW_64BIT 3 +#define CSW_128BIT 4 +#define CSW_256BIT 5 #define CSW_ADDRINC_MASK (3UL << 4) #define CSW_ADDRINC_OFF 0UL #define CSW_ADDRINC_SINGLE (1UL << 4) @@ -216,9 +254,11 @@ struct adiv5_ap { struct adiv5_dap *dap; /** - * Number of this AP. + * ADIv5: Number of this AP (0~255) + * ADIv6: Base address of this AP (4k aligned) + * TODO: to be more coherent, it should be renamed apsel */ - uint8_t ap_num; + uint64_t ap_num; /** * Default value for (MEM-AP) AP_REG_CSW register. @@ -232,6 +272,26 @@ struct adiv5_ap { */ uint32_t csw_value; + /** + * Save the supported CSW.Size data types for the MEM-AP. + * Each bit corresponds to a data type. + * 0b1 = Supported data size. 0b0 = Not supported. + * Bit 0 = Byte (8-bits) + * Bit 1 = Halfword (16-bits) + * Bit 2 = Word (32-bits) - always supported by spec. + * Bit 3 = Doubleword (64-bits) + * Bit 4 = 128-bits + * Bit 5 = 256-bits + */ + uint32_t csw_size_supported_mask; + /** + * Probed CSW.Size data types for the MEM-AP. + * Each bit corresponds to a data type. + * 0b1 = Data size has been probed. 0b0 = Not yet probed. + * Bits assigned to sizes same way as above. + */ + uint32_t csw_size_probed_mask; + /** * Cache for (MEM-AP) AP_REG_TAR register value This is written to * configure the address being read or written @@ -249,7 +309,8 @@ struct adiv5_ap { uint32_t tar_autoincr_block; /* true if packed transfers are supported by the MEM-AP */ - bool packed_transfers; + bool packed_transfers_supported; + bool packed_transfers_probed; /* true if unaligned memory access is not supported by the MEM-AP */ bool unaligned_access_bad; @@ -259,6 +320,12 @@ struct adiv5_ap { /* MEM AP configuration register indicating LPAE support */ uint32_t cfg_reg; + + /* references counter */ + unsigned int refcount; + + /* AP referenced during config. Never put it, even when refcount reaches zero */ + bool config_ap_never_release; }; @@ -297,13 +364,23 @@ struct adiv5_dap { struct adiv5_ap ap[DP_APSEL_MAX + 1]; /* The current manually selected AP by the "dap apsel" command */ - uint32_t apsel; + uint64_t apsel; + /** Cache for DP SELECT and SELECT1 (ADIv6) register. */ + uint64_t select; + /** Validity of DP SELECT cache. false will force register rewrite */ + bool select_valid; + bool select1_valid; /* ADIv6 only */ /** - * Cache for DP_SELECT register. A value of DP_SELECT_INVALID - * indicates no cached value and forces rewrite of the register. + * Partial DPBANKSEL validity for SWD only. + * ADIv6 line reset sets DP SELECT DPBANKSEL to zero, + * ADIv5 does not. + * We can rely on it for the banked DP register 0 also on ADIv5 + * as ADIv5 has no mapping for DP reg 0 - it is always DPIDR. + * It is important to avoid setting DP SELECT in connection + * reset state before reading DPIDR. */ - uint32_t select; + bool select_dpbanksel_valid; /* information about current pending SWjDP-AHBAP transaction */ uint8_t ack; @@ -320,6 +397,10 @@ struct adiv5_dap { * swizzle appropriately. */ bool ti_be_32_quirks; + /* The Nuvoton NPCX M4 has an issue with writing to non-4-byte-aligned mmios. + * The work around is to repeat the data in all 4 bytes of DRW */ + bool nu_npcx_quirks; + /** * STLINK adapter need to know if last AP operation was read or write, and * in case of write has to flush it with a dummy read from DP_RDBUFF @@ -347,6 +428,12 @@ struct adiv5_dap { * Record if enter in SWD required passing through DORMANT */ bool switch_through_dormant; + + /** Indicates ADI version (5, 6 or 0 for unknown) being used */ + unsigned int adi_version; + + /* ADIv6 only field indicating ROM Table address size */ + unsigned int asize; }; /** @@ -357,6 +444,9 @@ struct adiv5_dap { * available until run(). */ struct dap_ops { + /** Optional; called once on the first enabled dap before connecting */ + int (*pre_connect_init)(struct adiv5_dap *dap); + /** connect operation for SWD */ int (*connect)(struct adiv5_dap *dap); @@ -406,6 +496,9 @@ enum ap_type { AP_TYPE_AHB5H_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 8), /* AHB5 with enhanced HPROT Memory-AP */ }; +extern const struct dap_ops jtag_dp_ops; +extern const struct dap_ops swd_dap_ops; + /* Check the ap->cfg_reg Long Address field (bit 1) * * 0b0: The AP only supports physical addresses 32 bits or smaller @@ -420,6 +513,18 @@ static inline bool is_64bit_ap(struct adiv5_ap *ap) return (ap->cfg_reg & MEM_AP_REG_CFG_LA) != 0; } +/** + * Check if DAP is ADIv6 + * + * @param dap The DAP to test + * + * @return true for ADIv6, false for either ADIv5 or unknown version + */ +static inline bool is_adiv6(const struct adiv5_dap *dap) +{ + return dap->adi_version == 6; +} + /** * Send an adi-v5 sequence to the DAP. * @@ -486,6 +591,10 @@ static inline int dap_queue_ap_read(struct adiv5_ap *ap, unsigned reg, uint32_t *data) { assert(ap->dap->ops); + if (ap->refcount == 0) { + ap->refcount = 1; + LOG_ERROR("BUG: refcount AP#0x%" PRIx64 " used without get", ap->ap_num); + } return ap->dap->ops->queue_ap_read(ap, reg, data); } @@ -502,6 +611,10 @@ static inline int dap_queue_ap_write(struct adiv5_ap *ap, unsigned reg, uint32_t data) { assert(ap->dap->ops); + if (ap->refcount == 0) { + ap->refcount = 1; + LOG_ERROR("BUG: refcount AP#0x%" PRIx64 " used without get", ap->ap_num); + } return ap->dap->ops->queue_ap_write(ap, reg, data); } @@ -619,19 +732,25 @@ int mem_ap_init(struct adiv5_ap *ap); /* Invalidate cached DP select and cached TAR and CSW of all APs */ void dap_invalidate_cache(struct adiv5_dap *dap); -/* Probe the AP for ROM Table location */ -int dap_get_debugbase(struct adiv5_ap *ap, - target_addr_t *dbgbase, uint32_t *apid); +/* read ADIv6 baseptr register */ +int adiv6_dap_read_baseptr(struct command_invocation *cmd, struct adiv5_dap *dap, target_addr_t *baseptr); + +/* test if ap_num is valid, based on current knowledge of dap */ +bool is_ap_num_valid(struct adiv5_dap *dap, uint64_t ap_num); -/* Probe Access Ports to find a particular type */ -int dap_find_ap(struct adiv5_dap *dap, +/* Probe Access Ports to find a particular type. Increment AP refcount */ +int dap_find_get_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_ap **ap_out); -static inline struct adiv5_ap *dap_ap(struct adiv5_dap *dap, uint8_t ap_num) -{ - return &dap->ap[ap_num]; -} +/* Return AP with specified ap_num. Increment AP refcount */ +struct adiv5_ap *dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num); + +/* Return AP with specified ap_num. Increment AP refcount and keep it non-zero */ +struct adiv5_ap *dap_get_config_ap(struct adiv5_dap *dap, uint64_t ap_num); + +/* Decrement AP refcount and release the AP when refcount reaches zero */ +int dap_put_ap(struct adiv5_ap *ap); /** Check if SWD multidrop configuration is valid */ static inline bool dap_is_multidrop(struct adiv5_dap *dap) @@ -641,7 +760,7 @@ static inline bool dap_is_multidrop(struct adiv5_dap *dap) /* Lookup CoreSight component */ int dap_lookup_cs_component(struct adiv5_ap *ap, - target_addr_t dbgbase, uint8_t type, target_addr_t *addr, int32_t *idx); + uint8_t type, target_addr_t *addr, int32_t idx); struct target; @@ -664,7 +783,7 @@ extern const struct swd_driver *adiv5_dap_swd_driver(struct adiv5_dap *self); extern int dap_cleanup_all(void); struct adiv5_private_config { - int ap_num; + uint64_t ap_num; struct adiv5_dap *dap; }; @@ -673,7 +792,7 @@ extern int adiv5_jim_configure(struct target *target, struct jim_getopt_info *go struct adiv5_mem_ap_spot { struct adiv5_dap *dap; - int ap_num; + uint64_t ap_num; uint32_t base; }; diff --git a/src/target/arm_coresight.h b/src/target/arm_coresight.h index a08f4fb53b..58139dcdbe 100644 --- a/src/target/arm_coresight.h +++ b/src/target/arm_coresight.h @@ -44,13 +44,10 @@ #define ARM_CS_CIDR3 (0xFFC) #define ARM_CS_CIDR_CLASS_MASK (0x0000F000) -#define ARM_CS_CIDR_CLASS_SHIFT (12) +#define ARM_CS_CIDR_CLASS(cidr) (((cidr) >> 12) & 0x000F) #define ARM_CS_CLASS_0X1_ROM_TABLE (0x1) #define ARM_CS_CLASS_0X9_CS_COMPONENT (0x9) -#define ARM_CS_CIDR1_CLASS_MASK (0x000000F0) -#define ARM_CS_CIDR1_CLASS_SHIFT (4) - static inline bool is_valid_arm_cs_cidr(uint32_t cidr) { return (cidr & ~ARM_CS_CIDR_CLASS_MASK) == 0xB105000D; @@ -66,6 +63,10 @@ static inline bool is_valid_arm_cs_cidr(uint32_t cidr) #define ARM_CS_C9_DEVARCH_PRESENT BIT(20) #define ARM_CS_C9_DEVARCH_ARCHITECT_MASK (0xFFE00000) #define ARM_CS_C9_DEVARCH_ARCHITECT_SHIFT (21) +#define ARM_CS_C9_DEVARCH_REVISION(devarch) \ + (((devarch) & ARM_CS_C9_DEVARCH_REVISION_MASK) >> ARM_CS_C9_DEVARCH_REVISION_SHIFT) +#define ARM_CS_C9_DEVARCH_ARCHITECT(devarch) \ + (((devarch) & ARM_CS_C9_DEVARCH_ARCHITECT_MASK) >> ARM_CS_C9_DEVARCH_ARCHITECT_SHIFT) #define ARM_CS_C9_DEVID (0xFC8) diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index 96927bf945..7637ad0158 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2016 by Matthias Welwarsky * * * - * 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, write to the * - * Free Software Foundation, Inc., * - * * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -34,6 +22,7 @@ struct arm_cti { struct list_head lh; char *name; struct adiv5_mem_ap_spot spot; + struct adiv5_ap *ap; }; static LIST_HEAD(all_cti); @@ -65,7 +54,7 @@ struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) static int arm_cti_mod_reg_bits(struct arm_cti *self, unsigned int reg, uint32_t mask, uint32_t value) { - struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num); + struct adiv5_ap *ap = self->ap; uint32_t tmp; /* Read register */ @@ -84,15 +73,14 @@ static int arm_cti_mod_reg_bits(struct arm_cti *self, unsigned int reg, uint32_t int arm_cti_enable(struct arm_cti *self, bool enable) { - struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num); uint32_t val = enable ? 1 : 0; - return mem_ap_write_atomic_u32(ap, self->spot.base + CTI_CTR, val); + return mem_ap_write_atomic_u32(self->ap, self->spot.base + CTI_CTR, val); } int arm_cti_ack_events(struct arm_cti *self, uint32_t event) { - struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num); + struct adiv5_ap *ap = self->ap; int retval; uint32_t tmp; @@ -134,19 +122,15 @@ int arm_cti_ungate_channel(struct arm_cti *self, uint32_t channel) int arm_cti_write_reg(struct arm_cti *self, unsigned int reg, uint32_t value) { - struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num); - - return mem_ap_write_atomic_u32(ap, self->spot.base + reg, value); + return mem_ap_write_atomic_u32(self->ap, self->spot.base + reg, value); } int arm_cti_read_reg(struct arm_cti *self, unsigned int reg, uint32_t *p_value) { - struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num); - if (!p_value) return ERROR_COMMAND_ARGUMENT_INVALID; - return mem_ap_read_atomic_u32(ap, self->spot.base + reg, p_value); + return mem_ap_read_atomic_u32(self->ap, self->spot.base + reg, p_value); } int arm_cti_pulse_channel(struct arm_cti *self, uint32_t channel) @@ -228,6 +212,8 @@ int arm_cti_cleanup_all(void) struct arm_cti *obj, *tmp; list_for_each_entry_safe(obj, tmp, &all_cti, lh) { + if (obj->ap) + dap_put_ap(obj->ap); free(obj->name); free(obj); } @@ -238,7 +224,7 @@ int arm_cti_cleanup_all(void) COMMAND_HANDLER(handle_cti_dump) { struct arm_cti *cti = CMD_DATA; - struct adiv5_ap *ap = dap_ap(cti->spot.dap, cti->spot.ap_num); + struct adiv5_ap *ap = cti->ap; int retval = ERROR_OK; for (int i = 0; (retval == ERROR_OK) && (i < (int)ARRAY_SIZE(cti_names)); i++) @@ -518,6 +504,12 @@ static int cti_create(struct jim_getopt_info *goi) list_add_tail(&cti->lh, &all_cti); + cti->ap = dap_get_ap(cti->spot.dap, cti->spot.ap_num); + if (!cti->ap) { + Jim_SetResultString(goi->interp, "Cannot get AP", -1); + return JIM_ERR; + } + return JIM_OK; } @@ -533,20 +525,17 @@ static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return cti_create(&goi); } -static int jim_cti_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(cti_handle_names) { struct arm_cti *obj; - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); - return JIM_ERR; - } - Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); - list_for_each_entry(obj, &all_cti, lh) { - Jim_ListAppendElement(interp, Jim_GetResult(interp), - Jim_NewStringObj(interp, obj->name, -1)); - } - return JIM_OK; + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + list_for_each_entry(obj, &all_cti, lh) + command_print(CMD, "%s", obj->name); + + return ERROR_OK; } @@ -561,7 +550,7 @@ static const struct command_registration cti_subcommand_handlers[] = { { .name = "names", .mode = COMMAND_ANY, - .jim_handler = jim_cti_names, + .handler = cti_handle_names, .usage = "", .help = "Lists all registered CTI objects by name", }, diff --git a/src/target/arm_cti.h b/src/target/arm_cti.h index 7c4f7ebe39..cfcde65608 100644 --- a/src/target/arm_cti.h +++ b/src/target/arm_cti.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2016 by Matthias Welwarsky * * * - * 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, write to the * - * Free Software Foundation, Inc., * - * * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM_CTI_H diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c index 2dba45d0b8..9f4afae743 100644 --- a/src/target/arm_dap.c +++ b/src/target/arm_dap.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2016 by Matthias Welwarsky * * * - * 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, write to the * - * Free Software Foundation, Inc., * - * * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -32,8 +20,6 @@ static LIST_HEAD(all_dap); -extern const struct dap_ops swd_dap_ops; -extern const struct dap_ops jtag_dp_ops; extern struct adapter_driver *adapter_driver; /* DAP command support */ @@ -50,7 +36,7 @@ static void dap_instance_init(struct adiv5_dap *dap) /* Set up with safe defaults */ for (i = 0; i <= DP_APSEL_MAX; i++) { dap->ap[i].dap = dap; - dap->ap[i].ap_num = i; + dap->ap[i].ap_num = DP_APSEL_INVALID; /* memaccess_tck max is 255 */ dap->ap[i].memaccess_tck = 255; /* Number of bits for tar autoincrement, impl. dep. at least 10 */ @@ -58,6 +44,8 @@ static void dap_instance_init(struct adiv5_dap *dap) /* default CSW value */ dap->ap[i].csw_default = CSW_AHB_DEFAULT; dap->ap[i].cfg_reg = MEM_AP_REG_CFG_INVALID; /* mem_ap configuration reg (large physical addr, etc.) */ + dap->ap[i].refcount = 0; + dap->ap[i].config_ap_never_release = false; } INIT_LIST_HEAD(&dap->cmd_journal); INIT_LIST_HEAD(&dap->cmd_pool); @@ -103,6 +91,7 @@ static int dap_init_all(void) { struct arm_dap_object *obj; int retval; + bool pre_connect = true; LOG_DEBUG("Initializing all DAPs ..."); @@ -127,9 +116,42 @@ static int dap_init_all(void) } else dap->ops = &jtag_dp_ops; + if (dap->adi_version == 0) { + LOG_DEBUG("DAP %s configured by default to use ADIv5 protocol", jtag_tap_name(dap->tap)); + dap->adi_version = 5; + } else { + LOG_DEBUG("DAP %s configured to use %s protocol by user cfg file", jtag_tap_name(dap->tap), + is_adiv6(dap) ? "ADIv6" : "ADIv5"); + } + + if (pre_connect && dap->ops->pre_connect_init) { + retval = dap->ops->pre_connect_init(dap); + if (retval != ERROR_OK) + return retval; + + pre_connect = false; + } + retval = dap->ops->connect(dap); if (retval != ERROR_OK) return retval; + + /* see if address size of ROM Table is greater than 32-bits */ + if (is_adiv6(dap)) { + uint32_t dpidr1; + + retval = dap->ops->queue_dp_read(dap, DP_DPIDR1, &dpidr1); + if (retval != ERROR_OK) { + LOG_ERROR("DAP read of DPIDR1 failed..."); + return retval; + } + retval = dap_run(dap); + if (retval != ERROR_OK) { + LOG_ERROR("DAP read of DPIDR1 failed..."); + return retval; + } + dap->asize = dpidr1 & DP_DPIDR1_ASIZE_MASK; + } } return ERROR_OK; @@ -142,6 +164,10 @@ int dap_cleanup_all(void) list_for_each_entry_safe(obj, tmp, &all_dap, lh) { dap = &obj->dap; + for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) { + if (dap->ap[i].refcount != 0) + LOG_ERROR("BUG: refcount AP#%u still %u at exit", i, dap->ap[i].refcount); + } if (dap->ops && dap->ops->quit) dap->ops->quit(dap); @@ -157,6 +183,8 @@ enum dap_cfg_param { CFG_IGNORE_SYSPWRUPACK, CFG_DP_ID, CFG_INSTANCE_ID, + CFG_ADIV6, + CFG_ADIV5, }; static const struct jim_nvp nvp_config_opts[] = { @@ -164,6 +192,8 @@ static const struct jim_nvp nvp_config_opts[] = { { .name = "-ignore-syspwrupack", .value = CFG_IGNORE_SYSPWRUPACK }, { .name = "-dp-id", .value = CFG_DP_ID }, { .name = "-instance-id", .value = CFG_INSTANCE_ID }, + { .name = "-adiv6", .value = CFG_ADIV6 }, + { .name = "-adiv5", .value = CFG_ADIV5 }, { .name = NULL, .value = -1 } }; @@ -243,6 +273,12 @@ static int dap_configure(struct jim_getopt_info *goi, struct arm_dap_object *dap dap->dap.multidrop_instance_id_valid = true; break; } + case CFG_ADIV6: + dap->dap.adi_version = 6; + break; + case CFG_ADIV5: + dap->dap.adi_version = 5; + break; default: break; } @@ -392,20 +428,16 @@ static int jim_dap_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return dap_create(&goi); } -static int jim_dap_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_dap_names) { + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + struct arm_dap_object *obj; + list_for_each_entry(obj, &all_dap, lh) + command_print(CMD, "%s", obj->name); - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); - return JIM_ERR; - } - Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); - list_for_each_entry(obj, &all_dap, lh) { - Jim_ListAppendElement(interp, Jim_GetResult(interp), - Jim_NewStringObj(interp, obj->name, -1)); - } - return JIM_OK; + return ERROR_OK; } COMMAND_HANDLER(handle_dap_init) @@ -418,7 +450,7 @@ COMMAND_HANDLER(handle_dap_info_command) struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); struct adiv5_dap *dap = arm->dap; - uint32_t apsel; + uint64_t apsel; if (!dap) { LOG_ERROR("DAP instance not available. Probably a HLA target..."); @@ -430,15 +462,34 @@ COMMAND_HANDLER(handle_dap_info_command) apsel = dap->apsel; break; case 1: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); - if (apsel > DP_APSEL_MAX) + if (!strcmp(CMD_ARGV[0], "root")) { + if (!is_adiv6(dap)) { + command_print(CMD, "Option \"root\" not allowed with ADIv5 DAP"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + int retval = adiv6_dap_read_baseptr(CMD, dap, &apsel); + if (retval != ERROR_OK) { + command_print(CMD, "Failed reading DAP baseptr"); + return retval; + } + break; + } + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); + if (!is_ap_num_valid(dap, apsel)) return ERROR_COMMAND_SYNTAX_ERROR; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } - return dap_info_command(CMD, &dap->ap[apsel]); + struct adiv5_ap *ap = dap_get_ap(dap, apsel); + if (!ap) { + command_print(CMD, "Cannot get AP"); + return ERROR_FAIL; + } + int retval = dap_info_command(CMD, ap); + dap_put_ap(ap); + return retval; } static const struct command_registration dap_subcommand_handlers[] = { @@ -452,7 +503,7 @@ static const struct command_registration dap_subcommand_handlers[] = { { .name = "names", .mode = COMMAND_ANY, - .jim_handler = jim_dap_names, + .handler = handle_dap_names, .usage = "", .help = "Lists all registered DAP instances by name", }, @@ -467,9 +518,9 @@ static const struct command_registration dap_subcommand_handlers[] = { .name = "info", .handler = handle_dap_info_command, .mode = COMMAND_EXEC, - .help = "display ROM table for MEM-AP of current target " - "(default currently selected AP)", - .usage = "[ap_num]", + .help = "display ROM table for specified MEM-AP (default MEM-AP of current target) " + "or the ADIv6 root ROM table of current target's DAP", + .usage = "[ap_num | 'root']", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index d3d27a93c8..749274f369 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2009 by David Brownell * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/arm_disassembler.h b/src/target/arm_disassembler.h index 6f15f4b5e1..1be567475c 100644 --- a/src/target/arm_disassembler.h +++ b/src/target/arm_disassembler.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM_DISASSEMBLER_H diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index e60ef225da..9f3a444afc 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright (C) 2009 by David Brownell - * - * 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/>. */ #ifdef HAVE_CONFIG_H @@ -74,6 +63,29 @@ static int dpm_mrc(struct target *target, int cpnum, return retval; } +static int dpm_mrrc(struct target *target, int cpnum, + uint32_t op, uint32_t crm, uint64_t *value) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = arm->dpm; + int retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("MRRC p%d, %d, r0, r1, c%d", cpnum, + (int)op, (int)crm); + + /* read coprocessor register into R0, R1; return via DCC */ + retval = dpm->instr_read_data_r0_r1(dpm, + ARMV5_T_MRRC(cpnum, op, 0, 1, crm), + value); + + /* (void) */ dpm->finish(dpm); + return retval; +} + static int dpm_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) @@ -99,6 +111,29 @@ static int dpm_mcr(struct target *target, int cpnum, return retval; } +static int dpm_mcrr(struct target *target, int cpnum, + uint32_t op, uint32_t crm, uint64_t value) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = arm->dpm; + int retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("MCRR p%d, %d, r0, r1, c%d", cpnum, + (int)op, (int)crm); + + /* read DCC into r0, r1; then write coprocessor register from R0, R1 */ + retval = dpm->instr_write_data_r0_r1(dpm, + ARMV5_T_MCRR(cpnum, op, 0, 1, crm), value); + + /* (void) */ dpm->finish(dpm); + + return retval; +} + /*----------------------------------------------------------------------*/ /* @@ -929,7 +964,7 @@ static int dpm_watchpoint_setup(struct arm_dpm *dpm, unsigned index_t, uint32_t control; /* this hardware doesn't support data value matching or masking */ - if (wp->value || wp->mask != ~(uint32_t)0) { + if (wp->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) { LOG_DEBUG("watchpoint values and masking not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1061,7 +1096,7 @@ int arm_dpm_setup(struct arm_dpm *dpm) { struct arm *arm = dpm->arm; struct target *target = arm->target; - struct reg_cache *cache = 0; + struct reg_cache *cache = NULL; arm->dpm = dpm; @@ -1081,6 +1116,8 @@ int arm_dpm_setup(struct arm_dpm *dpm) /* coprocessor access setup */ arm->mrc = dpm_mrc; arm->mcr = dpm_mcr; + arm->mrrc = dpm_mrrc; + arm->mcrr = dpm_mcrr; /* breakpoint setup -- optional until it works everywhere */ if (!target->type->add_breakpoint) { diff --git a/src/target/arm_dpm.h b/src/target/arm_dpm.h index 0172d9a23d..2da4631112 100644 --- a/src/target/arm_dpm.h +++ b/src/target/arm_dpm.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Copyright (C) 2009 by David Brownell - * - * 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/>. */ #ifndef OPENOCD_TARGET_ARM_DPM_H @@ -83,6 +72,12 @@ struct arm_dpm { int (*instr_write_data_r0)(struct arm_dpm *dpm, uint32_t opcode, uint32_t data); + /** + * Runs two instructions, writing data to R0 and R1 before execution. + */ + int (*instr_write_data_r0_r1)(struct arm_dpm *dpm, + uint32_t opcode, uint64_t data); + /** Runs one instruction, writing data to R0 before execution. */ int (*instr_write_data_r0_64)(struct arm_dpm *dpm, uint32_t opcode, uint64_t data); @@ -103,6 +98,13 @@ struct arm_dpm { int (*instr_read_data_r0)(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data); + /** + * Runs two instructions, reading data from r0 and r1 after + * execution. + */ + int (*instr_read_data_r0_r1)(struct arm_dpm *dpm, + uint32_t opcode, uint64_t *data); + int (*instr_read_data_r0_64)(struct arm_dpm *dpm, uint32_t opcode, uint64_t *data); diff --git a/src/target/arm_jtag.c b/src/target/arm_jtag.c index 6a27e323f8..c1ec4735ac 100644 --- a/src/target/arm_jtag.c +++ b/src/target/arm_jtag.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/arm_jtag.h b/src/target/arm_jtag.h index f3e0bc2a3d..11b7c3efd7 100644 --- a/src/target/arm_jtag.h +++ b/src/target/arm_jtag.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM_JTAG_H diff --git a/src/target/arm_opcodes.h b/src/target/arm_opcodes.h index 00035f5818..c8ce51f299 100644 --- a/src/target/arm_opcodes.h +++ b/src/target/arm_opcodes.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Copyright (C) 2005 by Dominic Rath * Dominic.Rath@gmx.de @@ -10,19 +12,6 @@ * * Copyright (C) 2009 by Øyvind Harboe * oyvind.harboe@zylin.com - * - * 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/>. */ #ifndef OPENOCD_TARGET_ARM_OPCODES_H @@ -198,6 +187,17 @@ (0xee100010 | (crm) | ((op2) << 5) | ((cp) << 8) \ | ((rd) << 12) | ((crn) << 16) | ((op1) << 21)) +/* Move to two ARM registers from coprocessor + * cp: Coprocessor number + * op: Coprocessor opcode + * rt: destination register 1 + * rt2: destination register 2 + * crm: coprocessor source register + */ +#define ARMV5_T_MRRC(cp, op, rt, rt2, crm) \ + (0xec500000 | (crm) | ((op) << 4) | ((cp) << 8) \ + | ((rt) << 12) | ((rt2) << 16)) + /* Move to coprocessor from ARM register * cp: Coprocessor number * op1: Coprocessor opcode @@ -210,6 +210,17 @@ (0xee000010 | (crm) | ((op2) << 5) | ((cp) << 8) \ | ((rd) << 12) | ((crn) << 16) | ((op1) << 21)) +/* Move to coprocessor from two ARM registers + * cp: Coprocessor number + * op: Coprocessor opcode + * rt: destination register 1 + * rt2: destination register 2 + * crm: coprocessor source register + */ +#define ARMV5_T_MCRR(cp, op, rt, rt2, crm) \ + (0xec400000 | (crm) | ((op) << 4) | ((cp) << 8) \ + | ((rt) << 12) | ((rt2) << 16)) + /* Breakpoint instruction (ARMv5) * im: 16-bit immediate */ diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c index 507d1cd2c4..b557589407 100644 --- a/src/target/arm_semihosting.c +++ b/src/target/arm_semihosting.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 by Marvell Technology Group Ltd. * * Written by Nicolas Pitre <nico@marvell.com> * @@ -10,19 +12,6 @@ * * * Copyright (C) 2018 by Liviu Ionescu * * <ilg@livius.net> * - * * - * 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/>. * ***************************************************************************/ /** diff --git a/src/target/arm_semihosting.h b/src/target/arm_semihosting.h index cf1f8de142..0a912a7262 100644 --- a/src/target/arm_semihosting.h +++ b/src/target/arm_semihosting.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 by Marvell Technology Group Ltd. * * Written by Nicolas Pitre <nico@marvell.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM_SEMIHOSTING_H diff --git a/src/target/arm_simulator.c b/src/target/arm_simulator.c index 480d9bc128..058e3d38b8 100644 --- a/src/target/arm_simulator.c +++ b/src/target/arm_simulator.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Hongtao Zheng * * hontor@126.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/arm_simulator.h b/src/target/arm_simulator.h index 5bdbf562cc..e4a25d8657 100644 --- a/src/target/arm_simulator.h +++ b/src/target/arm_simulator.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM_SIMULATOR_H diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index fba3fec4f2..5cea682ec4 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later /** * @file @@ -90,6 +90,7 @@ struct arm_tpiu_swo_event_action { struct arm_tpiu_swo_object { struct list_head lh; struct adiv5_mem_ap_spot spot; + struct adiv5_ap *ap; char *name; struct arm_tpiu_swo_event_action *event_action; /* record enable before init */ @@ -233,6 +234,9 @@ int arm_tpiu_swo_cleanup_all(void) ea = next; } + if (obj->ap) + dap_put_ap(obj->ap); + free(obj->name); free(obj->out_filename); free(obj); @@ -591,77 +595,81 @@ static const struct service_driver arm_tpiu_swo_service_driver = { .keep_client_alive_handler = NULL, }; -static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_arm_tpiu_swo_enable) { - struct command *c = jim_to_command(interp); - struct arm_tpiu_swo_object *obj = c->jim_handler_data; - struct command_context *cmd_ctx = current_command_context(interp); - struct adiv5_ap *tpiu_ap = dap_ap(obj->spot.dap, obj->spot.ap_num); + struct arm_tpiu_swo_object *obj = CMD_DATA; uint32_t value; int retval; - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); - return JIM_ERR; - } + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; - if (cmd_ctx->mode == COMMAND_CONFIG) { + if (CMD_CTX->mode == COMMAND_CONFIG) { LOG_DEBUG("%s: enable deferred", obj->name); obj->deferred_enable = true; - return JIM_OK; + return ERROR_OK; } if (obj->enabled) - return JIM_OK; + return ERROR_OK; - if (transport_is_hla() && obj->spot.ap_num > 0) { - LOG_ERROR("Invalid access port %d. Only AP#0 allowed with hla transport", obj->spot.ap_num); - return JIM_ERR; + if (transport_is_hla() && obj->spot.ap_num != 0) { + command_print(CMD, + "Invalid access port 0x%" PRIx64 ". Only AP#0 allowed with hla transport", + obj->spot.ap_num); + return ERROR_FAIL; } if (!obj->traceclkin_freq) { - LOG_ERROR("Trace clock-in frequency not set"); - return JIM_ERR; + command_print(CMD, "Trace clock-in frequency not set"); + return ERROR_FAIL; } if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) if (!obj->swo_pin_freq) LOG_DEBUG("SWO pin frequency not set, will be autodetected by the adapter"); - struct target *target = get_current_target(cmd_ctx); + struct target *target = get_current_target(CMD_CTX); /* START_DEPRECATED_TPIU */ if (obj->recheck_ap_cur_target) { if (strcmp(target->type->name, "cortex_m") && strcmp(target->type->name, "hla_target")) { LOG_ERROR(MSG "Current target is not a Cortex-M nor a HLA"); - return JIM_ERR; + return ERROR_FAIL; } if (!target_was_examined(target)) { LOG_ERROR(MSG "Current target not examined yet"); - return JIM_ERR; + return ERROR_FAIL; } struct cortex_m_common *cm = target_to_cm(target); obj->recheck_ap_cur_target = false; obj->spot.ap_num = cm->armv7m.debug_ap->ap_num; - tpiu_ap = dap_ap(obj->spot.dap, obj->spot.ap_num); if (obj->spot.ap_num == 0) LOG_INFO(MSG "Confirmed TPIU %s is on AP 0", obj->name); else - LOG_INFO(MSG "Target %s is on AP %d. Revised command is " - "\'tpiu create %s -dap %s -ap-num %d\'", + LOG_INFO(MSG "Target %s is on AP#0x%" PRIx64 ". Revised command is " + "\'tpiu create %s -dap %s -ap-num 0x%" PRIx64 "\'", target_name(target), obj->spot.ap_num, obj->name, adiv5_dap_name(obj->spot.dap), obj->spot.ap_num); } /* END_DEPRECATED_TPIU */ + if (!obj->ap) { + obj->ap = dap_get_ap(obj->spot.dap, obj->spot.ap_num); + if (!obj->ap) { + command_print(CMD, "Cannot get AP"); + return ERROR_FAIL; + } + } + /* trigger the event before any attempt to R/W in the TPIU/SWO */ arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_ENABLE); - retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_DEVID_OFFSET, &value); + retval = wrap_read_u32(target, obj->ap, obj->spot.base + TPIU_DEVID_OFFSET, &value); if (retval != ERROR_OK) { - LOG_ERROR("Unable to read %s", obj->name); - return JIM_ERR; + command_print(CMD, "Unable to read %s", obj->name); + return retval; } switch (obj->pin_protocol) { case TPIU_SPPR_PROTOCOL_SYNC: @@ -677,21 +685,20 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const value = 0; } if (!value) { - struct jim_nvp *p; - jim_nvp_value2name(interp, nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol, &p); - LOG_ERROR("%s does not support protocol %s", obj->name, p->name); - return JIM_ERR; + struct jim_nvp *p = jim_nvp_value2name_simple(nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol); + command_print(CMD, "%s does not support protocol %s", obj->name, p->name); + return ERROR_FAIL; } if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_SYNC) { - retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_SSPSR_OFFSET, &value); + retval = wrap_read_u32(target, obj->ap, obj->spot.base + TPIU_SSPSR_OFFSET, &value); if (retval != ERROR_OK) { - LOG_ERROR("Cannot read TPIU register SSPSR"); - return JIM_ERR; + command_print(CMD, "Cannot read TPIU register SSPSR"); + return retval; } if (!(value & BIT(obj->port_width - 1))) { - LOG_ERROR("TPIU does not support port-width of %d bits", obj->port_width); - return JIM_ERR; + command_print(CMD, "TPIU does not support port-width of %d bits", obj->port_width); + return ERROR_FAIL; } } @@ -703,41 +710,42 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const struct arm_tpiu_swo_priv_connection *priv = malloc(sizeof(*priv)); if (!priv) { LOG_ERROR("Out of memory"); - return JIM_ERR; + return ERROR_FAIL; } priv->obj = obj; LOG_INFO("starting trace server for %s on %s", obj->name, &obj->out_filename[1]); retval = add_service(&arm_tpiu_swo_service_driver, &obj->out_filename[1], CONNECTION_LIMIT_UNLIMITED, priv); if (retval != ERROR_OK) { - LOG_ERROR("Can't configure trace TCP port %s", &obj->out_filename[1]); - return JIM_ERR; + command_print(CMD, "Can't configure trace TCP port %s", &obj->out_filename[1]); + return retval; } } else if (strcmp(obj->out_filename, "-")) { obj->file = fopen(obj->out_filename, "ab"); if (!obj->file) { - LOG_ERROR("Can't open trace destination file \"%s\"", obj->out_filename); - return JIM_ERR; + command_print(CMD, "Can't open trace destination file \"%s\"", obj->out_filename); + return ERROR_FAIL; } } retval = adapter_config_trace(true, obj->pin_protocol, obj->port_width, &swo_pin_freq, obj->traceclkin_freq, &prescaler); if (retval != ERROR_OK) { - LOG_ERROR("Failed to start adapter's trace"); + command_print(CMD, "Failed to start adapter's trace"); arm_tpiu_swo_close_output(obj); - return JIM_ERR; + return retval; } if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) if (!swo_pin_freq) { if (obj->swo_pin_freq) - LOG_ERROR("Adapter rejected SWO pin frequency %d Hz", obj->swo_pin_freq); + command_print(CMD, "Adapter rejected SWO pin frequency %d Hz", obj->swo_pin_freq); else - LOG_ERROR("Adapter does not support auto-detection of SWO pin frequency nor a default value"); + command_print(CMD, + "Adapter does not support auto-detection of SWO pin frequency nor a default value"); arm_tpiu_swo_close_output(obj); - return JIM_ERR; + return ERROR_FAIL; } if (obj->swo_pin_freq != swo_pin_freq) @@ -759,26 +767,26 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const obj->swo_pin_freq = swo_pin_freq; } - retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_CSPSR_OFFSET, BIT(obj->port_width - 1)); + retval = wrap_write_u32(target, obj->ap, obj->spot.base + TPIU_CSPSR_OFFSET, BIT(obj->port_width - 1)); if (retval != ERROR_OK) goto error_exit; - retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_ACPR_OFFSET, prescaler - 1); + retval = wrap_write_u32(target, obj->ap, obj->spot.base + TPIU_ACPR_OFFSET, prescaler - 1); if (retval != ERROR_OK) goto error_exit; - retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_SPPR_OFFSET, obj->pin_protocol); + retval = wrap_write_u32(target, obj->ap, obj->spot.base + TPIU_SPPR_OFFSET, obj->pin_protocol); if (retval != ERROR_OK) goto error_exit; - retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_FFCR_OFFSET, &value); + retval = wrap_read_u32(target, obj->ap, obj->spot.base + TPIU_FFCR_OFFSET, &value); if (retval != ERROR_OK) goto error_exit; if (obj->en_formatter) value |= BIT(1); else value &= ~BIT(1); - retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_FFCR_OFFSET, value); + retval = wrap_write_u32(target, obj->ap, obj->spot.base + TPIU_FFCR_OFFSET, value); if (retval != ERROR_OK) goto error_exit; @@ -789,10 +797,10 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const /* END_DEPRECATED_TPIU */ obj->enabled = true; - return JIM_OK; + return ERROR_OK; error_exit: - LOG_ERROR("Error!"); + command_print(CMD, "Error!"); if (obj->en_capture) { obj->en_capture = false; @@ -801,27 +809,22 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj); - retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL); - if (retval != ERROR_OK) { - LOG_ERROR("Failed to stop adapter's trace"); - return JIM_ERR; - } + int retval1 = adapter_config_trace(false, 0, 0, NULL, 0, NULL); + if (retval1 != ERROR_OK) + command_print(CMD, "Failed to stop adapter's trace"); } - return JIM_ERR; + return retval; } -static int jim_arm_tpiu_swo_disable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_arm_tpiu_swo_disable) { - struct command *c = jim_to_command(interp); - struct arm_tpiu_swo_object *obj = c->jim_handler_data; + struct arm_tpiu_swo_object *obj = CMD_DATA; - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); - return JIM_ERR; - } + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; if (!obj->enabled) - return JIM_OK; + return ERROR_OK; obj->enabled = false; arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_DISABLE); @@ -835,20 +838,19 @@ static int jim_arm_tpiu_swo_disable(Jim_Interp *interp, int argc, Jim_Obj *const int retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL); if (retval != ERROR_OK) { - LOG_ERROR("Failed to stop adapter's trace"); - return JIM_ERR; + command_print(CMD, "Failed to stop adapter's trace"); + return retval; } } arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_DISABLE); /* START_DEPRECATED_TPIU */ - struct command_context *cmd_ctx = current_command_context(interp); - struct target *target = get_current_target(cmd_ctx); + struct target *target = get_current_target(CMD_CTX); target_handle_event(target, TARGET_EVENT_TRACE_CONFIG); /* END_DEPRECATED_TPIU */ - return JIM_OK; + return ERROR_OK; } static const struct command_registration arm_tpiu_swo_instance_command_handlers[] = { @@ -876,14 +878,14 @@ static const struct command_registration arm_tpiu_swo_instance_command_handlers[ { .name = "enable", .mode = COMMAND_ANY, - .jim_handler = jim_arm_tpiu_swo_enable, + .handler = handle_arm_tpiu_swo_enable, .usage = "", .help = "Enables the TPIU/SWO output", }, { .name = "disable", .mode = COMMAND_EXEC, - .jim_handler = jim_arm_tpiu_swo_disable, + .handler = handle_arm_tpiu_swo_disable, .usage = "", .help = "Disables the TPIU/SWO output", }, @@ -979,39 +981,34 @@ static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const return JIM_ERR; } -static int jim_arm_tpiu_swo_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_arm_tpiu_swo_names) { struct arm_tpiu_swo_object *obj; - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); - return JIM_ERR; - } - Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); - list_for_each_entry(obj, &all_tpiu_swo, lh) { - Jim_ListAppendElement(interp, Jim_GetResult(interp), - Jim_NewStringObj(interp, obj->name, -1)); - } - return JIM_OK; + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + list_for_each_entry(obj, &all_tpiu_swo, lh) + command_print(CMD, "%s", obj->name); + + return ERROR_OK; } -static int jim_arm_tpiu_swo_init(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_arm_tpiu_swo_init) { - struct command_context *cmd_ctx = current_command_context(interp); struct arm_tpiu_swo_object *obj; - int retval = JIM_OK; + int retval = ERROR_OK; + + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); - return JIM_ERR; - } list_for_each_entry(obj, &all_tpiu_swo, lh) { if (!obj->deferred_enable) continue; LOG_DEBUG("%s: running enable during init", obj->name); - int retval2 = command_run_linef(cmd_ctx, "%s enable", obj->name); + int retval2 = command_run_linef(CMD_CTX, "%s enable", obj->name); if (retval2 != ERROR_OK) - retval = JIM_ERR; + retval = retval2; } return retval; } @@ -1037,7 +1034,7 @@ COMMAND_HANDLER(handle_tpiu_deprecated_config_command) struct cortex_m_common *cm = target_to_cm(target); struct adiv5_private_config *pc = target->private_config; struct adiv5_dap *dap = pc->dap; - int ap_num = pc->ap_num; + uint64_t ap_num = pc->ap_num; bool set_recheck_ap_cur_target = false; LOG_INFO(MSG "Adding a TPIU \'%s.tpiu\' in the configuration", target_name(target)); @@ -1055,10 +1052,10 @@ COMMAND_HANDLER(handle_tpiu_deprecated_config_command) set_recheck_ap_cur_target = true; } - LOG_INFO(MSG "Running: \'tpiu create %s.tpiu -dap %s -ap-num %d\'", + LOG_INFO(MSG "Running: \'tpiu create %s.tpiu -dap %s -ap-num 0x%" PRIx64 "\'", target_name(target), adiv5_dap_name(dap), ap_num); - retval = command_run_linef(CMD_CTX, "tpiu create %s.tpiu -dap %s -ap-num %d", + retval = command_run_linef(CMD_CTX, "tpiu create %s.tpiu -dap %s -ap-num 0x%" PRIx64, target_name(target), adiv5_dap_name(dap), ap_num); if (retval != ERROR_OK) return retval; @@ -1183,14 +1180,14 @@ static const struct command_registration arm_tpiu_swo_subcommand_handlers[] = { { .name = "names", .mode = COMMAND_ANY, - .jim_handler = jim_arm_tpiu_swo_names, + .handler = handle_arm_tpiu_swo_names, .usage = "", .help = "Lists all registered TPIU and SWO objects by name", }, { .name = "init", .mode = COMMAND_EXEC, - .jim_handler = jim_arm_tpiu_swo_init, + .handler = handle_arm_tpiu_swo_init, .usage = "", .help = "Initialize TPIU and SWO", }, diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index b861cf5dbd..1886d5e1f6 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -10,19 +12,6 @@ * * * Copyright (C) 2018 by Liviu Ionescu * * <ilg@livius.net> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -546,7 +535,7 @@ static struct reg_feature arm_gdb_dummy_fp_features = { * Modern ARM cores use Vector Floating Point (VFP), if they * have any floating point support. VFP is not FPA-compatible. */ -struct reg arm_gdb_dummy_fp_reg = { +static struct reg arm_gdb_dummy_fp_reg = { .name = "GDB dummy FPA register", .value = (uint8_t *) arm_gdb_dummy_fp_value, .valid = true, @@ -563,7 +552,7 @@ static const uint8_t arm_gdb_dummy_fps_value[4]; * Dummy FPA status registers are required to support GDB on ARM. * Register packets require an obsolete FPA status register. */ -struct reg arm_gdb_dummy_fps_reg = { +static struct reg arm_gdb_dummy_fps_reg = { .name = "GDB dummy FPA status register", .value = (uint8_t *) arm_gdb_dummy_fps_value, .valid = true, @@ -589,7 +578,7 @@ static int armv4_5_get_core_reg(struct reg *reg) struct target *target = reg_arch_info->target; if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -611,7 +600,7 @@ static int armv4_5_set_core_reg(struct reg *reg, uint8_t *buf) uint32_t value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -828,8 +817,8 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) } if (target->state != TARGET_HALTED) { - command_print(CMD, "error: target must be halted for register accesses"); - return ERROR_FAIL; + command_print(CMD, "Error: target must be halted for register accesses"); + return ERROR_TARGET_NOT_HALTED; } if (arm->core_type != ARM_CORE_TYPE_STD) { @@ -844,7 +833,7 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) } if (!arm->full_context) { - command_print(CMD, "error: target doesn't support %s", + command_print(CMD, "Error: target doesn't support %s", CMD_NAME); return ERROR_FAIL; } @@ -916,32 +905,33 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) return ERROR_OK; } -COMMAND_HANDLER(handle_armv4_5_core_state_command) +COMMAND_HANDLER(handle_arm_core_state_command) { struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); + int ret = ERROR_OK; if (!is_arm(arm)) { command_print(CMD, "current target isn't an ARM"); return ERROR_FAIL; } - if (arm->core_type == ARM_CORE_TYPE_M_PROFILE) { - /* armv7m not supported */ - command_print(CMD, "Unsupported Command"); - return ERROR_OK; - } - if (CMD_ARGC > 0) { - if (strcmp(CMD_ARGV[0], "arm") == 0) - arm->core_state = ARM_STATE_ARM; + if (strcmp(CMD_ARGV[0], "arm") == 0) { + if (arm->core_type == ARM_CORE_TYPE_M_PROFILE) { + command_print(CMD, "arm mode not supported on Cortex-M"); + ret = ERROR_FAIL; + } else { + arm->core_state = ARM_STATE_ARM; + } + } if (strcmp(CMD_ARGV[0], "thumb") == 0) arm->core_state = ARM_STATE_THUMB; } command_print(CMD, "core state: %s", arm_state_strings[arm->core_state]); - return ERROR_OK; + return ret; } COMMAND_HANDLER(handle_arm_disassemble_command) @@ -999,35 +989,38 @@ COMMAND_HANDLER(handle_arm_disassemble_command) #endif } -static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(handle_armv4_5_mcrmrc) { - struct command_context *context; - struct target *target; - struct arm *arm; - int retval; + bool is_mcr = false; + unsigned int arg_cnt = 5; + + if (!strcmp(CMD_NAME, "mcr")) { + is_mcr = true; + arg_cnt = 6; + } - context = current_command_context(interp); - assert(context); + if (arg_cnt != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; - target = get_current_target(context); + struct target *target = get_current_target(CMD_CTX); if (!target) { - LOG_ERROR("%s: no current target", __func__); - return JIM_ERR; + command_print(CMD, "no current target"); + return ERROR_FAIL; } if (!target_was_examined(target)) { - LOG_ERROR("%s: not yet examined", target_name(target)); - return JIM_ERR; + command_print(CMD, "%s: not yet examined", target_name(target)); + return ERROR_TARGET_NOT_EXAMINED; } - arm = target_to_arm(target); + + struct arm *arm = target_to_arm(target); if (!is_arm(arm)) { - LOG_ERROR("%s: not an ARM", target_name(target)); - return JIM_ERR; + command_print(CMD, "%s: not an ARM", target_name(target)); + return ERROR_FAIL; } - if ((argc < 6) || (argc > 7)) { - /* FIXME use the command name to verify # params... */ - LOG_ERROR("%s: wrong number of arguments", __func__); - return JIM_ERR; + if (target->state != TARGET_HALTED) { + command_print(CMD, "Error: [%s] not halted", target_name(target)); + return ERROR_TARGET_NOT_HALTED; } int cpnum; @@ -1036,98 +1029,157 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) uint32_t crn; uint32_t crm; uint32_t value; - long l; /* NOTE: parameter sequence matches ARM instruction set usage: * MCR pNUM, op1, rX, CRn, CRm, op2 ; write CP from rX * MRC pNUM, op1, rX, CRn, CRm, op2 ; read CP into rX * The "rX" is necessarily omitted; it uses Tcl mechanisms. */ - retval = Jim_GetLong(interp, argv[1], &l); - if (retval != JIM_OK) - return retval; - if (l & ~0xf) { - LOG_ERROR("%s: %s %d out of range", __func__, - "coprocessor", (int) l); - return JIM_ERR; + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cpnum); + if (cpnum & ~0xf) { + command_print(CMD, "coprocessor %d out of range", cpnum); + return ERROR_COMMAND_ARGUMENT_INVALID; } - cpnum = l; - retval = Jim_GetLong(interp, argv[2], &l); - if (retval != JIM_OK) - return retval; - if (l & ~0x7) { - LOG_ERROR("%s: %s %d out of range", __func__, - "op1", (int) l); - return JIM_ERR; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], op1); + if (op1 & ~0x7) { + command_print(CMD, "op1 %d out of range", op1); + return ERROR_COMMAND_ARGUMENT_INVALID; } - op1 = l; - retval = Jim_GetLong(interp, argv[3], &l); - if (retval != JIM_OK) - return retval; - if (l & ~0xf) { - LOG_ERROR("%s: %s %d out of range", __func__, - "CRn", (int) l); - return JIM_ERR; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], crn); + if (crn & ~0xf) { + command_print(CMD, "CRn %d out of range", crn); + return ERROR_COMMAND_ARGUMENT_INVALID; } - crn = l; - retval = Jim_GetLong(interp, argv[4], &l); - if (retval != JIM_OK) - return retval; - if (l & ~0xf) { - LOG_ERROR("%s: %s %d out of range", __func__, - "CRm", (int) l); - return JIM_ERR; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], crm); + if (crm & ~0xf) { + command_print(CMD, "CRm %d out of range", crm); + return ERROR_COMMAND_ARGUMENT_INVALID; } - crm = l; - retval = Jim_GetLong(interp, argv[5], &l); - if (retval != JIM_OK) - return retval; - if (l & ~0x7) { - LOG_ERROR("%s: %s %d out of range", __func__, - "op2", (int) l); - return JIM_ERR; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], op2); + if (op2 & ~0x7) { + command_print(CMD, "op2 %d out of range", op2); + return ERROR_COMMAND_ARGUMENT_INVALID; } - op2 = l; - - value = 0; - /* FIXME don't assume "mrc" vs "mcr" from the number of params; - * that could easily be a typo! Check both... - * + /* * FIXME change the call syntax here ... simplest to just pass * the MRC() or MCR() instruction to be executed. That will also * let us support the "mrc2" and "mcr2" opcodes (toggling one bit) * if that's ever needed. */ - if (argc == 7) { - retval = Jim_GetLong(interp, argv[6], &l); - if (retval != JIM_OK) - return retval; - value = l; + if (is_mcr) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[5], value); /* NOTE: parameters reordered! */ /* ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2) */ - retval = arm->mcr(target, cpnum, op1, op2, crn, crm, value); + int retval = arm->mcr(target, cpnum, op1, op2, crn, crm, value); if (retval != ERROR_OK) - return JIM_ERR; + return retval; } else { + value = 0; /* NOTE: parameters reordered! */ /* ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2) */ - retval = arm->mrc(target, cpnum, op1, op2, crn, crm, &value); + int retval = arm->mrc(target, cpnum, op1, op2, crn, crm, &value); if (retval != ERROR_OK) - return JIM_ERR; + return retval; - Jim_SetResult(interp, Jim_NewIntObj(interp, value)); + command_print(CMD, "0x%" PRIx32, value); } - return JIM_OK; + return ERROR_OK; } -extern const struct command_registration semihosting_common_handlers[]; +COMMAND_HANDLER(handle_armv4_5_mcrrmrrc) +{ + bool is_mcrr = false; + unsigned int arg_cnt = 3; + + if (!strcmp(CMD_NAME, "mcrr")) { + is_mcrr = true; + arg_cnt = 4; + } + + if (arg_cnt != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + if (!target) { + command_print(CMD, "no current target"); + return ERROR_FAIL; + } + if (!target_was_examined(target)) { + command_print(CMD, "%s: not yet examined", target_name(target)); + return ERROR_TARGET_NOT_EXAMINED; + } + + struct arm *arm = target_to_arm(target); + if (!is_arm(arm)) { + command_print(CMD, "%s: not an ARM", target_name(target)); + return ERROR_FAIL; + } + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + int cpnum; + uint32_t op1; + uint32_t crm; + uint64_t value; + + /* NOTE: parameter sequence matches ARM instruction set usage: + * MCRR pNUM, op1, rX1, rX2, CRm ; write CP from rX1 and rX2 + * MREC pNUM, op1, rX1, rX2, CRm ; read CP into rX1 and rX2 + * The "rXn" are necessarily omitted; they use Tcl mechanisms. + */ + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cpnum); + if (cpnum & ~0xf) { + command_print(CMD, "coprocessor %d out of range", cpnum); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], op1); + if (op1 & ~0xf) { + command_print(CMD, "op1 %d out of range", op1); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], crm); + if (crm & ~0xf) { + command_print(CMD, "CRm %d out of range", crm); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + /* + * FIXME change the call syntax here ... simplest to just pass + * the MRC() or MCR() instruction to be executed. That will also + * let us support the "mrrc2" and "mcrr2" opcodes (toggling one bit) + * if that's ever needed. + */ + if (is_mcrr) { + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[3], value); + + /* NOTE: parameters reordered! */ + /* ARMV5_T_MCRR(cpnum, op1, crm) */ + int retval = arm->mcrr(target, cpnum, op1, crm, value); + if (retval != ERROR_OK) + return retval; + } else { + value = 0; + /* NOTE: parameters reordered! */ + /* ARMV5_T_MRRC(cpnum, op1, crm) */ + int retval = arm->mrrc(target, cpnum, op1, crm, &value); + if (retval != ERROR_OK) + return retval; + + command_print(CMD, "0x%" PRIx64, value); + } + + return ERROR_OK; +} static const struct command_registration arm_exec_command_handlers[] = { { @@ -1137,9 +1189,44 @@ static const struct command_registration arm_exec_command_handlers[] = { .help = "display ARM core registers", .usage = "", }, + { + .name = "mcr", + .mode = COMMAND_EXEC, + .handler = handle_armv4_5_mcrmrc, + .help = "write coprocessor register", + .usage = "cpnum op1 CRn CRm op2 value", + }, + { + .name = "mrc", + .mode = COMMAND_EXEC, + .handler = handle_armv4_5_mcrmrc, + .help = "read coprocessor register", + .usage = "cpnum op1 CRn CRm op2", + }, + { + .name = "mcrr", + .mode = COMMAND_EXEC, + .handler = handle_armv4_5_mcrrmrrc, + .help = "write coprocessor 64-bit register", + .usage = "cpnum op1 CRm value", + }, + { + .name = "mrrc", + .mode = COMMAND_EXEC, + .handler = handle_armv4_5_mcrrmrrc, + .help = "read coprocessor 64-bit register", + .usage = "cpnum op1 CRm", + }, + { + .chain = arm_all_profiles_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration arm_all_profiles_command_handlers[] = { { .name = "core_state", - .handler = handle_armv4_5_core_state_command, + .handler = handle_arm_core_state_command, .mode = COMMAND_EXEC, .usage = "['arm'|'thumb']", .help = "display/change ARM core state", @@ -1151,25 +1238,12 @@ static const struct command_registration arm_exec_command_handlers[] = { .usage = "address [count ['thumb']]", .help = "disassemble instructions", }, - { - .name = "mcr", - .mode = COMMAND_EXEC, - .jim_handler = &jim_mcrmrc, - .help = "write coprocessor register", - .usage = "cpnum op1 CRn CRm op2 value", - }, - { - .name = "mrc", - .mode = COMMAND_EXEC, - .jim_handler = &jim_mcrmrc, - .help = "read coprocessor register", - .usage = "cpnum op1 CRn CRm op2", - }, { .chain = semihosting_common_handlers, }, COMMAND_REGISTRATION_DONE }; + const struct command_registration arm_command_handlers[] = { { .name = "arm", @@ -1190,7 +1264,7 @@ const struct command_registration arm_command_handlers[] = { * same way as a gdb for arm. This can be changed later on. User can still * set the specific architecture variant with the gdb command. */ -const char *arm_get_gdb_arch(struct target *target) +const char *arm_get_gdb_arch(const struct target *target) { return "arm"; } @@ -1282,7 +1356,7 @@ int arm_get_gdb_reg_list(struct target *target, /* wait for execution to complete and check exit point */ static int armv4_5_run_algorithm_completion(struct target *target, uint32_t exit_point, - int timeout_ms, + unsigned int timeout_ms, void *arch_info) { int retval; @@ -1316,9 +1390,9 @@ int armv4_5_run_algorithm_inner(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, - int timeout_ms, void *arch_info, + unsigned int timeout_ms, void *arch_info, int (*run_it)(struct target *target, uint32_t exit_point, - int timeout_ms, void *arch_info)) + unsigned int timeout_ms, void *arch_info)) { struct arm *arm = target_to_arm(target); struct arm_algorithm *arm_algorithm_info = arch_info; @@ -1337,7 +1411,7 @@ int armv4_5_run_algorithm_inner(struct target *target, } if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted (run target algo)"); return ERROR_TARGET_NOT_HALTED; } @@ -1504,7 +1578,7 @@ int armv4_5_run_algorithm(struct target *target, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, - int timeout_ms, + unsigned int timeout_ms, void *arch_info) { return armv4_5_run_algorithm_inner(target, @@ -1565,7 +1639,7 @@ int arm_checksum_memory(struct target *target, buf_set_u32(reg_params[1].value, 0, 32, count); /* 20 second timeout/megabyte */ - int timeout = 20000 * (1 + (count / (1024 * 1024))); + unsigned int timeout = 20000 * (1 + (count / (1024 * 1024))); /* armv4 must exit using a hardware breakpoint */ if (arm->arch == ARM_ARCH_V4) @@ -1697,6 +1771,14 @@ static int arm_default_mrc(struct target *target, int cpnum, return ERROR_FAIL; } +static int arm_default_mrrc(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t *value) +{ + LOG_ERROR("%s doesn't implement MRRC", target_type_name(target)); + return ERROR_FAIL; +} + static int arm_default_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, @@ -1706,6 +1788,14 @@ static int arm_default_mcr(struct target *target, int cpnum, return ERROR_FAIL; } +static int arm_default_mcrr(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t value) +{ + LOG_ERROR("%s doesn't implement MCRR", target_type_name(target)); + return ERROR_FAIL; +} + int arm_init_arch_info(struct target *target, struct arm *arm) { target->arch_info = arm; @@ -1725,8 +1815,12 @@ int arm_init_arch_info(struct target *target, struct arm *arm) if (!arm->mrc) arm->mrc = arm_default_mrc; + if (!arm->mrrc) + arm->mrrc = arm_default_mrrc; if (!arm->mcr) arm->mcr = arm_default_mcr; + if (!arm->mcrr) + arm->mcrr = arm_default_mcrr; return ERROR_OK; } diff --git a/src/target/armv4_5.h b/src/target/armv4_5.h index bef1cfe32a..250fa82fc5 100644 --- a/src/target/armv4_5.h +++ b/src/target/armv4_5.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2009 by Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV4_5_H diff --git a/src/target/armv4_5_cache.c b/src/target/armv4_5_cache.c index eda8cb7c6a..e12c43d336 100644 --- a/src/target/armv4_5_cache.c +++ b/src/target/armv4_5_cache.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/armv4_5_cache.h b/src/target/armv4_5_cache.h index 985a3a770d..3659941e52 100644 --- a/src/target/armv4_5_cache.h +++ b/src/target/armv4_5_cache.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV4_5_CACHE_H diff --git a/src/target/armv4_5_mmu.c b/src/target/armv4_5_mmu.c index 115a489503..0c09cb4ca7 100644 --- a/src/target/armv4_5_mmu.c +++ b/src/target/armv4_5_mmu.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -118,8 +107,10 @@ int armv4_5_mmu_read_physical(struct target *target, { int retval; - if (target->state != TARGET_HALTED) + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; + } /* disable MMU and data (or unified) cache */ retval = armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0); @@ -146,8 +137,10 @@ int armv4_5_mmu_write_physical(struct target *target, { int retval; - if (target->state != TARGET_HALTED) + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; + } /* disable MMU and data (or unified) cache */ retval = armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0); diff --git a/src/target/armv4_5_mmu.h b/src/target/armv4_5_mmu.h index 7beaf4ee96..774f1056eb 100644 --- a/src/target/armv4_5_mmu.h +++ b/src/target/armv4_5_mmu.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV4_5_MMU_H diff --git a/src/target/armv7a.c b/src/target/armv7a.c index d564f19ae7..82f4be5a0b 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 by David Brownell * * * * Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -112,7 +101,7 @@ static int armv7a_read_midr(struct target *target) armv7a->arch = (midr >> 16) & 0xf; armv7a->variant = (midr >> 20) & 0xf; armv7a->implementor = (midr >> 24) & 0xff; - LOG_INFO("%s rev %" PRIx32 ", partnum %" PRIx32 ", arch %" PRIx32 + LOG_DEBUG("%s rev %" PRIx32 ", partnum %" PRIx32 ", arch %" PRIx32 ", variant %" PRIx32 ", implementor %" PRIx32, target->cmd_name, armv7a->rev, diff --git a/src/target/armv7a.h b/src/target/armv7a.h index c282554a5e..6b9c2a68f4 100644 --- a/src/target/armv7a.h +++ b/src/target/armv7a.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 by David Brownell * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV7A_H @@ -30,7 +19,7 @@ enum { ARM_CPSR = 16 }; -#define ARMV7_COMMON_MAGIC 0x0A450999 +#define ARMV7_COMMON_MAGIC 0x0A450999U /* VA to PA translation operations opc2 values*/ #define V2PCWPR 0 @@ -98,8 +87,9 @@ struct armv7a_mmu_common { }; struct armv7a_common { + unsigned int common_magic; + struct arm arm; - int common_magic; struct reg_cache *core_cache; /* Core Debug Unit */ diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c index ba6f076f0f..e1f0dfafb0 100644 --- a/src/target/armv7a_cache.c +++ b/src/target/armv7a_cache.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2015 by Oleksij Rempel * * linux@rempel-privat.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -33,7 +22,7 @@ static int armv7a_l1_d_cache_sanity_check(struct target *target) struct armv7a_common *armv7a = target_to_armv7a(target); if (target->state != TARGET_HALTED) { - LOG_ERROR("%s: target not halted", __func__); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -51,7 +40,7 @@ static int armv7a_l1_i_cache_sanity_check(struct target *target) struct armv7a_common *armv7a = target_to_armv7a(target); if (target->state != TARGET_HALTED) { - LOG_ERROR("%s: target not halted", __func__); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/armv7a_cache.h b/src/target/armv7a_cache.h index 8d8ca2d7da..17ec5e6de1 100644 --- a/src/target/armv7a_cache.h +++ b/src/target/armv7a_cache.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2015 Oleksij Rempel * * linux@rempel-privat.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM7A_CACHE_H diff --git a/src/target/armv7a_cache_l2x.c b/src/target/armv7a_cache_l2x.c index c26d051734..39c503f096 100644 --- a/src/target/armv7a_cache_l2x.c +++ b/src/target/armv7a_cache_l2x.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2015 by Oleksij Rempel * * linux@rempel-privat.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/armv7a_cache_l2x.h b/src/target/armv7a_cache_l2x.h index f98b554465..d5f1a6f0e5 100644 --- a/src/target/armv7a_cache_l2x.h +++ b/src/target/armv7a_cache_l2x.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2015 Oleksij Rempel * * linux@rempel-privat.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARM7A_CACHE_L2X_H diff --git a/src/target/armv7a_mmu.c b/src/target/armv7a_mmu.c index 98a0065083..c4d294eae3 100644 --- a/src/target/armv7a_mmu.c +++ b/src/target/armv7a_mmu.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2016 by Matthias Welwarsky * * matthias.welwarsky@sysgo.com * * * * Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/armv7a_mmu.h b/src/target/armv7a_mmu.h index 36cd9d19ef..d93d3c6aaf 100644 --- a/src/target/armv7a_mmu.h +++ b/src/target/armv7a_mmu.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2016 by Matthias Welwarsky * * matthias.welwarsky@sysgo.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV7A_MMU_H diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 0a51ad4d60..d508af7bf0 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -17,19 +19,6 @@ * Copyright (C) 2019 by Tomas Vanek * * vanekt@fbl.cz * * * - * 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/>. * - * * * ARMv7-M Architecture, Application Level Reference Manual * * ARM DDI 0405C (September 2008) * * * @@ -64,7 +53,7 @@ const int armv7m_psp_reg_map[ARMV7M_NUM_CORE_REGS] = { ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7, ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11, ARMV7M_R12, ARMV7M_PSP, ARMV7M_R14, ARMV7M_PC, - ARMV7M_xPSR, + ARMV7M_XPSR, }; /* MSP is used in handler and some thread modes */ @@ -73,7 +62,7 @@ const int armv7m_msp_reg_map[ARMV7M_NUM_CORE_REGS] = { ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7, ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11, ARMV7M_R12, ARMV7M_MSP, ARMV7M_R14, ARMV7M_PC, - ARMV7M_xPSR, + ARMV7M_XPSR, }; /* @@ -108,7 +97,7 @@ static const struct { { ARMV7M_R13, "sp", 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_R14, "lr", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_PC, "pc", 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_xPSR, "xPSR", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, + { ARMV7M_XPSR, "xpsr", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, { ARMV7M_MSP, "msp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system" }, { ARMV7M_PSP, "psp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system" }, @@ -127,27 +116,27 @@ static const struct { { ARMV7M_FAULTMASK, "faultmask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, { ARMV7M_CONTROL, "control", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, - /* ARMv8-M specific registers */ - { ARMV8M_MSP_NS, "msp_ns", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" }, - { ARMV8M_PSP_NS, "psp_ns", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" }, - { ARMV8M_MSP_S, "msp_s", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" }, - { ARMV8M_PSP_S, "psp_s", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" }, - { ARMV8M_MSPLIM_S, "msplim_s", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" }, - { ARMV8M_PSPLIM_S, "psplim_s", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" }, - { ARMV8M_MSPLIM_NS, "msplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" }, - { ARMV8M_PSPLIM_NS, "psplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" }, + /* ARMv8-M security extension (TrustZone) specific registers */ + { ARMV8M_MSP_NS, "msp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, + { ARMV8M_PSP_NS, "psp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, + { ARMV8M_MSP_S, "msp_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, + { ARMV8M_PSP_S, "psp_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, + { ARMV8M_MSPLIM_S, "msplim_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, + { ARMV8M_PSPLIM_S, "psplim_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, + { ARMV8M_MSPLIM_NS, "msplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, + { ARMV8M_PSPLIM_NS, "psplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, { ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S, "pmsk_bpri_fltmsk_ctrl_s", 32, REG_TYPE_INT, NULL, NULL }, - { ARMV8M_PRIMASK_S, "primask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, - { ARMV8M_BASEPRI_S, "basepri_s", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, - { ARMV8M_FAULTMASK_S, "faultmask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, - { ARMV8M_CONTROL_S, "control_s", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, + { ARMV8M_PRIMASK_S, "primask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, + { ARMV8M_BASEPRI_S, "basepri_s", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, + { ARMV8M_FAULTMASK_S, "faultmask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, + { ARMV8M_CONTROL_S, "control_s", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, { ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS, "pmsk_bpri_fltmsk_ctrl_ns", 32, REG_TYPE_INT, NULL, NULL }, - { ARMV8M_PRIMASK_NS, "primask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, - { ARMV8M_BASEPRI_NS, "basepri_ns", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, - { ARMV8M_FAULTMASK_NS, "faultmask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, - { ARMV8M_CONTROL_NS, "control_ns", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, + { ARMV8M_PRIMASK_NS, "primask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, + { ARMV8M_BASEPRI_NS, "basepri_ns", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, + { ARMV8M_FAULTMASK_NS, "faultmask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, + { ARMV8M_CONTROL_NS, "control_ns", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, /* FPU registers */ { ARMV7M_D0, "d0", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, @@ -193,8 +182,11 @@ int armv7m_restore_context(struct target *target) for (i = cache->num_regs - 1; i >= 0; i--) { struct reg *r = &cache->reg_list[i]; - if (r->exist && r->dirty) - armv7m->arm.write_core_reg(target, r, i, ARM_MODE_ANY, r->value); + if (r->exist && r->dirty) { + int retval = armv7m->arm.write_core_reg(target, r, i, ARM_MODE_ANY, r->value); + if (retval != ERROR_OK) + return retval; + } } return ERROR_OK; @@ -256,7 +248,7 @@ uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id) switch (arm_reg_id) { case ARMV7M_R0 ... ARMV7M_R14: case ARMV7M_PC: - case ARMV7M_xPSR: + case ARMV7M_XPSR: case ARMV7M_MSP: case ARMV7M_PSP: /* NOTE: we "know" here that the register identifiers @@ -492,7 +484,7 @@ int armv7m_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, - int timeout_ms, void *arch_info) + unsigned int timeout_ms, void *arch_info) { int retval; @@ -533,17 +525,23 @@ int armv7m_start_algorithm(struct target *target, } if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted (start target algo)"); return ERROR_TARGET_NOT_HALTED; } /* Store all non-debug execution registers to armv7m_algorithm_info context */ for (unsigned i = 0; i < armv7m->arm.core_cache->num_regs; i++) { + struct reg *reg = &armv7m->arm.core_cache->reg_list[i]; + if (!reg->exist) + continue; + + if (!reg->valid) + armv7m_get_core_reg(reg); - armv7m_algorithm_info->context[i] = buf_get_u32( - armv7m->arm.core_cache->reg_list[i].value, - 0, - 32); + if (!reg->valid) + LOG_TARGET_WARNING(target, "Storing invalid register %s", reg->name); + + armv7m_algorithm_info->context[i] = buf_get_u32(reg->value, 0, 32); } for (int i = 0; i < num_mem_params; i++) { @@ -590,7 +588,7 @@ int armv7m_start_algorithm(struct target *target, * Because xPSR.T is populated on reset from the vector table, * it might be 0 if the vector table has "bad" data in it. */ - struct reg *reg = &armv7m->arm.core_cache->reg_list[ARMV7M_xPSR]; + struct reg *reg = &armv7m->arm.core_cache->reg_list[ARMV7M_XPSR]; buf_set_u32(reg->value, 0, 32, 0x01000000); reg->valid = true; reg->dirty = true; @@ -624,7 +622,7 @@ int armv7m_start_algorithm(struct target *target, int armv7m_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - target_addr_t exit_point, int timeout_ms, + target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { struct armv7m_common *armv7m = target_to_armv7m(target); @@ -696,16 +694,19 @@ int armv7m_wait_algorithm(struct target *target, } for (int i = armv7m->arm.core_cache->num_regs - 1; i >= 0; i--) { + struct reg *reg = &armv7m->arm.core_cache->reg_list[i]; + if (!reg->exist) + continue; + uint32_t regvalue; - regvalue = buf_get_u32(armv7m->arm.core_cache->reg_list[i].value, 0, 32); + regvalue = buf_get_u32(reg->value, 0, 32); if (regvalue != armv7m_algorithm_info->context[i]) { LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32, - armv7m->arm.core_cache->reg_list[i].name, - armv7m_algorithm_info->context[i]); - buf_set_u32(armv7m->arm.core_cache->reg_list[i].value, + reg->name, armv7m_algorithm_info->context[i]); + buf_set_u32(reg->value, 0, 32, armv7m_algorithm_info->context[i]); - armv7m->arm.core_cache->reg_list[i].valid = true; - armv7m->arm.core_cache->reg_list[i].dirty = true; + reg->valid = true; + reg->dirty = true; } } @@ -737,8 +738,9 @@ int armv7m_arch_state(struct target *target) ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32); sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32); - LOG_USER("target halted due to %s, current mode: %s %s\n" + LOG_USER("[%s] halted due to %s, current mode: %s %s\n" "xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s%s", + target_name(target), debug_reason_name(target), arm_mode_name(arm->core_mode), armv7m_exception_string(armv7m->exception_number), @@ -814,7 +816,7 @@ struct reg_cache *armv7m_build_reg_cache(struct target *target) LOG_ERROR("unable to allocate reg type list"); } - arm->cpsr = reg_list + ARMV7M_xPSR; + arm->cpsr = reg_list + ARMV7M_XPSR; arm->pc = reg_list + ARMV7M_PC; arm->core_cache = cache; @@ -865,6 +867,7 @@ int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m) /* Enable stimulus port #0 by default */ armv7m->trace_config.itm_ter[0] = 1; + arm->core_state = ARM_STATE_THUMB; arm->core_type = ARM_CORE_TYPE_M_PROFILE; arm->arch_info = armv7m; arm->setup_semihosting = armv7m_setup_semihosting; @@ -906,7 +909,7 @@ int armv7m_checksum_memory(struct target *target, buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, count); - int timeout = 20000 * (1 + (count / (1024 * 1024))); + unsigned int timeout = 20000 * (1 + (count / (1024 * 1024))); retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, crc_algorithm->address + (sizeof(cortex_m_crc_code) - 6), @@ -1013,7 +1016,7 @@ int armv7m_blank_check_memory(struct target *target, buf_set_u32(reg_params[1].value, 0, 32, erased_word); /* assume CPU clk at least 1 MHz */ - int timeout = (timed_out ? 30000 : 2000) + total_size * 3 / 1000; + unsigned int timeout = (timed_out ? 30000 : 2000) + total_size * 3 / 1000; retval = target_run_algorithm(target, 0, NULL, @@ -1095,7 +1098,11 @@ int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found) const struct command_registration armv7m_command_handlers[] = { { - .chain = arm_command_handlers, + .name = "arm", + .mode = COMMAND_ANY, + .help = "ARM command group", + .usage = "", + .chain = arm_all_profiles_command_handlers, }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/armv7m.h b/src/target/armv7m.h index 9ac121ac31..2878dd1c76 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV7M_H @@ -57,7 +46,7 @@ enum { ARMV7M_REGSEL_R14, ARMV7M_REGSEL_PC = 15, - ARMV7M_REGSEL_xPSR = 16, + ARMV7M_REGSEL_XPSR = 16, ARMV7M_REGSEL_MSP, ARMV7M_REGSEL_PSP, @@ -135,7 +124,7 @@ enum { ARMV7M_R14 = ARMV7M_REGSEL_R14, ARMV7M_PC = ARMV7M_REGSEL_PC, - ARMV7M_xPSR = ARMV7M_REGSEL_xPSR, + ARMV7M_XPSR = ARMV7M_REGSEL_XPSR, ARMV7M_MSP = ARMV7M_REGSEL_MSP, ARMV7M_PSP = ARMV7M_REGSEL_PSP, @@ -210,7 +199,7 @@ enum { /* for convenience add registers' block delimiters */ ARMV7M_LAST_REG, ARMV7M_CORE_FIRST_REG = ARMV7M_R0, - ARMV7M_CORE_LAST_REG = ARMV7M_xPSR, + ARMV7M_CORE_LAST_REG = ARMV7M_XPSR, ARMV7M_FPU_FIRST_REG = ARMV7M_D0, ARMV7M_FPU_LAST_REG = ARMV7M_FPSCR, ARMV8M_FIRST_REG = ARMV8M_MSP_NS, @@ -222,16 +211,19 @@ enum { FPV4_SP, FPV5_SP, FPV5_DP, + FPV5_MVE_I, + FPV5_MVE_F, }; #define ARMV7M_NUM_CORE_REGS (ARMV7M_CORE_LAST_REG - ARMV7M_CORE_FIRST_REG + 1) -#define ARMV7M_COMMON_MAGIC 0x2A452A45 +#define ARMV7M_COMMON_MAGIC 0x2A452A45U struct armv7m_common { + unsigned int common_magic; + struct arm arm; - int common_magic; int exception_number; /* AP this processor is connected to in the DAP */ @@ -300,7 +292,7 @@ target_to_armv7m_safe(struct target *target) } struct armv7m_algorithm { - int common_magic; + unsigned int common_magic; enum arm_mode core_mode; @@ -324,7 +316,7 @@ int armv7m_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, - int timeout_ms, void *arch_info); + unsigned int timeout_ms, void *arch_info); int armv7m_start_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, @@ -335,7 +327,7 @@ int armv7m_start_algorithm(struct target *target, int armv7m_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - target_addr_t exit_point, int timeout_ms, + target_addr_t exit_point, unsigned int timeout_ms, void *arch_info); int armv7m_invalidate_core_regs(struct target *target); diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c index 74ffaf5a4b..45117d2db8 100644 --- a/src/target/armv7m_trace.c +++ b/src/target/armv7m_trace.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2015 Paul Fertser <fercerpav@gmail.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/armv7m_trace.h b/src/target/armv7m_trace.h index 7e4977aba7..5abb0b9406 100644 --- a/src/target/armv7m_trace.h +++ b/src/target/armv7m_trace.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2015 Paul Fertser <fercerpav@gmail.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV7M_TRACE_H diff --git a/src/target/armv8.c b/src/target/armv8.c index 2de1157129..bf582ff801 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -1,22 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2015 by David Ung * * * * Copyright (C) 2018 by Liviu Ionescu * * <ilg@livius.net> * - * * - * 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, write to the * - * Free Software Foundation, Inc., * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -31,6 +19,7 @@ #include "register.h" #include <helper/binarybuffer.h> #include <helper/command.h> +#include <helper/nvp.h> #include <stdlib.h> #include <string.h> @@ -126,6 +115,166 @@ const char *armv8_mode_name(unsigned psr_mode) return "UNRECOGNIZED"; } +static uint8_t armv8_pa_size(uint32_t ps) +{ + uint8_t ret = 0; + switch (ps) { + case 0: + ret = 32; + break; + case 1: + ret = 36; + break; + case 2: + ret = 40; + break; + case 3: + ret = 42; + break; + case 4: + ret = 44; + break; + case 5: + ret = 48; + break; + default: + LOG_INFO("Unknown physical address size"); + break; + } + return ret; +} + +static __attribute__((unused)) int armv8_read_ttbcr32(struct target *target) +{ + struct armv8_common *armv8 = target_to_armv8(target); + struct arm_dpm *dpm = armv8->arm.dpm; + uint32_t ttbcr, ttbcr_n; + int retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + /* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(15, 0, 0, 2, 0, 2), + &ttbcr); + if (retval != ERROR_OK) + goto done; + + LOG_DEBUG("ttbcr %" PRIx32, ttbcr); + + ttbcr_n = ttbcr & 0x7; + armv8->armv8_mmu.ttbcr = ttbcr; + + /* + * ARM Architecture Reference Manual (ARMv7-A and ARMv7-R edition), + * document # ARM DDI 0406C + */ + armv8->armv8_mmu.ttbr_range[0] = 0xffffffff >> ttbcr_n; + armv8->armv8_mmu.ttbr_range[1] = 0xffffffff; + armv8->armv8_mmu.ttbr_mask[0] = 0xffffffff << (14 - ttbcr_n); + armv8->armv8_mmu.ttbr_mask[1] = 0xffffffff << 14; + + LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32 " ttbr1_mask %" PRIx32, + (ttbcr_n != 0) ? "used" : "not used", + armv8->armv8_mmu.ttbr_mask[0], + armv8->armv8_mmu.ttbr_mask[1]); + +done: + dpm->finish(dpm); + return retval; +} + +static int armv8_read_ttbcr(struct target *target) +{ + struct armv8_common *armv8 = target_to_armv8(target); + struct arm_dpm *dpm = armv8->arm.dpm; + struct arm *arm = &armv8->arm; + uint32_t ttbcr; + uint64_t ttbcr_64; + + int retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + /* clear ttrr1_used and ttbr0_mask */ + memset(&armv8->armv8_mmu.ttbr1_used, 0, sizeof(armv8->armv8_mmu.ttbr1_used)); + memset(&armv8->armv8_mmu.ttbr0_mask, 0, sizeof(armv8->armv8_mmu.ttbr0_mask)); + + switch (armv8_curel_from_core_mode(arm->core_mode)) { + case SYSTEM_CUREL_EL3: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_TCR_EL3, 0), + &ttbcr); + retval += dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_TTBR0_EL3, 0), + &armv8->ttbr_base); + if (retval != ERROR_OK) + goto done; + armv8->va_size = 64 - (ttbcr & 0x3F); + armv8->pa_size = armv8_pa_size((ttbcr >> 16) & 7); + armv8->page_size = (ttbcr >> 14) & 3; + break; + case SYSTEM_CUREL_EL2: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_TCR_EL2, 0), + &ttbcr); + retval += dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_TTBR0_EL2, 0), + &armv8->ttbr_base); + if (retval != ERROR_OK) + goto done; + armv8->va_size = 64 - (ttbcr & 0x3F); + armv8->pa_size = armv8_pa_size((ttbcr >> 16) & 7); + armv8->page_size = (ttbcr >> 14) & 3; + break; + case SYSTEM_CUREL_EL0: + armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H); + /* fall through */ + case SYSTEM_CUREL_EL1: + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_TCR_EL1, 0), + &ttbcr_64); + armv8->va_size = 64 - (ttbcr_64 & 0x3F); + armv8->pa_size = armv8_pa_size((ttbcr_64 >> 32) & 7); + armv8->page_size = (ttbcr_64 >> 14) & 3; + armv8->armv8_mmu.ttbr1_used = (((ttbcr_64 >> 16) & 0x3F) != 0) ? 1 : 0; + armv8->armv8_mmu.ttbr0_mask = 0x0000FFFFFFFFFFFFULL; + retval += dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_TTBR0_EL1 | (armv8->armv8_mmu.ttbr1_used), 0), + &armv8->ttbr_base); + if (retval != ERROR_OK) + goto done; + break; + default: + LOG_ERROR("unknown core state"); + retval = ERROR_FAIL; + break; + } + if (retval != ERROR_OK) + goto done; + + if (armv8->armv8_mmu.ttbr1_used == 1) + LOG_INFO("TTBR0 access above %" PRIx64, (uint64_t)(armv8->armv8_mmu.ttbr0_mask)); + +done: + armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); + dpm->finish(dpm); + return retval; +} + +static int armv8_get_pauth_mask(struct armv8_common *armv8, uint64_t *mask) +{ + struct arm *arm = &armv8->arm; + int retval = ERROR_OK; + if (armv8->va_size == 0) + retval = armv8_read_ttbcr(arm->target); + if (retval != ERROR_OK) + return retval; + + *mask = ~(((uint64_t)1 << armv8->va_size) - 1); + + return retval; +} + static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regval) { struct arm_dpm *dpm = &armv8->dpm; @@ -146,7 +295,7 @@ static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regv retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS_DLR(0), &value_64); break; - case ARMV8_xPSR: + case ARMV8_XPSR: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS_DSPSR(0), &value); value_64 = value; @@ -203,6 +352,10 @@ static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regv ARMV8_MRS(SYSTEM_SPSR_EL3, 0), &value); value_64 = value; break; + case ARMV8_PAUTH_CMASK: + case ARMV8_PAUTH_DMASK: + retval = armv8_get_pauth_mask(armv8, &value_64); + break; default: retval = ERROR_FAIL; break; @@ -261,7 +414,7 @@ static int armv8_write_reg(struct armv8_common *armv8, int regnum, uint64_t valu ARMV8_MSR_DLR(0), value_64); break; - case ARMV8_xPSR: + case ARMV8_XPSR: value = value_64; retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_DSPSR(0), @@ -376,7 +529,7 @@ static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *re ARMV8_MRC_DLR(0), &value); break; - case ARMV8_xPSR: + case ARMV8_XPSR: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRC_DSPSR(0), &value); @@ -411,17 +564,17 @@ static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *re break; case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */ retval = dpm->instr_read_data_r0(dpm, - ARMV8_MRS_xPSR_T1(1, 0), + ARMV8_MRS_XPSR_T1(1, 0), &value); break; case ARMV8_SPSR_EL2: /* mapped to SPSR_hyp */ retval = dpm->instr_read_data_r0(dpm, - ARMV8_MRS_xPSR_T1(1, 0), + ARMV8_MRS_XPSR_T1(1, 0), &value); break; case ARMV8_SPSR_EL3: /* mapped to SPSR_mon */ retval = dpm->instr_read_data_r0(dpm, - ARMV8_MRS_xPSR_T1(1, 0), + ARMV8_MRS_XPSR_T1(1, 0), &value); break; case ARMV8_FPSR: @@ -512,7 +665,7 @@ static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t va retval = dpm->instr_write_data_r0(dpm, ARMV8_MCR_DLR(0), value); break; - case ARMV8_xPSR: /* CPSR */ + case ARMV8_XPSR: /* CPSR */ /* read r0 from DCC, then "MCR r0, DSPSR" */ retval = dpm->instr_write_data_r0(dpm, ARMV8_MCR_DSPSR(0), value); @@ -547,17 +700,17 @@ static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t va break; case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */ retval = dpm->instr_write_data_r0(dpm, - ARMV8_MSR_GP_xPSR_T1(1, 0, 15), + ARMV8_MSR_GP_XPSR_T1(1, 0, 15), value); break; case ARMV8_SPSR_EL2: /* mapped to SPSR_hyp */ retval = dpm->instr_write_data_r0(dpm, - ARMV8_MSR_GP_xPSR_T1(1, 0, 15), + ARMV8_MSR_GP_XPSR_T1(1, 0, 15), value); break; case ARMV8_SPSR_EL3: /* mapped to SPSR_mon */ retval = dpm->instr_write_data_r0(dpm, - ARMV8_MSR_GP_xPSR_T1(1, 0, 15), + ARMV8_MSR_GP_XPSR_T1(1, 0, 15), value); break; case ARMV8_FPSR: @@ -784,156 +937,85 @@ static __attribute__((unused)) void armv8_show_fault_registers(struct target *ta armv8_show_fault_registers32(armv8); } -static uint8_t armv8_pa_size(uint32_t ps) +/* method adapted to cortex A : reused arm v4 v5 method*/ +int armv8_mmu_translate_va(struct target *target, target_addr_t va, target_addr_t *val) { - uint8_t ret = 0; - switch (ps) { + return ERROR_OK; +} + +static void armv8_decode_cacheability(int attr) +{ + if (attr == 0) { + LOG_USER_N("UNPREDICTABLE"); + return; + } + if (attr == 4) { + LOG_USER_N("Non-cacheable"); + return; + } + switch (attr & 0xC) { case 0: - ret = 32; - break; - case 1: - ret = 36; - break; - case 2: - ret = 40; - break; - case 3: - ret = 42; + LOG_USER_N("Write-Through Transient"); break; - case 4: - ret = 44; + case 0x4: + LOG_USER_N("Write-Back Transient"); break; - case 5: - ret = 48; + case 0x8: + LOG_USER_N("Write-Through Non-transient"); break; - default: - LOG_INFO("Unknown physical address size"); + case 0xC: + LOG_USER_N("Write-Back Non-transient"); break; } - return ret; -} - -static __attribute__((unused)) int armv8_read_ttbcr32(struct target *target) -{ - struct armv8_common *armv8 = target_to_armv8(target); - struct arm_dpm *dpm = armv8->arm.dpm; - uint32_t ttbcr, ttbcr_n; - int retval = dpm->prepare(dpm); - if (retval != ERROR_OK) - goto done; - /* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/ - retval = dpm->instr_read_data_r0(dpm, - ARMV4_5_MRC(15, 0, 0, 2, 0, 2), - &ttbcr); - if (retval != ERROR_OK) - goto done; - - LOG_DEBUG("ttbcr %" PRIx32, ttbcr); - - ttbcr_n = ttbcr & 0x7; - armv8->armv8_mmu.ttbcr = ttbcr; - - /* - * ARM Architecture Reference Manual (ARMv7-A and ARMv7-R edition), - * document # ARM DDI 0406C - */ - armv8->armv8_mmu.ttbr_range[0] = 0xffffffff >> ttbcr_n; - armv8->armv8_mmu.ttbr_range[1] = 0xffffffff; - armv8->armv8_mmu.ttbr_mask[0] = 0xffffffff << (14 - ttbcr_n); - armv8->armv8_mmu.ttbr_mask[1] = 0xffffffff << 14; - - LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32 " ttbr1_mask %" PRIx32, - (ttbcr_n != 0) ? "used" : "not used", - armv8->armv8_mmu.ttbr_mask[0], - armv8->armv8_mmu.ttbr_mask[1]); - -done: - dpm->finish(dpm); - return retval; + if (attr & 2) + LOG_USER_N(" Read-Allocate"); + else + LOG_USER_N(" No-Read Allocate"); + if (attr & 1) + LOG_USER_N(" Write-Allocate"); + else + LOG_USER_N(" No-Write Allocate"); } -static __attribute__((unused)) int armv8_read_ttbcr(struct target *target) +static void armv8_decode_memory_attr(int attr) { - struct armv8_common *armv8 = target_to_armv8(target); - struct arm_dpm *dpm = armv8->arm.dpm; - struct arm *arm = &armv8->arm; - uint32_t ttbcr; - uint64_t ttbcr_64; - - int retval = dpm->prepare(dpm); - if (retval != ERROR_OK) - goto done; - - /* clear ttrr1_used and ttbr0_mask */ - memset(&armv8->armv8_mmu.ttbr1_used, 0, sizeof(armv8->armv8_mmu.ttbr1_used)); - memset(&armv8->armv8_mmu.ttbr0_mask, 0, sizeof(armv8->armv8_mmu.ttbr0_mask)); - - switch (armv8_curel_from_core_mode(arm->core_mode)) { - case SYSTEM_CUREL_EL3: - retval = dpm->instr_read_data_r0(dpm, - ARMV8_MRS(SYSTEM_TCR_EL3, 0), - &ttbcr); - retval += dpm->instr_read_data_r0_64(dpm, - ARMV8_MRS(SYSTEM_TTBR0_EL3, 0), - &armv8->ttbr_base); - if (retval != ERROR_OK) - goto done; - armv8->va_size = 64 - (ttbcr & 0x3F); - armv8->pa_size = armv8_pa_size((ttbcr >> 16) & 7); - armv8->page_size = (ttbcr >> 14) & 3; - break; - case SYSTEM_CUREL_EL2: - retval = dpm->instr_read_data_r0(dpm, - ARMV8_MRS(SYSTEM_TCR_EL2, 0), - &ttbcr); - retval += dpm->instr_read_data_r0_64(dpm, - ARMV8_MRS(SYSTEM_TTBR0_EL2, 0), - &armv8->ttbr_base); - if (retval != ERROR_OK) - goto done; - armv8->va_size = 64 - (ttbcr & 0x3F); - armv8->pa_size = armv8_pa_size((ttbcr >> 16) & 7); - armv8->page_size = (ttbcr >> 14) & 3; - break; - case SYSTEM_CUREL_EL0: - armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H); - /* fall through */ - case SYSTEM_CUREL_EL1: - retval = dpm->instr_read_data_r0_64(dpm, - ARMV8_MRS(SYSTEM_TCR_EL1, 0), - &ttbcr_64); - armv8->va_size = 64 - (ttbcr_64 & 0x3F); - armv8->pa_size = armv8_pa_size((ttbcr_64 >> 32) & 7); - armv8->page_size = (ttbcr_64 >> 14) & 3; - armv8->armv8_mmu.ttbr1_used = (((ttbcr_64 >> 16) & 0x3F) != 0) ? 1 : 0; - armv8->armv8_mmu.ttbr0_mask = 0x0000FFFFFFFFFFFF; - retval += dpm->instr_read_data_r0_64(dpm, - ARMV8_MRS(SYSTEM_TTBR0_EL1 | (armv8->armv8_mmu.ttbr1_used), 0), - &armv8->ttbr_base); - if (retval != ERROR_OK) - goto done; - break; - default: - LOG_ERROR("unknown core state"); - retval = ERROR_FAIL; - break; + if (attr == 0x40) { + LOG_USER("Normal Memory, Inner Non-cacheable, " + "Outer Non-cacheable, XS=0"); + } else if (attr == 0xA0) { + LOG_USER("Normal Memory, Inner Write-through Cacheable, " + "Outer Write-through Cacheable, Read-Allocate, " + "No-Write Allocate, Non-transient, XS=0"); + } else if (attr == 0xF0) { + LOG_USER("Tagged Normal Memory, Inner Write-Back, " + "Outer Write-Back, Read-Allocate, Write-Allocate, " + "Non-transient"); + } else if ((attr & 0xF0) == 0) { + switch (attr & 0xC) { + case 0: + LOG_USER_N("Device-nGnRnE Memory"); + break; + case 0x4: + LOG_USER_N("Device-nGnRE Memory"); + break; + case 0x8: + LOG_USER_N("Device-nGRE Memory"); + break; + case 0xC: + LOG_USER_N("Device-GRE Memory"); + break; + } + if (attr & 1) + LOG_USER(", XS=0"); + else + LOG_USER_N("\n"); + } else { + LOG_USER_N("Normal Memory, Inner "); + armv8_decode_cacheability(attr & 0xF); + LOG_USER_N(", Outer "); + armv8_decode_cacheability(attr >> 4); + LOG_USER_N("\n"); } - if (retval != ERROR_OK) - goto done; - - if (armv8->armv8_mmu.ttbr1_used == 1) - LOG_INFO("TTBR0 access above %" PRIx64, (uint64_t)(armv8->armv8_mmu.ttbr0_mask)); - -done: - armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); - dpm->finish(dpm); - return retval; -} - -/* method adapted to cortex A : reused arm v4 v5 method*/ -int armv8_mmu_translate_va(struct target *target, target_addr_t va, target_addr_t *val) -{ - return ERROR_OK; } /* V8 method VA TO PA */ @@ -957,7 +1039,7 @@ int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va, }; if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s not halted", target_name(target)); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1018,11 +1100,9 @@ int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va, int NS = (par >> 9) & 1; int ATTR = (par >> 56) & 0xFF; - char *memtype = (ATTR & 0xF0) == 0 ? "Device Memory" : "Normal Memory"; - LOG_USER("%sshareable, %s", shared_name[SH], secure_name[NS]); - LOG_USER("%s", memtype); + armv8_decode_memory_attr(ATTR); } } @@ -1037,7 +1117,7 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command) unsigned int argp = 0; int retval; - static const struct jim_nvp nvp_ecatch_modes[] = { + static const struct nvp nvp_ecatch_modes[] = { { .name = "off", .value = 0 }, { .name = "nsec_el1", .value = (1 << 5) }, { .name = "nsec_el2", .value = (2 << 5) }, @@ -1047,7 +1127,7 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command) { .name = "sec_el13", .value = (5 << 1) }, { .name = NULL, .value = -1 }, }; - const struct jim_nvp *n; + const struct nvp *n; if (CMD_ARGC == 0) { const char *sec = NULL, *nsec = NULL; @@ -1057,11 +1137,11 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command) if (retval != ERROR_OK) return retval; - n = jim_nvp_value2name_simple(nvp_ecatch_modes, edeccr & 0x0f); + n = nvp_value2name(nvp_ecatch_modes, edeccr & 0x0f); if (n->name) sec = n->name; - n = jim_nvp_value2name_simple(nvp_ecatch_modes, edeccr & 0xf0); + n = nvp_value2name(nvp_ecatch_modes, edeccr & 0xf0); if (n->name) nsec = n->name; @@ -1075,7 +1155,7 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command) } while (argp < CMD_ARGC) { - n = jim_nvp_name2value_simple(nvp_ecatch_modes, CMD_ARGV[argp]); + n = nvp_name2value(nvp_ecatch_modes, CMD_ARGV[argp]); if (!n->name) { LOG_ERROR("Unknown option: %s", CMD_ARGV[argp]); return ERROR_FAIL; @@ -1095,6 +1175,15 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command) return ERROR_OK; } +COMMAND_HANDLER(armv8_pauth_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct armv8_common *armv8 = target_to_armv8(target); + return CALL_COMMAND_HANDLER(handle_command_parse_bool, + &armv8->enable_pauth, + "pauth feature"); +} + int armv8_handle_cache_info_command(struct command_invocation *cmd, struct armv8_cache_common *armv8_cache) { @@ -1376,7 +1465,7 @@ static const struct { { ARMV8_SP, "sp", 64, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_PC, "pc", 64, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.aarch64.core", NULL}, - { ARMV8_xPSR, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, + { ARMV8_XPSR, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "general", "org.gnu.gdb.aarch64.core", aarch64_flags_cpsr}, { ARMV8_V0, "v0", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V1, "v1", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, @@ -1433,6 +1522,8 @@ static const struct { NULL}, { ARMV8_SPSR_EL3, "SPSR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", NULL}, + { ARMV8_PAUTH_DMASK, "pauth_dmask", 64, ARM_MODE_ANY, REG_TYPE_UINT64, NULL, "org.gnu.gdb.aarch64.pauth", NULL}, + { ARMV8_PAUTH_CMASK, "pauth_cmask", 64, ARM_MODE_ANY, REG_TYPE_UINT64, NULL, "org.gnu.gdb.aarch64.pauth", NULL}, }; static const struct { @@ -1461,7 +1552,7 @@ static const struct { { ARMV8_R13, 0, "sp", 32, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.core" }, { ARMV8_R14, 0, "lr", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" }, { ARMV8_PC, 0, "pc", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_xPSR, 0, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_XPSR, 0, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, { ARMV8_V0, 0, "d0", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V0, 8, "d1", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, { ARMV8_V1, 0, "d2", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, @@ -1662,9 +1753,12 @@ struct reg_cache *armv8_build_reg_cache(struct target *target) *reg_list[i].reg_data_type = *armv8_regs[i].data_type; } else LOG_ERROR("unable to allocate reg type list"); + + if (i == ARMV8_PAUTH_CMASK || i == ARMV8_PAUTH_DMASK) + reg_list[i].exist = armv8->enable_pauth; } - arm->cpsr = reg_list + ARMV8_xPSR; + arm->cpsr = reg_list + ARMV8_XPSR; arm->pc = reg_list + ARMV8_PC; arm->core_cache = cache; @@ -1757,10 +1851,21 @@ const struct command_registration armv8_command_handlers[] = { .help = "configure exception catch", .usage = "[(nsec_el1,nsec_el2,sec_el1,sec_el3)+,off]", }, + { + .name = "pauth", + .handler = armv8_pauth_command, + .mode = COMMAND_CONFIG, + .help = "enable or disable providing GDB with an 8-bytes mask to " + "remove signature bits added by pointer authentication." + "Pointer authentication feature is broken until gdb 12.1, going to be fixed. " + "Consider using a newer version of gdb if you want enable " + "pauth feature.", + .usage = "[on|off]", + }, COMMAND_REGISTRATION_DONE }; -const char *armv8_get_gdb_arch(struct target *target) +const char *armv8_get_gdb_arch(const struct target *target) { struct arm *arm = target_to_arm(target); return arm->core_state == ARM_STATE_AARCH64 ? "aarch64" : "arm"; diff --git a/src/target/armv8.h b/src/target/armv8.h index c30739c8c5..f5aa211097 100644 --- a/src/target/armv8.h +++ b/src/target/armv8.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2015 by David Ung * - * * - * 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, write to the * - * Free Software Foundation, Inc., * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV8_H @@ -61,7 +49,7 @@ enum { ARMV8_SP = 31, ARMV8_PC = 32, - ARMV8_xPSR = 33, + ARMV8_XPSR = 33, ARMV8_V0 = 34, ARMV8_V1, @@ -110,6 +98,10 @@ enum { ARMV8_ESR_EL3 = 75, ARMV8_SPSR_EL3 = 76, + /* Pseudo registers defined by GDB to remove the pauth signature. */ + ARMV8_PAUTH_DMASK = 77, + ARMV8_PAUTH_CMASK = 78, + ARMV8_LAST_REG, }; @@ -120,7 +112,7 @@ enum run_control_op { ARMV8_RUNCONTROL_STEP = 3, }; -#define ARMV8_COMMON_MAGIC 0x0A450AAA +#define ARMV8_COMMON_MAGIC 0x0A450AAAU /* VA to PA translation operations opc2 values*/ #define V2PCWPR 0 @@ -190,8 +182,9 @@ struct armv8_mmu_common { }; struct armv8_common { + unsigned int common_magic; + struct arm arm; - int common_magic; struct reg_cache *core_cache; /* Core Debug Unit */ @@ -211,11 +204,15 @@ struct armv8_common { uint8_t pa_size; uint32_t page_size; uint64_t ttbr_base; + bool is_armv8r; struct armv8_mmu_common armv8_mmu; struct arm_cti *cti; + /* True if OpenOCD provides pointer auth related info to GDB */ + bool enable_pauth; + /* last run-control command issued to this target (resume, halt, step) */ enum run_control_op last_run_control_op; diff --git a/src/target/armv8_cache.c b/src/target/armv8_cache.c index 5b58d3f9fd..66d4e00801 100644 --- a/src/target/armv8_cache.c +++ b/src/target/armv8_cache.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2016 by Matthias Welwarsky * * matthias.welwarsky@sysgo.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -254,7 +243,7 @@ static int armv8_flush_all_data(struct target *target) foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (curr->state == TARGET_HALTED) { - LOG_INFO("Wait flushing data l1 on core %" PRId32, curr->coreid); + LOG_TARGET_INFO(curr, "Wait flushing data l1."); retval = _armv8_flush_all_data(curr); } } @@ -297,8 +286,9 @@ static struct armv8_cachesize decode_cache_reg(uint32_t cache_reg) size.index = (cache_reg >> 13) & 0x7fff; size.way = ((cache_reg >> 3) & 0x3ff); - while (((size.way << i) & 0x80000000) == 0) - i++; + if (size.way != 0) + while (((size.way << i) & 0x80000000) == 0) + i++; size.way_shift = i; return size; diff --git a/src/target/armv8_cache.h b/src/target/armv8_cache.h index fa46e16daf..7a12aa1506 100644 --- a/src/target/armv8_cache.h +++ b/src/target/armv8_cache.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2016 by Matthias Welwarsky * * matthias.welwarsky@sysgo.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ARMV8_CACHE_H_ #define OPENOCD_TARGET_ARMV8_CACHE_H_ diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index 765f1b7775..552bcfa024 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -1,16 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright (C) 2009 by David Brownell - * - * 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. - * */ #ifdef HAVE_CONFIG_H @@ -283,7 +274,7 @@ static int dpmv8_instr_write_data_dcc(struct arm_dpm *dpm, if (retval != ERROR_OK) return retval; - return dpmv8_exec_opcode(dpm, opcode, 0); + return dpmv8_exec_opcode(dpm, opcode, NULL); } static int dpmv8_instr_write_data_dcc_64(struct arm_dpm *dpm, @@ -296,7 +287,7 @@ static int dpmv8_instr_write_data_dcc_64(struct arm_dpm *dpm, if (retval != ERROR_OK) return retval; - return dpmv8_exec_opcode(dpm, opcode, 0); + return dpmv8_exec_opcode(dpm, opcode, NULL); } static int dpmv8_instr_write_data_r0(struct arm_dpm *dpm, @@ -596,6 +587,9 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) } LOG_DEBUG("target_el = %i, last_el = %i", target_el, dpm->last_el); + if (dpm->last_el == target_el) + return ERROR_OK; /* nothing to do */ + if (target_el > dpm->last_el) { retval = dpm->instr_execute(dpm, armv8_opcode(armv8, ARMV8_OPC_DCPS) | target_el); @@ -610,7 +604,7 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) /* load SPSR with the desired mode and execute DRPS */ LOG_DEBUG("SPSR = 0x%08"PRIx32, cpsr); retval = dpm->instr_write_data_r0(dpm, - ARMV8_MSR_GP_xPSR_T1(1, 0, 15), cpsr); + ARMV8_MSR_GP_XPSR_T1(1, 0, 15), cpsr); if (retval == ERROR_OK) retval = dpm->instr_execute(dpm, armv8_opcode(armv8, ARMV8_OPC_DRPS)); } @@ -731,7 +725,8 @@ static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) } /** - * Read basic registers of the current context: R0 to R15, and CPSR; + * Read basic registers of the current context: R0 to R15, and CPSR in AArch32 + * state or R0 to R31, PC and CPSR in AArch64 state; * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb). * In normal operation this is called on entry to halting debug state, * possibly after some other operations supporting restore of debug state @@ -778,9 +773,15 @@ int armv8_dpm_read_current_registers(struct arm_dpm *dpm) /* update core mode and state */ armv8_set_cpsr(arm, cpsr); - for (unsigned int i = ARMV8_PC; i < cache->num_regs ; i++) { + /* read the remaining registers that would be required by GDB 'g' packet */ + for (unsigned int i = ARMV8_R2; i <= ARMV8_PC ; i++) { struct arm_reg *arm_reg; + /* in AArch32 skip AArch64 registers */ + /* TODO: this should be detected below through arm_reg->mode */ + if (arm->core_state != ARM_STATE_AARCH64 && i > ARMV8_R14 && i < ARMV8_PC) + continue; + r = armv8_reg_current(arm, i); if (!r->exist || r->valid) continue; @@ -926,7 +927,7 @@ int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) if (!cache->reg_list[i].exist) continue; /* skip PC and CPSR */ - if (i == ARMV8_PC || i == ARMV8_xPSR) + if (i == ARMV8_PC || i == ARMV8_XPSR) continue; /* skip invalid */ if (!cache->reg_list[i].valid) @@ -948,7 +949,7 @@ int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) /* flush CPSR and PC */ if (retval == ERROR_OK) - retval = dpmv8_write_reg(dpm, &cache->reg_list[ARMV8_xPSR], ARMV8_xPSR); + retval = dpmv8_write_reg(dpm, &cache->reg_list[ARMV8_XPSR], ARMV8_XPSR); if (retval == ERROR_OK) retval = dpmv8_write_reg(dpm, &cache->reg_list[ARMV8_PC], ARMV8_PC); /* flush R0 -- it's *very* dirty by now */ @@ -1216,7 +1217,7 @@ static int dpmv8_watchpoint_setup(struct arm_dpm *dpm, unsigned index_t, uint32_t control; /* this hardware doesn't support data value matching or masking */ - if (wp->value || wp->mask != ~(uint32_t)0) { + if (wp->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) { LOG_DEBUG("watchpoint values and masking not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1302,9 +1303,9 @@ void armv8_dpm_handle_exception(struct arm_dpm *dpm, bool do_restore) unsigned int el; static const int clobbered_regs_by_el[3][5] = { - { ARMV8_PC, ARMV8_xPSR, ARMV8_ELR_EL1, ARMV8_ESR_EL1, ARMV8_SPSR_EL1 }, - { ARMV8_PC, ARMV8_xPSR, ARMV8_ELR_EL2, ARMV8_ESR_EL2, ARMV8_SPSR_EL2 }, - { ARMV8_PC, ARMV8_xPSR, ARMV8_ELR_EL3, ARMV8_ESR_EL3, ARMV8_SPSR_EL3 }, + { ARMV8_PC, ARMV8_XPSR, ARMV8_ELR_EL1, ARMV8_ESR_EL1, ARMV8_SPSR_EL1 }, + { ARMV8_PC, ARMV8_XPSR, ARMV8_ELR_EL2, ARMV8_ESR_EL2, ARMV8_SPSR_EL2 }, + { ARMV8_PC, ARMV8_XPSR, ARMV8_ELR_EL3, ARMV8_ESR_EL3, ARMV8_SPSR_EL3 }, }; el = (dpm->dscr >> 8) & 3; @@ -1319,7 +1320,7 @@ void armv8_dpm_handle_exception(struct arm_dpm *dpm, bool do_restore) mem_ap_write_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_DRCR, DRCR_CSE); - armv8->read_reg_u64(armv8, ARMV8_xPSR, &dlr); + armv8->read_reg_u64(armv8, ARMV8_XPSR, &dlr); dspsr = dlr; armv8->read_reg_u64(armv8, ARMV8_PC, &dlr); diff --git a/src/target/armv8_dpm.h b/src/target/armv8_dpm.h index c30b04ffa6..19b33da6f0 100644 --- a/src/target/armv8_dpm.h +++ b/src/target/armv8_dpm.h @@ -1,15 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Copyright (C) 2009 by David Brownell - * - * 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. */ #ifndef OPENOCD_TARGET_ARMV8_DPM_H diff --git a/src/target/armv8_opcodes.c b/src/target/armv8_opcodes.c index 96db728717..2635b3ec5f 100644 --- a/src/target/armv8_opcodes.c +++ b/src/target/armv8_opcodes.c @@ -1,16 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright (C) 2015 by Matthias Welwarsky <matthias.welwarsky@sysgo.com> - * - * 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. - * */ #ifdef HAVE_CONFIG_H @@ -45,9 +36,11 @@ static const uint32_t a64_opcodes[ARMV8_OPC_NUM] = { [ARMV8_OPC_LDRB_IP] = ARMV8_LDRB_IP(1, 0), [ARMV8_OPC_LDRH_IP] = ARMV8_LDRH_IP(1, 0), [ARMV8_OPC_LDRW_IP] = ARMV8_LDRW_IP(1, 0), + [ARMV8_OPC_LDRD_IP] = ARMV8_LDRD_IP(1, 0), [ARMV8_OPC_STRB_IP] = ARMV8_STRB_IP(1, 0), [ARMV8_OPC_STRH_IP] = ARMV8_STRH_IP(1, 0), [ARMV8_OPC_STRW_IP] = ARMV8_STRW_IP(1, 0), + [ARMV8_OPC_STRD_IP] = ARMV8_STRD_IP(1, 0), }; static const uint32_t t32_opcodes[ARMV8_OPC_NUM] = { diff --git a/src/target/armv8_opcodes.h b/src/target/armv8_opcodes.h index 8c213ef4dd..ddb0f9b073 100644 --- a/src/target/armv8_opcodes.h +++ b/src/target/armv8_opcodes.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* - * Copyright (C) 2015 by pierrr kuo - * vichy.kuo@gmail.com - * 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. - * + * Copyright (C) 2015 by pierrr kuo <vichy.kuo@gmail.com> */ + #ifndef OPENOCD_TARGET_ARMV8_OPCODES_H #define OPENOCD_TARGET_ARMV8_OPCODES_H @@ -146,9 +138,9 @@ (0xd500401f | ((op1) << 16) | ((crm) << 8) | ((op2) << 5)) #define ARMV8_MRS_T1(r, m1, rd, m) (0xF3E08020 | (r << 20) | (m1 << 16) | (rd << 8) | (m << 4)) -#define ARMV8_MRS_xPSR_T1(r, rd) (0xF3EF8000 | (r << 20) | (rd << 8)) +#define ARMV8_MRS_XPSR_T1(r, rd) (0xF3EF8000 | (r << 20) | (rd << 8)) #define ARMV8_MSR_GP_T1(r, m1, rd, m) (0xF3808020 | (r << 20) | (m1 << 8) | (rd << 16) | (m << 4)) -#define ARMV8_MSR_GP_xPSR_T1(r, rn, mask) (0xF3808000 | (r << 20) | (rn << 16) | (mask << 8)) +#define ARMV8_MSR_GP_XPSR_T1(r, rn, mask) (0xF3808000 | (r << 20) | (rn << 16) | (mask << 8)) #define ARMV8_BKPT(im) (0xD4200000 | ((im & 0xffff) << 5)) #define ARMV8_HLT(im) (0x0D4400000 | ((im & 0xffff) << 5)) @@ -163,6 +155,7 @@ #define ARMV8_LDRB_IP(rd, rn) (0x38401400 | (rn << 5) | rd) #define ARMV8_LDRH_IP(rd, rn) (0x78402400 | (rn << 5) | rd) #define ARMV8_LDRW_IP(rd, rn) (0xb8404400 | (rn << 5) | rd) +#define ARMV8_LDRD_IP(rd, rn) (0xf8408400 | (rn << 5) | rd) #define ARMV8_LDRB_IP_T3(rd, rn) (0xf8100b01 | (rn << 16) | (rd << 12)) #define ARMV8_LDRH_IP_T3(rd, rn) (0xf8300b02 | (rn << 16) | (rd << 12)) @@ -171,6 +164,7 @@ #define ARMV8_STRB_IP(rd, rn) (0x38001400 | (rn << 5) | rd) #define ARMV8_STRH_IP(rd, rn) (0x78002400 | (rn << 5) | rd) #define ARMV8_STRW_IP(rd, rn) (0xb8004400 | (rn << 5) | rd) +#define ARMV8_STRD_IP(rd, rn) (0xf8008400 | (rn << 5) | rd) #define ARMV8_STRB_IP_T3(rd, rn) (0xf8000b01 | (rn << 16) | (rd << 12)) #define ARMV8_STRH_IP_T3(rd, rn) (0xf8200b02 | (rn << 16) | (rd << 12)) @@ -208,9 +202,11 @@ enum armv8_opcode { ARMV8_OPC_STRB_IP, ARMV8_OPC_STRH_IP, ARMV8_OPC_STRW_IP, + ARMV8_OPC_STRD_IP, ARMV8_OPC_LDRB_IP, ARMV8_OPC_LDRH_IP, ARMV8_OPC_LDRW_IP, + ARMV8_OPC_LDRD_IP, ARMV8_OPC_NUM, }; diff --git a/src/target/avr32_ap7k.c b/src/target/avr32_ap7k.c index 4cf0276d6b..bbbf236592 100644 --- a/src/target/avr32_ap7k.c +++ b/src/target/avr32_ap7k.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * * Based on mips_m4k code: * * Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> * * Copyright (C) 2008 by David T.L. Wong * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -320,7 +309,7 @@ static int avr32_ap7k_resume(struct target *target, int current, int retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -442,7 +431,7 @@ static int avr32_ap7k_read_memory(struct target *target, target_addr_t address, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -482,7 +471,7 @@ static int avr32_ap7k_write_memory(struct target *target, target_addr_t address, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/avr32_ap7k.h b/src/target/avr32_ap7k.h index 65b856ef13..ac35754f47 100644 --- a/src/target/avr32_ap7k.h +++ b/src/target/avr32_ap7k.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_AVR32_AP7K_H @@ -20,9 +9,11 @@ struct target; -#define AP7K_COMMON_MAGIC 0x4150374b +#define AP7K_COMMON_MAGIC 0x4150374bU + struct avr32_ap7k_common { - int common_magic; + unsigned int common_magic; + struct avr32_jtag jtag; struct reg_cache *core_cache; uint32_t core_regs[AVR32NUMCOREREGS]; diff --git a/src/target/avr32_jtag.c b/src/target/avr32_jtag.c index a23ddf7b1c..a9c4f8dd64 100644 --- a/src/target/avr32_jtag.c +++ b/src/target/avr32_jtag.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/avr32_jtag.h b/src/target/avr32_jtag.h index b431ef4c82..382b245ba8 100644 --- a/src/target/avr32_jtag.h +++ b/src/target/avr32_jtag.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_AVR32_JTAG_H diff --git a/src/target/avr32_mem.c b/src/target/avr32_mem.c index 8f38a18442..835a501f03 100644 --- a/src/target/avr32_mem.c +++ b/src/target/avr32_mem.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/avr32_mem.h b/src/target/avr32_mem.h index f60a12179b..4a8019a31c 100644 --- a/src/target/avr32_mem.h +++ b/src/target/avr32_mem.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_AVR32_MEM_H diff --git a/src/target/avr32_regs.c b/src/target/avr32_regs.c index 7273822c2f..d6fd0e0020 100644 --- a/src/target/avr32_regs.c +++ b/src/target/avr32_regs.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/avr32_regs.h b/src/target/avr32_regs.h index cb492a9feb..90046571fd 100644 --- a/src/target/avr32_regs.h +++ b/src/target/avr32_regs.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko <gonzo@bluezbox.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_AVR32_REGS_H diff --git a/src/target/avrt.c b/src/target/avrt.c index feceec6363..61bef329fe 100644 --- a/src/target/avrt.c +++ b/src/target/avrt.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 by Simon Qian * * SimonQian@SimonQian.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/avrt.h b/src/target/avrt.h index 3610eb5e32..615cb8a890 100644 --- a/src/target/avrt.h +++ b/src/target/avrt.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 by Simon Qian * * SimonQian@SimonQian.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_AVRT_H diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index 3bfdbde91b..77f7673d07 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) ST-Ericsson SA 2011 * * michel.jaouen@stericsson.com : smp minimum 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -29,6 +18,11 @@ #include "rtos/rtos.h" #include "smp.h" +enum breakpoint_watchpoint { + BREAKPOINT, + WATCHPOINT, +}; + static const char * const breakpoint_type_strings[] = { "hardware", "software" @@ -59,7 +53,7 @@ static int breakpoint_add_internal(struct target *target, * breakpoint" ... check all the parameters before * succeeding. */ - LOG_ERROR("Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")", + LOG_TARGET_ERROR(target, "Duplicate Breakpoint address: " TARGET_ADDR_FMT " (BP %" PRIu32 ")", address, breakpoint->unique_id); return ERROR_TARGET_DUPLICATE_BREAKPOINT; } @@ -85,21 +79,20 @@ static int breakpoint_add_internal(struct target *target, reason = "resource not available"; goto fail; case ERROR_TARGET_NOT_HALTED: - reason = "target running"; + reason = "target not halted"; goto fail; default: reason = "unknown reason"; fail: - LOG_ERROR("can't add breakpoint: %s", reason); + LOG_TARGET_ERROR(target, "can't add breakpoint: %s", reason); free((*breakpoint_p)->orig_instr); free(*breakpoint_p); *breakpoint_p = NULL; return retval; } - LOG_DEBUG("[%d] added %s breakpoint at " TARGET_ADDR_FMT + LOG_TARGET_DEBUG(target, "added %s breakpoint at " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")", - target->coreid, breakpoint_type_strings[(*breakpoint_p)->type], (*breakpoint_p)->address, (*breakpoint_p)->length, (*breakpoint_p)->unique_id); @@ -141,14 +134,14 @@ static int context_breakpoint_add_internal(struct target *target, (*breakpoint_p)->unique_id = bpwp_unique_id++; retval = target_add_context_breakpoint(target, *breakpoint_p); if (retval != ERROR_OK) { - LOG_ERROR("could not add breakpoint"); + LOG_TARGET_ERROR(target, "could not add breakpoint"); free((*breakpoint_p)->orig_instr); free(*breakpoint_p); *breakpoint_p = NULL; return retval; } - LOG_DEBUG("added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %" PRIu32 ")", + LOG_TARGET_DEBUG(target, "added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %" PRIu32 ")", breakpoint_type_strings[(*breakpoint_p)->type], (*breakpoint_p)->asid, (*breakpoint_p)->length, (*breakpoint_p)->unique_id); @@ -172,11 +165,11 @@ static int hybrid_breakpoint_add_internal(struct target *target, * breakpoint" ... check all the parameters before * succeeding. */ - LOG_ERROR("Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")", + LOG_TARGET_ERROR(target, "Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")", asid, breakpoint->unique_id); return ERROR_TARGET_DUPLICATE_BREAKPOINT; } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) { - LOG_ERROR("Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")", + LOG_TARGET_ERROR(target, "Duplicate Breakpoint IVA: " TARGET_ADDR_FMT " (BP %" PRIu32 ")", address, breakpoint->unique_id); return ERROR_TARGET_DUPLICATE_BREAKPOINT; @@ -197,13 +190,13 @@ static int hybrid_breakpoint_add_internal(struct target *target, retval = target_add_hybrid_breakpoint(target, *breakpoint_p); if (retval != ERROR_OK) { - LOG_ERROR("could not add breakpoint"); + LOG_TARGET_ERROR(target, "could not add breakpoint"); free((*breakpoint_p)->orig_instr); free(*breakpoint_p); *breakpoint_p = NULL; return retval; } - LOG_DEBUG( + LOG_TARGET_DEBUG(target, "added %s Hybrid breakpoint at address " TARGET_ADDR_FMT " of length 0x%8.8x, (BPID: %" PRIu32 ")", breakpoint_type_strings[(*breakpoint_p)->type], (*breakpoint_p)->address, @@ -218,19 +211,12 @@ int breakpoint_add(struct target *target, uint32_t length, enum breakpoint_type type) { - if (target->smp) { - struct target_list *head; - - if (type == BKPT_SOFT) { - head = list_first_entry(target->smp_targets, struct target_list, lh); - struct target *curr = head->target; - if (target->rtos) - curr = rtos_swbp_target(target, address, length, type); - return breakpoint_add_internal(curr, address, length, type); - } - - foreach_smp_target(head, target->smp_targets) { - struct target *curr = head->target; + if (target->smp && type == BKPT_HARD) { + struct target_list *list_node; + foreach_smp_target(list_node, target->smp_targets) { + struct target *curr = list_node->target; + if (curr->state == TARGET_UNAVAILABLE) + continue; int retval = breakpoint_add_internal(curr, address, length, type); if (retval != ERROR_OK) return retval; @@ -238,6 +224,8 @@ int breakpoint_add(struct target *target, return ERROR_OK; } else { + /* For software breakpoints on SMP targets, only set them on a + * single target. We assume that SMP targets share memory. */ return breakpoint_add_internal(target, address, length, type); } } @@ -252,6 +240,8 @@ int context_breakpoint_add(struct target *target, foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; + if (curr->state == TARGET_UNAVAILABLE) + continue; int retval = context_breakpoint_add_internal(curr, asid, length, type); if (retval != ERROR_OK) return retval; @@ -274,6 +264,8 @@ int hybrid_breakpoint_add(struct target *target, foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; + if (curr->state == TARGET_UNAVAILABLE) + continue; int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type); if (retval != ERROR_OK) return retval; @@ -284,11 +276,17 @@ int hybrid_breakpoint_add(struct target *target, return hybrid_breakpoint_add_internal(target, address, asid, length, type); } -/* free up a breakpoint */ -static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove) +/* Free the data structures we use to track a breakpoint on data_target. + * Remove the actual breakpoint from breakpoint_target. + * This separation is useful when a software breakpoint is tracked on a target + * that is currently unavailable, but the breakpoint also affects a target that + * is available. + */ +static int breakpoint_free(struct target *data_target, struct target *breakpoint_target, + struct breakpoint *breakpoint_to_remove) { - struct breakpoint *breakpoint = target->breakpoints; - struct breakpoint **breakpoint_p = &target->breakpoints; + struct breakpoint *breakpoint = data_target->breakpoints; + struct breakpoint **breakpoint_p = &data_target->breakpoints; int retval; while (breakpoint) { @@ -299,99 +297,234 @@ static void breakpoint_free(struct target *target, struct breakpoint *breakpoint } if (!breakpoint) - return; + return ERROR_BREAKPOINT_NOT_FOUND; - retval = target_remove_breakpoint(target, breakpoint); + retval = target_remove_breakpoint(breakpoint_target, breakpoint); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(breakpoint_target, "could not remove breakpoint #%d on this target", + breakpoint->number); + return retval; + } - LOG_DEBUG("free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval); + LOG_TARGET_DEBUG(data_target, "free BPID: %" PRIu32 " --> %d", breakpoint->unique_id, retval); (*breakpoint_p) = breakpoint->next; free(breakpoint->orig_instr); free(breakpoint); + + return ERROR_OK; } -static int breakpoint_remove_internal(struct target *target, target_addr_t address) +static int breakpoint_remove_all_internal(struct target *target) { + LOG_TARGET_DEBUG(target, "Delete all breakpoints"); + struct breakpoint *breakpoint = target->breakpoints; + int retval = ERROR_OK; while (breakpoint) { - if ((breakpoint->address == address) || - (breakpoint->address == 0 && breakpoint->asid == address)) - break; + struct breakpoint *tmp = breakpoint; breakpoint = breakpoint->next; + int status = breakpoint_free(target, target, tmp); + if (status != ERROR_OK) + retval = status; } - if (breakpoint) { - breakpoint_free(target, breakpoint); - return 1; - } else { - if (!target->smp) - LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address); - return 0; + return retval; +} + +int breakpoint_remove(struct target *target, target_addr_t address) +{ + if (!target->smp) { + struct breakpoint *breakpoint = breakpoint_find(target, address); + if (breakpoint) + return breakpoint_free(target, target, breakpoint); + return ERROR_BREAKPOINT_NOT_FOUND; + } + + int retval = ERROR_OK; + unsigned int found = 0; + struct target_list *head; + /* Target where we found a software breakpoint. */ + struct target *software_breakpoint_target = NULL; + struct breakpoint *software_breakpoint = NULL; + /* Target that is available. */ + struct target *available_target = NULL; + /* Target that is available and halted. */ + struct target *halted_target = NULL; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + + if (!available_target && curr->state != TARGET_UNAVAILABLE) + available_target = curr; + if (!halted_target && curr->state == TARGET_HALTED) + halted_target = curr; + + struct breakpoint *breakpoint = breakpoint_find(curr, address); + if (!breakpoint) + continue; + + found++; + + if (breakpoint->type == BKPT_SOFT) { + /* Software breakpoints are set on only one of the SMP + * targets. We can remove them through any of the SMP + * targets. */ + if (software_breakpoint_target) { + LOG_TARGET_WARNING(curr, "Already found software breakpoint at " + TARGET_ADDR_FMT " on %s.", address, target_name(software_breakpoint_target)); + } else { + assert(!software_breakpoint_target); + software_breakpoint_target = curr; + software_breakpoint = breakpoint; + } + } else { + int status = breakpoint_free(curr, curr, breakpoint); + if (status != ERROR_OK) + retval = status; + } + } + + if (!found) { + LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address); + return ERROR_BREAKPOINT_NOT_FOUND; + } + + if (software_breakpoint) { + struct target *remove_target; + if (software_breakpoint_target->state == TARGET_HALTED) + remove_target = software_breakpoint_target; + else if (halted_target) + remove_target = halted_target; + else + remove_target = available_target; + + if (remove_target) { + LOG_DEBUG("Removing software breakpoint found on %s using %s (address=" + TARGET_ADDR_FMT ").", + target_name(software_breakpoint_target), + target_name(remove_target), + address); + /* Remove the software breakpoint through + * remove_target, but update the breakpoints structure + * of software_breakpoint_target. */ + int status = breakpoint_free(software_breakpoint_target, remove_target, software_breakpoint); + if (status != ERROR_OK) + /* TODO: If there is an error, can we try to remove the + * same breakpoint from a different target? */ + retval = status; + } else { + LOG_WARNING("No halted target found to remove software breakpoint at " + TARGET_ADDR_FMT ".", address); + } } + + return retval; } -static void breakpoint_remove_all_internal(struct target *target) +static int watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove) { - struct breakpoint *breakpoint = target->breakpoints; + struct watchpoint *watchpoint = target->watchpoints; + struct watchpoint **watchpoint_p = &target->watchpoints; + int retval; - while (breakpoint) { - struct breakpoint *tmp = breakpoint; - breakpoint = breakpoint->next; - breakpoint_free(target, tmp); + while (watchpoint) { + if (watchpoint == watchpoint_to_remove) + break; + watchpoint_p = &watchpoint->next; + watchpoint = watchpoint->next; + } + + if (!watchpoint) + return ERROR_WATCHPOINT_NOT_FOUND; + retval = target_remove_watchpoint(target, watchpoint); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "could not remove watchpoint #%d on this target", + watchpoint->number); + return retval; } + + LOG_TARGET_DEBUG(target, "free WPID: %d --> %d", watchpoint->unique_id, retval); + (*watchpoint_p) = watchpoint->next; + free(watchpoint); + + return ERROR_OK; } -void breakpoint_remove(struct target *target, target_addr_t address) +static int watchpoint_remove_all_internal(struct target *target) { - if (target->smp) { - unsigned int num_breakpoints = 0; - struct target_list *head; + struct watchpoint *watchpoint = target->watchpoints; + int retval = ERROR_OK; - foreach_smp_target(head, target->smp_targets) { - struct target *curr = head->target; - num_breakpoints += breakpoint_remove_internal(curr, address); - } - if (!num_breakpoints) - LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address); - } else { - breakpoint_remove_internal(target, address); + while (watchpoint) { + struct watchpoint *tmp = watchpoint; + watchpoint = watchpoint->next; + int status = watchpoint_free(target, tmp); + if (status != ERROR_OK) + retval = status; } + + return retval; } -void breakpoint_remove_all(struct target *target) +static int breakpoint_watchpoint_remove_all(struct target *target, enum breakpoint_watchpoint bp_wp) { + assert(bp_wp == BREAKPOINT || bp_wp == WATCHPOINT); + int retval = ERROR_OK; if (target->smp) { struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; - breakpoint_remove_all_internal(curr); + + int status = ERROR_OK; + if (bp_wp == BREAKPOINT) + status = breakpoint_remove_all_internal(curr); + else + status = watchpoint_remove_all_internal(curr); + + if (status != ERROR_OK) + retval = status; } } else { - breakpoint_remove_all_internal(target); + if (bp_wp == BREAKPOINT) + retval = breakpoint_remove_all_internal(target); + else + retval = watchpoint_remove_all_internal(target); } + + return retval; } -static void breakpoint_clear_target_internal(struct target *target) +int breakpoint_remove_all(struct target *target) { - LOG_DEBUG("Delete all breakpoints for target: %s", - target_name(target)); - while (target->breakpoints) - breakpoint_free(target, target->breakpoints); + return breakpoint_watchpoint_remove_all(target, BREAKPOINT); } -void breakpoint_clear_target(struct target *target) +int watchpoint_remove_all(struct target *target) { + return breakpoint_watchpoint_remove_all(target, WATCHPOINT); +} + +int breakpoint_clear_target(struct target *target) +{ + int retval = ERROR_OK; + if (target->smp) { struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; - breakpoint_clear_target_internal(curr); + int status = breakpoint_remove_all_internal(curr); + + if (status != ERROR_OK) + retval = status; } } else { - breakpoint_clear_target_internal(target); + retval = breakpoint_remove_all_internal(target); } + + return retval; } struct breakpoint *breakpoint_find(struct target *target, target_addr_t address) @@ -399,7 +532,8 @@ struct breakpoint *breakpoint_find(struct target *target, target_addr_t address) struct breakpoint *breakpoint = target->breakpoints; while (breakpoint) { - if (breakpoint->address == address) + if (breakpoint->address == address || + (breakpoint->address == 0 && breakpoint->asid == address)) return breakpoint; breakpoint = breakpoint->next; } @@ -407,8 +541,8 @@ struct breakpoint *breakpoint_find(struct target *target, target_addr_t address) return NULL; } -int watchpoint_add_internal(struct target *target, target_addr_t address, - uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask) +static int watchpoint_add_internal(struct target *target, target_addr_t address, + uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask) { struct watchpoint *watchpoint = target->watchpoints; struct watchpoint **watchpoint_p = &target->watchpoints; @@ -421,7 +555,7 @@ int watchpoint_add_internal(struct target *target, target_addr_t address, || watchpoint->value != value || watchpoint->mask != mask || watchpoint->rw != rw) { - LOG_ERROR("address " TARGET_ADDR_FMT + LOG_TARGET_ERROR(target, "address " TARGET_ADDR_FMT " already has watchpoint %d", address, watchpoint->unique_id); return ERROR_FAIL; @@ -450,12 +584,12 @@ int watchpoint_add_internal(struct target *target, target_addr_t address, reason = "resource not available"; goto bye; case ERROR_TARGET_NOT_HALTED: - reason = "target running"; + reason = "target not halted"; goto bye; default: reason = "unrecognized error"; bye: - LOG_ERROR("can't add %s watchpoint at " TARGET_ADDR_FMT ", %s", + LOG_TARGET_ERROR(target, "can't add %s watchpoint at " TARGET_ADDR_FMT ", %s", watchpoint_rw_strings[(*watchpoint_p)->rw], address, reason); free(*watchpoint_p); @@ -463,9 +597,8 @@ int watchpoint_add_internal(struct target *target, target_addr_t address, return retval; } - LOG_DEBUG("[%d] added %s watchpoint at " TARGET_ADDR_FMT + LOG_TARGET_DEBUG(target, "added %s watchpoint at " TARGET_ADDR_FMT " of length 0x%8.8" PRIx32 " (WPID: %d)", - target->coreid, watchpoint_rw_strings[(*watchpoint_p)->rw], (*watchpoint_p)->address, (*watchpoint_p)->length, @@ -475,13 +608,15 @@ int watchpoint_add_internal(struct target *target, target_addr_t address, } int watchpoint_add(struct target *target, target_addr_t address, - uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask) + uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask) { if (target->smp) { struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; + if (curr->state == TARGET_UNAVAILABLE) + continue; int retval = watchpoint_add_internal(curr, address, length, rw, value, mask); if (retval != ERROR_OK) return retval; @@ -494,28 +629,7 @@ int watchpoint_add(struct target *target, target_addr_t address, } } -static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove) -{ - struct watchpoint *watchpoint = target->watchpoints; - struct watchpoint **watchpoint_p = &target->watchpoints; - int retval; - - while (watchpoint) { - if (watchpoint == watchpoint_to_remove) - break; - watchpoint_p = &watchpoint->next; - watchpoint = watchpoint->next; - } - - if (!watchpoint) - return; - retval = target_remove_watchpoint(target, watchpoint); - LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval); - (*watchpoint_p) = watchpoint->next; - free(watchpoint); -} - -int watchpoint_remove_internal(struct target *target, target_addr_t address) +static int watchpoint_remove_internal(struct target *target, target_addr_t address) { struct watchpoint *watchpoint = target->watchpoints; @@ -526,38 +640,67 @@ int watchpoint_remove_internal(struct target *target, target_addr_t address) } if (watchpoint) { - watchpoint_free(target, watchpoint); - return 1; + return watchpoint_free(target, watchpoint); } else { - if (!target->smp) - LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " found", address); - return 0; + return ERROR_WATCHPOINT_NOT_FOUND; } } -void watchpoint_remove(struct target *target, target_addr_t address) +int watchpoint_remove(struct target *target, target_addr_t address) { + int retval = ERROR_OK; + unsigned int num_found_watchpoints = 0; if (target->smp) { - unsigned int num_watchpoints = 0; struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; - num_watchpoints += watchpoint_remove_internal(curr, address); + int status = watchpoint_remove_internal(curr, address); + + if (status != ERROR_WATCHPOINT_NOT_FOUND) { + num_found_watchpoints++; + + if (status != ERROR_OK) { + LOG_TARGET_ERROR(curr, "failed to remove watchpoint at address " TARGET_ADDR_FMT, address); + retval = status; + } + } } - if (num_watchpoints == 0) - LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " num_watchpoints", address); } else { - watchpoint_remove_internal(target, address); + retval = watchpoint_remove_internal(target, address); + + if (retval != ERROR_WATCHPOINT_NOT_FOUND) { + num_found_watchpoints++; + + if (retval != ERROR_OK) + LOG_TARGET_ERROR(target, "failed to remove watchpoint at address " TARGET_ADDR_FMT, address); + } + } + + if (num_found_watchpoints == 0) { + LOG_TARGET_ERROR(target, "no watchpoint at address " TARGET_ADDR_FMT " found", address); + return ERROR_WATCHPOINT_NOT_FOUND; } + + return retval; } -void watchpoint_clear_target(struct target *target) +int watchpoint_clear_target(struct target *target) { LOG_DEBUG("Delete all watchpoints for target: %s", target_name(target)); - while (target->watchpoints) - watchpoint_free(target, target->watchpoints); + + struct watchpoint *watchpoint = target->watchpoints; + int retval = ERROR_OK; + + while (watchpoint) { + struct watchpoint *tmp = watchpoint; + watchpoint = watchpoint->next; + int status = watchpoint_free(target, tmp); + if (status != ERROR_OK) + retval = status; + } + return retval; } int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, @@ -573,7 +716,7 @@ int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, *rw = hit_watchpoint->rw; *address = hit_watchpoint->address; - LOG_DEBUG("Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)", + LOG_TARGET_DEBUG(target, "Found hit watchpoint at " TARGET_ADDR_FMT " (WPID: %d)", hit_watchpoint->address, hit_watchpoint->unique_id); diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index fc5b50b18f..0ec65de716 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_BREAKPOINTS_H @@ -47,11 +36,13 @@ struct breakpoint { int linked_brp; }; +#define WATCHPOINT_IGNORE_DATA_VALUE_MASK (~(uint64_t)0) + struct watchpoint { target_addr_t address; uint32_t length; - uint32_t mask; - uint32_t value; + uint64_t mask; + uint64_t value; enum watchpoint_rw rw; bool is_set; unsigned int number; @@ -59,15 +50,15 @@ struct watchpoint { uint32_t unique_id; }; -void breakpoint_clear_target(struct target *target); +int breakpoint_clear_target(struct target *target); int breakpoint_add(struct target *target, target_addr_t address, uint32_t length, enum breakpoint_type type); int context_breakpoint_add(struct target *target, uint32_t asid, uint32_t length, enum breakpoint_type type); int hybrid_breakpoint_add(struct target *target, target_addr_t address, uint32_t asid, uint32_t length, enum breakpoint_type type); -void breakpoint_remove(struct target *target, target_addr_t address); -void breakpoint_remove_all(struct target *target); +int breakpoint_remove(struct target *target, target_addr_t address); +int breakpoint_remove_all(struct target *target); struct breakpoint *breakpoint_find(struct target *target, target_addr_t address); @@ -77,11 +68,12 @@ static inline void breakpoint_hw_set(struct breakpoint *breakpoint, unsigned int breakpoint->number = hw_number; } -void watchpoint_clear_target(struct target *target); +int watchpoint_clear_target(struct target *target); int watchpoint_add(struct target *target, target_addr_t address, uint32_t length, - enum watchpoint_rw rw, uint32_t value, uint32_t mask); -void watchpoint_remove(struct target *target, target_addr_t address); + enum watchpoint_rw rw, uint64_t value, uint64_t mask); +int watchpoint_remove(struct target *target, target_addr_t address); +int watchpoint_remove_all(struct target *target); /* report type and address of just hit watchpoint */ int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, @@ -93,4 +85,7 @@ static inline void watchpoint_set(struct watchpoint *watchpoint, unsigned int nu watchpoint->number = number; } +#define ERROR_BREAKPOINT_NOT_FOUND (-1600) +#define ERROR_WATCHPOINT_NOT_FOUND (-1601) + #endif /* OPENOCD_TARGET_BREAKPOINTS_H */ diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 2dc1091081..7fa0c4e8b7 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -26,19 +28,6 @@ * Copyright (C) 2016 Chengyu Zheng * * chengyu.zheng@polimi.it : watchpoint 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/>. * - * * * Cortex-A8(tm) TRM, ARM DDI 0344H * * Cortex-A9(tm) TRM, ARM DDI 0407F * * Cortex-A4(tm) TRM, ARM DDI 0363E * @@ -63,6 +52,7 @@ #include "transport/transport.h" #include "smp.h" #include <helper/bits.h> +#include <helper/nvp.h> #include <helper/time_support.h> static int cortex_a_poll(struct target *target); @@ -481,6 +471,28 @@ static int cortex_a_instr_write_data_r0(struct arm_dpm *dpm, return retval; } +static int cortex_a_instr_write_data_r0_r1(struct arm_dpm *dpm, + uint32_t opcode, uint64_t data) +{ + struct cortex_a_common *a = dpm_to_a(dpm); + uint32_t dscr = DSCR_INSTR_COMP; + int retval; + + retval = cortex_a_instr_write_data_rt_dcc(dpm, 0, data & 0xffffffffULL); + if (retval != ERROR_OK) + return retval; + + retval = cortex_a_instr_write_data_rt_dcc(dpm, 1, data >> 32); + if (retval != ERROR_OK) + return retval; + + /* then the opcode, taking data from R0, R1 */ + retval = cortex_a_exec_opcode(a->armv7a_common.arm.target, + opcode, + &dscr); + return retval; +} + static int cortex_a_instr_cpsr_sync(struct arm_dpm *dpm) { struct target *target = dpm->arm->target; @@ -549,6 +561,29 @@ static int cortex_a_instr_read_data_r0(struct arm_dpm *dpm, return cortex_a_instr_read_data_rt_dcc(dpm, 0, data); } +static int cortex_a_instr_read_data_r0_r1(struct arm_dpm *dpm, + uint32_t opcode, uint64_t *data) +{ + uint32_t lo, hi; + int retval; + + /* the opcode, writing data to RO, R1 */ + retval = cortex_a_instr_read_data_r0(dpm, opcode, &lo); + if (retval != ERROR_OK) + return retval; + + *data = lo; + + /* write R1 to DCC */ + retval = cortex_a_instr_read_data_rt_dcc(dpm, 1, &hi); + if (retval != ERROR_OK) + return retval; + + *data |= (uint64_t)hi << 32; + + return retval; +} + static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, uint32_t addr, uint32_t control) { @@ -622,10 +657,12 @@ static int cortex_a_dpm_setup(struct cortex_a_common *a, uint32_t didr) dpm->instr_write_data_dcc = cortex_a_instr_write_data_dcc; dpm->instr_write_data_r0 = cortex_a_instr_write_data_r0; + dpm->instr_write_data_r0_r1 = cortex_a_instr_write_data_r0_r1; dpm->instr_cpsr_sync = cortex_a_instr_cpsr_sync; dpm->instr_read_data_dcc = cortex_a_instr_read_data_dcc; dpm->instr_read_data_r0 = cortex_a_instr_read_data_r0; + dpm->instr_read_data_r0_r1 = cortex_a_instr_read_data_r0_r1; dpm->bpwp_enable = cortex_a_bpwp_enable; dpm->bpwp_disable = cortex_a_bpwp_disable; @@ -818,11 +855,11 @@ static int cortex_a_internal_restore(struct target *target, int current, armv7m->core_cache->reg_list[ARMV7M_PRIMASK].valid = true; /* Make sure we are in Thumb mode */ - buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32, - buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, + buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_XPSR].value, 0, 32, + buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_XPSR].value, 0, 32) | (1 << 24)); - armv7m->core_cache->reg_list[ARMV7M_xPSR].dirty = true; - armv7m->core_cache->reg_list[ARMV7M_xPSR].valid = true; + armv7m->core_cache->reg_list[ARMV7M_XPSR].dirty = true; + armv7m->core_cache->reg_list[ARMV7M_XPSR].valid = true; } #endif @@ -1157,7 +1194,7 @@ static int cortex_a_step(struct target *target, int current, target_addr_t addre int retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2235,7 +2272,7 @@ static int cortex_a_write_cpu_memory(struct target *target, LOG_DEBUG("Writing CPU memory address 0x%" PRIx32 " size %" PRIu32 " count %" PRIu32, address, size, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2257,7 +2294,7 @@ static int cortex_a_write_cpu_memory(struct target *target, /* Switch to non-blocking mode if not already in that mode. */ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, &dscr); if (retval != ERROR_OK) - goto out; + return retval; /* Mark R0 as dirty. */ arm_reg_current(arm, 0)->dirty = true; @@ -2265,16 +2302,16 @@ static int cortex_a_write_cpu_memory(struct target *target, /* Read DFAR and DFSR, as they will be modified in the event of a fault. */ retval = cortex_a_read_dfar_dfsr(target, &orig_dfar, &orig_dfsr, &dscr); if (retval != ERROR_OK) - goto out; + return retval; /* Get the memory address into R0. */ retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, address); if (retval != ERROR_OK) - goto out; + return retval; retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr); if (retval != ERROR_OK) - goto out; + return retval; if (size == 4 && (address % 4) == 0) { /* We are doing a word-aligned transfer, so use fast mode. */ @@ -2299,7 +2336,6 @@ static int cortex_a_write_cpu_memory(struct target *target, retval = cortex_a_write_cpu_memory_slow(target, size, count, buffer, &dscr); } -out: final_retval = retval; /* Switch to non-blocking mode if not already in that mode. */ @@ -2553,7 +2589,7 @@ static int cortex_a_read_cpu_memory(struct target *target, LOG_DEBUG("Reading CPU memory address 0x%" PRIx32 " size %" PRIu32 " count %" PRIu32, address, size, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2575,7 +2611,7 @@ static int cortex_a_read_cpu_memory(struct target *target, /* Switch to non-blocking mode if not already in that mode. */ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, &dscr); if (retval != ERROR_OK) - goto out; + return retval; /* Mark R0 as dirty. */ arm_reg_current(arm, 0)->dirty = true; @@ -2583,16 +2619,16 @@ static int cortex_a_read_cpu_memory(struct target *target, /* Read DFAR and DFSR, as they will be modified in the event of a fault. */ retval = cortex_a_read_dfar_dfsr(target, &orig_dfar, &orig_dfsr, &dscr); if (retval != ERROR_OK) - goto out; + return retval; /* Get the memory address into R0. */ retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, address); if (retval != ERROR_OK) - goto out; + return retval; retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr); if (retval != ERROR_OK) - goto out; + return retval; if (size == 4 && (address % 4) == 0) { /* We are doing a word-aligned transfer, so use fast mode. */ @@ -2618,7 +2654,6 @@ static int cortex_a_read_cpu_memory(struct target *target, retval = cortex_a_read_cpu_memory_slow(target, size, count, buffer, &dscr); } -out: final_retval = retval; /* Switch to non-blocking mode if not already in that mode. */ @@ -2885,15 +2920,21 @@ static int cortex_a_examine_first(struct target *target) int retval = ERROR_OK; uint32_t didr, cpuid, dbg_osreg, dbg_idpfr1; - if (pc->ap_num == DP_APSEL_INVALID) { - /* Search for the APB-AP - it is needed for access to debug registers */ - retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap); - if (retval != ERROR_OK) { - LOG_ERROR("Could not find APB-AP for debug access"); - return retval; + if (!armv7a->debug_ap) { + if (pc->ap_num == DP_APSEL_INVALID) { + /* Search for the APB-AP - it is needed for access to debug registers */ + retval = dap_find_get_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap); + if (retval != ERROR_OK) { + LOG_ERROR("Could not find APB-AP for debug access"); + return retval; + } + } else { + armv7a->debug_ap = dap_get_ap(swjdp, pc->ap_num); + if (!armv7a->debug_ap) { + LOG_ERROR("Cannot get AP"); + return ERROR_FAIL; + } } - } else { - armv7a->debug_ap = dap_ap(swjdp, pc->ap_num); } retval = mem_ap_init(armv7a->debug_ap); @@ -2905,18 +2946,11 @@ static int cortex_a_examine_first(struct target *target) armv7a->debug_ap->memaccess_tck = 80; if (!target->dbgbase_set) { - target_addr_t dbgbase; - /* Get ROM Table base */ - uint32_t apid; - int32_t coreidx = target->coreid; LOG_DEBUG("%s's dbgbase is not set, trying to detect using the ROM table", target->cmd_name); - retval = dap_get_debugbase(armv7a->debug_ap, &dbgbase, &apid); - if (retval != ERROR_OK) - return retval; /* Lookup Processor DAP */ - retval = dap_lookup_cs_component(armv7a->debug_ap, dbgbase, ARM_CS_C9_DEVTYPE_CORE_DEBUG, - &armv7a->debug_base, &coreidx); + retval = dap_lookup_cs_component(armv7a->debug_ap, ARM_CS_C9_DEVTYPE_CORE_DEBUG, + &armv7a->debug_base, target->coreid); if (retval != ERROR_OK) { LOG_ERROR("Can't detect %s's dbgbase from the ROM table; you need to specify it explicitly.", target->cmd_name); @@ -2955,29 +2989,29 @@ static int cortex_a_examine_first(struct target *target) armv7a->debug_base + CPUDBG_PRSR, &dbg_osreg); if (retval != ERROR_OK) return retval; - LOG_DEBUG("target->coreid %" PRId32 " DBGPRSR 0x%" PRIx32, target->coreid, dbg_osreg); + LOG_TARGET_DEBUG(target, "DBGPRSR 0x%" PRIx32, dbg_osreg); if ((dbg_osreg & PRSR_POWERUP_STATUS) == 0) { - LOG_ERROR("target->coreid %" PRId32 " powered down!", target->coreid); + LOG_TARGET_ERROR(target, "powered down!"); target->state = TARGET_UNKNOWN; /* TARGET_NO_POWER? */ return ERROR_TARGET_INIT_FAILED; } if (dbg_osreg & PRSR_STICKY_RESET_STATUS) - LOG_DEBUG("target->coreid %" PRId32 " was reset!", target->coreid); + LOG_TARGET_DEBUG(target, "was reset!"); /* Read DBGOSLSR and check if OSLK is implemented */ retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_OSLSR, &dbg_osreg); if (retval != ERROR_OK) return retval; - LOG_DEBUG("target->coreid %" PRId32 " DBGOSLSR 0x%" PRIx32, target->coreid, dbg_osreg); + LOG_TARGET_DEBUG(target, "DBGOSLSR 0x%" PRIx32, dbg_osreg); /* check if OS Lock is implemented */ if ((dbg_osreg & OSLSR_OSLM) == OSLSR_OSLM0 || (dbg_osreg & OSLSR_OSLM) == OSLSR_OSLM1) { /* check if OS Lock is set */ if (dbg_osreg & OSLSR_OSLK) { - LOG_DEBUG("target->coreid %" PRId32 " OSLock set! Trying to unlock", target->coreid); + LOG_TARGET_DEBUG(target, "OSLock set! Trying to unlock"); retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_OSLAR, @@ -2988,8 +3022,7 @@ static int cortex_a_examine_first(struct target *target) /* if we fail to access the register or cannot reset the OSLK bit, bail out */ if (retval != ERROR_OK || (dbg_osreg & OSLSR_OSLK) != 0) { - LOG_ERROR("target->coreid %" PRId32 " OSLock sticky, core not powered?", - target->coreid); + LOG_TARGET_ERROR(target, "OSLock sticky, core not powered?"); target->state = TARGET_UNKNOWN; /* TARGET_NO_POWER? */ return ERROR_TARGET_INIT_FAILED; } @@ -3002,13 +3035,11 @@ static int cortex_a_examine_first(struct target *target) return retval; if (dbg_idpfr1 & 0x000000f0) { - LOG_DEBUG("target->coreid %" PRId32 " has security extensions", - target->coreid); + LOG_TARGET_DEBUG(target, "has security extensions"); armv7a->arm.core_type = ARM_CORE_TYPE_SEC_EXT; } if (dbg_idpfr1 & 0x0000f000) { - LOG_DEBUG("target->coreid %" PRId32 " has virtualization extensions", - target->coreid); + LOG_TARGET_DEBUG(target, "has virtualization extensions"); /* * overwrite and simplify the checks. * virtualization extensions require implementation of security extension @@ -3179,6 +3210,9 @@ static void cortex_a_deinit_target(struct target *target) dscr & ~DSCR_HALT_DBG_MODE); } + if (armv7a->debug_ap) + dap_put_ap(armv7a->debug_ap); + free(cortex_a->wrp_list); free(cortex_a->brp_list); arm_free_reg_cache(dpm->arm); @@ -3193,8 +3227,8 @@ static int cortex_a_mmu(struct target *target, int *enabled) struct armv7a_common *armv7a = target_to_armv7a(target); if (target->state != TARGET_HALTED) { - LOG_ERROR("%s: target not halted", __func__); - return ERROR_TARGET_INVALID; + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; } if (armv7a->is_armv7r) @@ -3257,15 +3291,15 @@ COMMAND_HANDLER(handle_cortex_a_mask_interrupts_command) struct target *target = get_current_target(CMD_CTX); struct cortex_a_common *cortex_a = target_to_cortex_a(target); - static const struct jim_nvp nvp_maskisr_modes[] = { + static const struct nvp nvp_maskisr_modes[] = { { .name = "off", .value = CORTEX_A_ISRMASK_OFF }, { .name = "on", .value = CORTEX_A_ISRMASK_ON }, { .name = NULL, .value = -1 }, }; - const struct jim_nvp *n; + const struct nvp *n; if (CMD_ARGC > 0) { - n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); + n = nvp_name2value(nvp_maskisr_modes, CMD_ARGV[0]); if (!n->name) { LOG_ERROR("Unknown parameter: %s - should be off or on", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; @@ -3274,7 +3308,7 @@ COMMAND_HANDLER(handle_cortex_a_mask_interrupts_command) cortex_a->isrmasking_mode = n->value; } - n = jim_nvp_value2name_simple(nvp_maskisr_modes, cortex_a->isrmasking_mode); + n = nvp_value2name(nvp_maskisr_modes, cortex_a->isrmasking_mode); command_print(CMD, "cortex_a interrupt mask %s", n->name); return ERROR_OK; @@ -3285,22 +3319,22 @@ COMMAND_HANDLER(handle_cortex_a_dacrfixup_command) struct target *target = get_current_target(CMD_CTX); struct cortex_a_common *cortex_a = target_to_cortex_a(target); - static const struct jim_nvp nvp_dacrfixup_modes[] = { + static const struct nvp nvp_dacrfixup_modes[] = { { .name = "off", .value = CORTEX_A_DACRFIXUP_OFF }, { .name = "on", .value = CORTEX_A_DACRFIXUP_ON }, { .name = NULL, .value = -1 }, }; - const struct jim_nvp *n; + const struct nvp *n; if (CMD_ARGC > 0) { - n = jim_nvp_name2value_simple(nvp_dacrfixup_modes, CMD_ARGV[0]); + n = nvp_name2value(nvp_dacrfixup_modes, CMD_ARGV[0]); if (!n->name) return ERROR_COMMAND_SYNTAX_ERROR; cortex_a->dacrfixup_mode = n->value; } - n = jim_nvp_value2name_simple(nvp_dacrfixup_modes, cortex_a->dacrfixup_mode); + n = nvp_value2name(nvp_dacrfixup_modes, cortex_a->dacrfixup_mode); command_print(CMD, "cortex_a domain access control fixup %s", n->name); return ERROR_OK; diff --git a/src/target/cortex_a.h b/src/target/cortex_a.h index 685621c6b1..37fba1a885 100644 --- a/src/target/cortex_a.h +++ b/src/target/cortex_a.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -10,19 +12,6 @@ * * * Copyright (C) 2009 by Dirk Behme * * dirk.behme@gmail.com - copy from cortex_m3 * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_CORTEX_A_H @@ -30,8 +19,7 @@ #include "armv7a.h" -#define CORTEX_A_COMMON_MAGIC 0x411fc082 -#define CORTEX_A15_COMMON_MAGIC 0x413fc0f1 +#define CORTEX_A_COMMON_MAGIC 0x411fc082U #define CORTEX_A5_PARTNUM 0xc05 #define CORTEX_A7_PARTNUM 0xc07 @@ -79,7 +67,9 @@ struct cortex_a_wrp { }; struct cortex_a_common { - int common_magic; + unsigned int common_magic; + + struct armv7a_common armv7a_common; /* Context information */ uint32_t cpudbg_dscr; @@ -108,9 +98,6 @@ struct cortex_a_common { enum cortex_a_isrmasking_mode isrmasking_mode; enum cortex_a_dacrfixup_mode dacrfixup_mode; - - struct armv7a_common armv7a_common; - }; static inline struct cortex_a_common * diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 344cfcf617..4894cabf8b 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -8,19 +10,6 @@ * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * - * 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/>. * - * * * * * Cortex-M3(tm) TRM, ARM DDI 0337E (r1p1) and 0337G (r2p0) * * * @@ -39,6 +28,8 @@ #include "register.h" #include "arm_opcodes.h" #include "arm_semihosting.h" +#include "smp.h" +#include <helper/nvp.h> #include <helper/time_support.h> #include <rtt/rtt.h> @@ -59,61 +50,89 @@ /* Supported Cortex-M Cores */ static const struct cortex_m_part_info cortex_m_parts[] = { { - .partno = CORTEX_M0_PARTNO, + .impl_part = CORTEX_M0_PARTNO, .name = "Cortex-M0", .arch = ARM_ARCH_V6M, }, { - .partno = CORTEX_M0P_PARTNO, + .impl_part = CORTEX_M0P_PARTNO, .name = "Cortex-M0+", .arch = ARM_ARCH_V6M, }, { - .partno = CORTEX_M1_PARTNO, + .impl_part = CORTEX_M1_PARTNO, .name = "Cortex-M1", .arch = ARM_ARCH_V6M, }, { - .partno = CORTEX_M3_PARTNO, + .impl_part = CORTEX_M3_PARTNO, .name = "Cortex-M3", .arch = ARM_ARCH_V7M, .flags = CORTEX_M_F_TAR_AUTOINCR_BLOCK_4K, }, { - .partno = CORTEX_M4_PARTNO, + .impl_part = CORTEX_M4_PARTNO, .name = "Cortex-M4", .arch = ARM_ARCH_V7M, .flags = CORTEX_M_F_HAS_FPV4 | CORTEX_M_F_TAR_AUTOINCR_BLOCK_4K, }, { - .partno = CORTEX_M7_PARTNO, + .impl_part = CORTEX_M7_PARTNO, .name = "Cortex-M7", .arch = ARM_ARCH_V7M, .flags = CORTEX_M_F_HAS_FPV5, }, { - .partno = CORTEX_M23_PARTNO, + .impl_part = CORTEX_M23_PARTNO, .name = "Cortex-M23", .arch = ARM_ARCH_V8M, }, { - .partno = CORTEX_M33_PARTNO, + .impl_part = CORTEX_M33_PARTNO, .name = "Cortex-M33", .arch = ARM_ARCH_V8M, .flags = CORTEX_M_F_HAS_FPV5, }, { - .partno = CORTEX_M35P_PARTNO, + .impl_part = CORTEX_M35P_PARTNO, .name = "Cortex-M35P", .arch = ARM_ARCH_V8M, .flags = CORTEX_M_F_HAS_FPV5, }, { - .partno = CORTEX_M55_PARTNO, + .impl_part = CORTEX_M55_PARTNO, .name = "Cortex-M55", .arch = ARM_ARCH_V8M, .flags = CORTEX_M_F_HAS_FPV5, }, + { + .impl_part = CORTEX_M85_PARTNO, + .name = "Cortex-M85", + .arch = ARM_ARCH_V8M, + .flags = CORTEX_M_F_HAS_FPV5, + }, + { + .impl_part = STAR_MC1_PARTNO, + .name = "STAR-MC1", + .arch = ARM_ARCH_V8M, + .flags = CORTEX_M_F_HAS_FPV5, + }, + { + .impl_part = INFINEON_SLX2_PARTNO, + .name = "Infineon-SLx2", + .arch = ARM_ARCH_V8M, + }, + { + .impl_part = REALTEK_M200_PARTNO, + .name = "Real-M200 (KM0)", + .arch = ARM_ARCH_V8M, + }, + { + .impl_part = REALTEK_M300_PARTNO, + .name = "Real-M300 (KM4)", + .arch = ARM_ARCH_V8M, + .flags = CORTEX_M_F_HAS_FPV5, + }, }; /* forward declarations */ @@ -663,6 +682,11 @@ static int cortex_m_endreset_event(struct target *target) register_cache_invalidate(armv7m->arm.core_cache); + /* TODO: invalidate also working areas (needed in the case of detected reset). + * Doing so will require flash drivers to test if working area + * is still valid in all target algo calling loops. + */ + /* make sure we have latest dhcsr flags */ retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) @@ -775,7 +799,7 @@ static int cortex_m_examine_exception_reason(struct target *target) static int cortex_m_debug_entry(struct target *target) { - uint32_t xPSR; + uint32_t xpsr; int retval; struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; @@ -799,15 +823,11 @@ static int cortex_m_debug_entry(struct target *target) return retval; /* examine PE security state */ - bool secure_state = false; + uint32_t dscsr = 0; if (armv7m->arm.arch == ARM_ARCH_V8M) { - uint32_t dscsr; - retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DSCSR, &dscsr); if (retval != ERROR_OK) return retval; - - secure_state = (dscsr & DSCSR_CDS) == DSCSR_CDS; } /* Load all registers to arm.core_cache */ @@ -826,11 +846,11 @@ static int cortex_m_debug_entry(struct target *target) return retval; r = arm->cpsr; - xPSR = buf_get_u32(r->value, 0, 32); + xpsr = buf_get_u32(r->value, 0, 32); /* Are we in an exception handler */ - if (xPSR & 0x1FF) { - armv7m->exception_number = (xPSR & 0x1FF); + if (xpsr & 0x1FF) { + armv7m->exception_number = (xpsr & 0x1FF); arm->core_mode = ARM_MODE_HANDLER; arm->map = armv7m_msp_reg_map; @@ -855,6 +875,7 @@ static int cortex_m_debug_entry(struct target *target) if (armv7m->exception_number) cortex_m_examine_exception_reason(target); + bool secure_state = (dscsr & DSCSR_CDS) == DSCSR_CDS; LOG_TARGET_DEBUG(target, "entered debug state in core mode: %s at PC 0x%" PRIx32 ", cpu in %s state, target->state: %s", arm_mode_name(arm->core_mode), @@ -871,7 +892,7 @@ static int cortex_m_debug_entry(struct target *target) return ERROR_OK; } -static int cortex_m_poll(struct target *target) +static int cortex_m_poll_one(struct target *target) { int detected_failure = ERROR_OK; int retval = ERROR_OK; @@ -934,21 +955,26 @@ static int cortex_m_poll(struct target *target) if ((prev_target_state == TARGET_RUNNING) || (prev_target_state == TARGET_RESET)) { retval = cortex_m_debug_entry(target); - if (retval != ERROR_OK) - return retval; - if (arm_semihosting(target, &retval) != 0) + /* arm_semihosting needs to know registers, don't run if debug entry returned error */ + if (retval == ERROR_OK && arm_semihosting(target, &retval) != 0) return retval; - target_call_event_callbacks(target, TARGET_EVENT_HALTED); + if (target->smp) { + LOG_TARGET_DEBUG(target, "postpone target event 'halted'"); + target->smp_halt_event_postponed = true; + } else { + /* regardless of errors returned in previous code update state */ + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } } if (prev_target_state == TARGET_DEBUG_RUNNING) { retval = cortex_m_debug_entry(target); - if (retval != ERROR_OK) - return retval; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } + if (retval != ERROR_OK) + return retval; } if (target->state == TARGET_UNKNOWN) { @@ -981,8 +1007,106 @@ static int cortex_m_poll(struct target *target) return retval; } -static int cortex_m_halt(struct target *target) +static int cortex_m_halt_one(struct target *target); + +static int cortex_m_smp_halt_all(struct list_head *smp_targets) +{ + int retval = ERROR_OK; + struct target_list *head; + + foreach_smp_target(head, smp_targets) { + struct target *curr = head->target; + if (!target_was_examined(curr)) + continue; + if (curr->state == TARGET_HALTED) + continue; + + int ret2 = cortex_m_halt_one(curr); + if (retval == ERROR_OK) + retval = ret2; /* store the first error code ignore others */ + } + return retval; +} + +static int cortex_m_smp_post_halt_poll(struct list_head *smp_targets) +{ + int retval = ERROR_OK; + struct target_list *head; + + foreach_smp_target(head, smp_targets) { + struct target *curr = head->target; + if (!target_was_examined(curr)) + continue; + /* skip targets that were already halted */ + if (curr->state == TARGET_HALTED) + continue; + + int ret2 = cortex_m_poll_one(curr); + if (retval == ERROR_OK) + retval = ret2; /* store the first error code ignore others */ + } + return retval; +} + +static int cortex_m_poll_smp(struct list_head *smp_targets) +{ + int retval = ERROR_OK; + struct target_list *head; + bool halted = false; + + foreach_smp_target(head, smp_targets) { + struct target *curr = head->target; + if (curr->smp_halt_event_postponed) { + halted = true; + break; + } + } + + if (halted) { + retval = cortex_m_smp_halt_all(smp_targets); + + int ret2 = cortex_m_smp_post_halt_poll(smp_targets); + if (retval == ERROR_OK) + retval = ret2; /* store the first error code ignore others */ + + foreach_smp_target(head, smp_targets) { + struct target *curr = head->target; + if (!curr->smp_halt_event_postponed) + continue; + + curr->smp_halt_event_postponed = false; + if (curr->state == TARGET_HALTED) { + LOG_TARGET_DEBUG(curr, "sending postponed target event 'halted'"); + target_call_event_callbacks(curr, TARGET_EVENT_HALTED); + } + } + /* There is no need to set gdb_service->target + * as hwthread_update_threads() selects an interesting thread + * by its own + */ + } + return retval; +} + +static int cortex_m_poll(struct target *target) +{ + int retval = cortex_m_poll_one(target); + + if (target->smp) { + struct target_list *last; + last = list_last_entry(target->smp_targets, struct target_list, lh); + if (target == last->target) + /* After the last target in SMP group has been polled + * check for postponed halted events and eventually halt and re-poll + * other targets */ + cortex_m_poll_smp(target->smp_targets); + } + return retval; +} + +static int cortex_m_halt_one(struct target *target) { + int retval; LOG_TARGET_DEBUG(target, "target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { @@ -993,22 +1117,8 @@ static int cortex_m_halt(struct target *target) if (target->state == TARGET_UNKNOWN) LOG_TARGET_WARNING(target, "target was in unknown state when halt was requested"); - if (target->state == TARGET_RESET) { - if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { - LOG_TARGET_ERROR(target, "can't request a halt while in reset if nSRST pulls nTRST"); - return ERROR_TARGET_FAILURE; - } else { - /* we came here in a reset_halt or reset_init sequence - * debug entry was already prepared in cortex_m3_assert_reset() - */ - target->debug_reason = DBG_REASON_DBGRQ; - - return ERROR_OK; - } - } - /* Write to Debug Halting Control and Status Register */ - cortex_m_write_debug_halt_mask(target, C_HALT, 0); + retval = cortex_m_write_debug_halt_mask(target, C_HALT, 0); /* Do this really early to minimize the window where the MASKINTS erratum * can pile up pending interrupts. */ @@ -1016,7 +1126,15 @@ static int cortex_m_halt(struct target *target) target->debug_reason = DBG_REASON_DBGRQ; - return ERROR_OK; + return retval; +} + +static int cortex_m_halt(struct target *target) +{ + if (target->smp) + return cortex_m_smp_halt_all(target->smp_targets); + else + return cortex_m_halt_one(target); } static int cortex_m_soft_reset_halt(struct target *target) @@ -1096,8 +1214,8 @@ void cortex_m_enable_breakpoints(struct target *target) } } -static int cortex_m_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) +static int cortex_m_restore_one(struct target *target, bool current, + target_addr_t *address, bool handle_breakpoints, bool debug_execution) { struct armv7m_common *armv7m = target_to_armv7m(target); struct breakpoint *breakpoint = NULL; @@ -1105,7 +1223,7 @@ static int cortex_m_resume(struct target *target, int current, struct reg *r; if (target->state != TARGET_HALTED) { - LOG_TARGET_WARNING(target, "target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1147,7 +1265,7 @@ static int cortex_m_resume(struct target *target, int current, /* current = 1: continue on current pc, otherwise continue at <address> */ r = armv7m->arm.pc; if (!current) { - buf_set_u32(r->value, 0, 32, address); + buf_set_u32(r->value, 0, 32, *address); r->dirty = true; r->valid = true; } @@ -1161,8 +1279,12 @@ static int cortex_m_resume(struct target *target, int current, armv7m_maybe_skip_bkpt_inst(target, NULL); resume_pc = buf_get_u32(r->value, 0, 32); + if (current) + *address = resume_pc; - armv7m_restore_context(target); + int retval = armv7m_restore_context(target); + if (retval != ERROR_OK) + return retval; /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { @@ -1172,34 +1294,99 @@ static int cortex_m_resume(struct target *target, int current, LOG_TARGET_DEBUG(target, "unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")", breakpoint->address, breakpoint->unique_id); - cortex_m_unset_breakpoint(target, breakpoint); - cortex_m_single_step_core(target); - cortex_m_set_breakpoint(target, breakpoint); + retval = cortex_m_unset_breakpoint(target, breakpoint); + if (retval == ERROR_OK) + retval = cortex_m_single_step_core(target); + int ret2 = cortex_m_set_breakpoint(target, breakpoint); + if (retval != ERROR_OK) + return retval; + if (ret2 != ERROR_OK) + return ret2; } } + return ERROR_OK; +} + +static int cortex_m_restart_one(struct target *target, bool debug_execution) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + /* Restart core */ cortex_m_set_maskints_for_run(target); cortex_m_write_debug_halt_mask(target, 0, C_HALT); target->debug_reason = DBG_REASON_NOTHALTED; - /* registers are now invalid */ register_cache_invalidate(armv7m->arm.core_cache); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - LOG_TARGET_DEBUG(target, "target resumed at 0x%" PRIx32 "", resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); - LOG_TARGET_DEBUG(target, "target debug resumed at 0x%" PRIx32 "", resume_pc); } return ERROR_OK; } +static int cortex_m_restore_smp(struct target *target, bool handle_breakpoints) +{ + struct target_list *head; + target_addr_t address; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + /* skip calling target */ + if (curr == target) + continue; + if (!target_was_examined(curr)) + continue; + /* skip running targets */ + if (curr->state == TARGET_RUNNING) + continue; + + int retval = cortex_m_restore_one(curr, true, &address, + handle_breakpoints, false); + if (retval != ERROR_OK) + return retval; + + retval = cortex_m_restart_one(curr, false); + if (retval != ERROR_OK) + return retval; + + LOG_TARGET_DEBUG(curr, "SMP resumed at " TARGET_ADDR_FMT, address); + } + return ERROR_OK; +} + +static int cortex_m_resume(struct target *target, int current, + target_addr_t address, int handle_breakpoints, int debug_execution) +{ + int retval = cortex_m_restore_one(target, !!current, &address, !!handle_breakpoints, !!debug_execution); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "context restore failed, aborting resume"); + return retval; + } + + if (target->smp && !debug_execution) { + retval = cortex_m_restore_smp(target, !!handle_breakpoints); + if (retval != ERROR_OK) + LOG_WARNING("resume of a SMP target failed, trying to resume current one"); + } + + cortex_m_restart_one(target, !!debug_execution); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "resume failed"); + return retval; + } + + LOG_TARGET_DEBUG(target, "%sresumed at " TARGET_ADDR_FMT, + debug_execution ? "debug " : "", address); + + return ERROR_OK; +} + /* int irqstepcount = 0; */ static int cortex_m_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) @@ -1213,10 +1400,15 @@ static int cortex_m_step(struct target *target, int current, bool isr_timed_out = false; if (target->state != TARGET_HALTED) { - LOG_TARGET_WARNING(target, "target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } + /* Just one of SMP cores will step. Set the gdb control + * target to current one or gdb miss gdb-end event */ + if (target->smp && target->gdb_service) + target->gdb_service->target = target; + /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u32(pc->value, 0, 32, address); @@ -1398,8 +1590,9 @@ static int cortex_m_assert_reset(struct target *target) struct armv7m_common *armv7m = &cortex_m->armv7m; enum cortex_m_soft_reset_config reset_config = cortex_m->soft_reset_config; - LOG_TARGET_DEBUG(target, "target->state: %s", - target_state_name(target)); + LOG_TARGET_DEBUG(target, "target->state: %s,%s examined", + target_state_name(target), + target_was_examined(target) ? "" : " not"); enum reset_types jtag_reset_config = jtag_get_reset_config(); @@ -1414,28 +1607,45 @@ static int cortex_m_assert_reset(struct target *target) } /* some cores support connecting while srst is asserted - * use that mode is it has been configured */ + * use that mode if it has been configured */ bool srst_asserted = false; - if (!target_was_examined(target)) { - if (jtag_reset_config & RESET_HAS_SRST) { - adapter_assert_reset(); + if ((jtag_reset_config & RESET_HAS_SRST) && + ((jtag_reset_config & RESET_SRST_NO_GATING) + || (!armv7m->debug_ap && !target->defer_examine))) { + /* If we have no debug_ap, asserting SRST is the only thing + * we can do now */ + adapter_assert_reset(); + srst_asserted = true; + } + + /* TODO: replace the hack calling target_examine_one() + * as soon as a better reset framework is available */ + if (!target_was_examined(target) && !target->defer_examine + && srst_asserted && (jtag_reset_config & RESET_SRST_NO_GATING)) { + LOG_TARGET_DEBUG(target, "Trying to re-examine under reset"); + target_examine_one(target); + } + + /* We need at least debug_ap to go further. + * Inform user and bail out if we don't have one. */ + if (!armv7m->debug_ap) { + if (srst_asserted) { if (target->reset_halt) - LOG_TARGET_ERROR(target, "Target not examined, will not halt after reset!"); + LOG_TARGET_ERROR(target, "Debug AP not available, will not halt after reset!"); + + /* Do not propagate error: reset was asserted, proceed to deassert! */ + target->state = TARGET_RESET; + register_cache_invalidate(cortex_m->armv7m.arm.core_cache); return ERROR_OK; + } else { - LOG_TARGET_ERROR(target, "Target not examined, reset NOT asserted!"); + LOG_TARGET_ERROR(target, "Debug AP not available, reset NOT asserted!"); return ERROR_FAIL; } } - if ((jtag_reset_config & RESET_HAS_SRST) && - (jtag_reset_config & RESET_SRST_NO_GATING)) { - adapter_assert_reset(); - srst_asserted = true; - } - /* Enable debug requests */ int retval = cortex_m_read_dhcsr_atomic_sticky(target); @@ -1483,9 +1693,8 @@ static int cortex_m_assert_reset(struct target *target) /* srst is asserted, ignore AP access errors */ retval = ERROR_OK; } else { - /* Use a standard Cortex-M3 software reset mechanism. - * We default to using VECTRESET as it is supported on all current cores - * (except Cortex-M0, M0+ and M1 which support SYSRESETREQ only!) + /* Use a standard Cortex-M software reset mechanism. + * We default to using VECTRESET. * This has the disadvantage of not resetting the peripherals, so a * reset-init event handler is needed to perform any peripheral resets. */ @@ -1532,25 +1741,16 @@ static int cortex_m_assert_reset(struct target *target) register_cache_invalidate(cortex_m->armv7m.arm.core_cache); - /* now return stored error code if any */ - if (retval != ERROR_OK) - return retval; - - if (target->reset_halt) { - retval = target_halt(target); - if (retval != ERROR_OK) - return retval; - } - - return ERROR_OK; + return retval; } static int cortex_m_deassert_reset(struct target *target) { struct armv7m_common *armv7m = &target_to_cm(target)->armv7m; - LOG_TARGET_DEBUG(target, "target->state: %s", - target_state_name(target)); + LOG_TARGET_DEBUG(target, "target->state: %s,%s examined", + target_state_name(target), + target_was_examined(target) ? "" : " not"); /* deassert reset lines */ adapter_deassert_reset(); @@ -1558,8 +1758,8 @@ static int cortex_m_deassert_reset(struct target *target) enum reset_types jtag_reset_config = jtag_get_reset_config(); if ((jtag_reset_config & RESET_HAS_SRST) && - !(jtag_reset_config & RESET_SRST_NO_GATING) && - target_was_examined(target)) { + !(jtag_reset_config & RESET_SRST_NO_GATING) && + armv7m->debug_ap) { int retval = dap_dp_init_or_reconnect(armv7m->debug_ap->dap); if (retval != ERROR_OK) { @@ -1747,7 +1947,8 @@ static int cortex_m_set_watchpoint(struct target *target, struct watchpoint *wat target_write_u32(target, comparator->dwt_comparator_address + 0, comparator->comp); - if ((cortex_m->dwt_devarch & 0x1FFFFF) != DWT_DEVARCH_ARMV8M) { + if ((cortex_m->dwt_devarch & 0x1FFFFF) != DWT_DEVARCH_ARMV8M_V2_0 + && (cortex_m->dwt_devarch & 0x1FFFFF) != DWT_DEVARCH_ARMV8M_V2_1) { uint32_t mask = 0, temp; /* watchpoint params were validated earlier */ @@ -1845,8 +2046,14 @@ int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - /* hardware doesn't support data value masking */ - if (watchpoint->mask != ~(uint32_t)0) { + /* REVISIT This DWT may well be able to watch for specific data + * values. Requires comparator #1 to set DATAVMATCH and match + * the data, and another comparator (DATAVADDR0) matching addr. + * + * NOTE: hardware doesn't support data value masking, so we'll need + * to check that mask is zero + */ + if (watchpoint->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) { LOG_TARGET_DEBUG(target, "watchpoint value masks not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1867,18 +2074,6 @@ int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - /* Caller doesn't seem to be able to describe watching for data - * values of zero; that flags "no value". - * - * REVISIT This DWT may well be able to watch for specific data - * values. Requires comparator #1 to set DATAVMATCH and match - * the data, and another comparator (DATAVADDR0) matching addr. - */ - if (watchpoint->value) { - LOG_TARGET_DEBUG(target, "data value watchpoint not YET supported"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - cortex_m->dwt_comp_available--; LOG_TARGET_DEBUG(target, "dwt_comp_available: %d", cortex_m->dwt_comp_available); @@ -1891,7 +2086,7 @@ int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpo /* REVISIT why check? DWT can be updated with core running ... */ if (target->state != TARGET_HALTED) { - LOG_TARGET_WARNING(target, "target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1904,7 +2099,7 @@ int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpo return ERROR_OK; } -int cortex_m_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) +static int cortex_m_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) { if (target->debug_reason != DBG_REASON_WATCHPOINT) return ERROR_FAIL; @@ -1984,6 +2179,10 @@ static int cortex_m_init_target(struct command_context *cmd_ctx, void cortex_m_deinit_target(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); + struct armv7m_common *armv7m = target_to_armv7m(target); + + if (!armv7m->is_hla_target && armv7m->debug_ap) + dap_put_ap(armv7m->debug_ap); free(cortex_m->fp_comparator_list); @@ -2248,30 +2447,47 @@ static void cortex_m_dwt_free(struct target *target) cm->dwt_cache = NULL; } -#define MVFR0 0xe000ef40 -#define MVFR1 0xe000ef44 +static bool cortex_m_has_tz(struct target *target) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + uint32_t dauthstatus; + + if (armv7m->arm.arch != ARM_ARCH_V8M) + return false; + + int retval = target_read_u32(target, DAUTHSTATUS, &dauthstatus); + if (retval != ERROR_OK) { + LOG_WARNING("Error reading DAUTHSTATUS register"); + return false; + } + return (dauthstatus & DAUTHSTATUS_SID_MASK) != 0; +} + -#define MVFR0_DEFAULT_M4 0x10110021 -#define MVFR1_DEFAULT_M4 0x11000011 +#define MVFR0 0xE000EF40 +#define MVFR0_SP_MASK 0x000000F0 +#define MVFR0_SP 0x00000020 +#define MVFR0_DP_MASK 0x00000F00 +#define MVFR0_DP 0x00000200 -#define MVFR0_DEFAULT_M7_SP 0x10110021 -#define MVFR0_DEFAULT_M7_DP 0x10110221 -#define MVFR1_DEFAULT_M7_SP 0x11000011 -#define MVFR1_DEFAULT_M7_DP 0x12000011 +#define MVFR1 0xE000EF44 +#define MVFR1_MVE_MASK 0x00000F00 +#define MVFR1_MVE_I 0x00000100 +#define MVFR1_MVE_F 0x00000200 static int cortex_m_find_mem_ap(struct adiv5_dap *swjdp, struct adiv5_ap **debug_ap) { - if (dap_find_ap(swjdp, AP_TYPE_AHB3_AP, debug_ap) == ERROR_OK) + if (dap_find_get_ap(swjdp, AP_TYPE_AHB3_AP, debug_ap) == ERROR_OK) return ERROR_OK; - return dap_find_ap(swjdp, AP_TYPE_AHB5_AP, debug_ap); + return dap_find_get_ap(swjdp, AP_TYPE_AHB5_AP, debug_ap); } int cortex_m_examine(struct target *target) { int retval; - uint32_t cpuid, fpcr, mvfr0, mvfr1; + uint32_t cpuid, fpcr; struct cortex_m_common *cortex_m = target_to_cm(target); struct adiv5_dap *swjdp = cortex_m->armv7m.arm.dap; struct armv7m_common *armv7m = target_to_armv7m(target); @@ -2279,15 +2495,21 @@ int cortex_m_examine(struct target *target) /* hla_target shares the examine handler but does not support * all its calls */ if (!armv7m->is_hla_target) { - if (cortex_m->apsel == DP_APSEL_INVALID) { - /* Search for the MEM-AP */ - retval = cortex_m_find_mem_ap(swjdp, &armv7m->debug_ap); - if (retval != ERROR_OK) { - LOG_TARGET_ERROR(target, "Could not find MEM-AP to control the core"); - return retval; + if (!armv7m->debug_ap) { + if (cortex_m->apsel == DP_APSEL_INVALID) { + /* Search for the MEM-AP */ + retval = cortex_m_find_mem_ap(swjdp, &armv7m->debug_ap); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "Could not find MEM-AP to control the core"); + return retval; + } + } else { + armv7m->debug_ap = dap_get_ap(swjdp, cortex_m->apsel); + if (!armv7m->debug_ap) { + LOG_ERROR("Cannot get AP"); + return ERROR_FAIL; + } } - } else { - armv7m->debug_ap = dap_ap(swjdp, cortex_m->apsel); } armv7m->debug_ap->memaccess_tck = 8; @@ -2305,18 +2527,18 @@ int cortex_m_examine(struct target *target) if (retval != ERROR_OK) return retval; - /* Get ARCH and CPU types */ - const enum cortex_m_partno core_partno = (cpuid & ARM_CPUID_PARTNO_MASK) >> ARM_CPUID_PARTNO_POS; + /* Inspect implementor/part to look for recognized cores */ + unsigned int impl_part = cpuid & (ARM_CPUID_IMPLEMENTOR_MASK | ARM_CPUID_PARTNO_MASK); for (unsigned int n = 0; n < ARRAY_SIZE(cortex_m_parts); n++) { - if (core_partno == cortex_m_parts[n].partno) { + if (impl_part == cortex_m_parts[n].impl_part) { cortex_m->core_info = &cortex_m_parts[n]; break; } } if (!cortex_m->core_info) { - LOG_TARGET_ERROR(target, "Cortex-M PARTNO 0x%x is unrecognized", core_partno); + LOG_TARGET_ERROR(target, "Cortex-M CPUID: 0x%x is unrecognized", cpuid); return ERROR_FAIL; } @@ -2328,7 +2550,7 @@ int cortex_m_examine(struct target *target) (uint8_t)((cpuid >> 0) & 0xf)); cortex_m->maskints_erratum = false; - if (core_partno == CORTEX_M7_PARTNO) { + if (impl_part == CORTEX_M7_PARTNO) { uint8_t rev, patch; rev = (cpuid >> 20) & 0xf; patch = (cpuid >> 0) & 0xf; @@ -2340,25 +2562,37 @@ int cortex_m_examine(struct target *target) LOG_TARGET_DEBUG(target, "cpuid: 0x%8.8" PRIx32 "", cpuid); if (cortex_m->core_info->flags & CORTEX_M_F_HAS_FPV4) { + uint32_t mvfr0; target_read_u32(target, MVFR0, &mvfr0); - target_read_u32(target, MVFR1, &mvfr1); - /* test for floating point feature on Cortex-M4 */ - if ((mvfr0 == MVFR0_DEFAULT_M4) && (mvfr1 == MVFR1_DEFAULT_M4)) { - LOG_TARGET_DEBUG(target, "%s floating point feature FPv4_SP found", cortex_m->core_info->name); + if ((mvfr0 & MVFR0_SP_MASK) == MVFR0_SP) { + LOG_TARGET_DEBUG(target, "%s floating point feature FPv4_SP found", + cortex_m->core_info->name); armv7m->fp_feature = FPV4_SP; } } else if (cortex_m->core_info->flags & CORTEX_M_F_HAS_FPV5) { + uint32_t mvfr0, mvfr1; target_read_u32(target, MVFR0, &mvfr0); target_read_u32(target, MVFR1, &mvfr1); - /* test for floating point features on Cortex-M7 */ - if ((mvfr0 == MVFR0_DEFAULT_M7_SP) && (mvfr1 == MVFR1_DEFAULT_M7_SP)) { - LOG_TARGET_DEBUG(target, "%s floating point feature FPv5_SP found", cortex_m->core_info->name); + if ((mvfr0 & MVFR0_DP_MASK) == MVFR0_DP) { + if ((mvfr1 & MVFR1_MVE_MASK) == MVFR1_MVE_F) { + LOG_TARGET_DEBUG(target, "%s floating point feature FPv5_DP + MVE-F found", + cortex_m->core_info->name); + armv7m->fp_feature = FPV5_MVE_F; + } else { + LOG_TARGET_DEBUG(target, "%s floating point feature FPv5_DP found", + cortex_m->core_info->name); + armv7m->fp_feature = FPV5_DP; + } + } else if ((mvfr0 & MVFR0_SP_MASK) == MVFR0_SP) { + LOG_TARGET_DEBUG(target, "%s floating point feature FPv5_SP found", + cortex_m->core_info->name); armv7m->fp_feature = FPV5_SP; - } else if ((mvfr0 == MVFR0_DEFAULT_M7_DP) && (mvfr1 == MVFR1_DEFAULT_M7_DP)) { - LOG_TARGET_DEBUG(target, "%s floating point feature FPv5_DP found", cortex_m->core_info->name); - armv7m->fp_feature = FPV5_DP; + } else if ((mvfr1 & MVFR1_MVE_MASK) == MVFR1_MVE_I) { + LOG_TARGET_DEBUG(target, "%s floating point feature MVE-I found", + cortex_m->core_info->name); + armv7m->fp_feature = FPV5_MVE_I; } } @@ -2370,7 +2604,7 @@ int cortex_m_examine(struct target *target) for (size_t idx = ARMV7M_FPU_FIRST_REG; idx <= ARMV7M_FPU_LAST_REG; idx++) armv7m->arm.core_cache->reg_list[idx].exist = false; - if (armv7m->arm.arch != ARM_ARCH_V8M) + if (!cortex_m_has_tz(target)) for (size_t idx = ARMV8M_FIRST_REG; idx <= ARMV8M_LAST_REG; idx++) armv7m->arm.core_cache->reg_list[idx].exist = false; @@ -2384,6 +2618,20 @@ int cortex_m_examine(struct target *target) retval = target_read_u32(target, DCB_DHCSR, &cortex_m->dcb_dhcsr); if (retval != ERROR_OK) return retval; + + /* Don't cumulate sticky S_RESET_ST at the very first read of DHCSR + * as S_RESET_ST may indicate a reset that happened long time ago + * (most probably the power-on reset before OpenOCD was started). + * As we are just initializing the debug system we do not need + * to call cortex_m_endreset_event() in the following poll. + */ + if (!cortex_m->dcb_dhcsr_sticky_is_recent) { + cortex_m->dcb_dhcsr_sticky_is_recent = true; + if (cortex_m->dcb_dhcsr & S_RESET_ST) { + LOG_TARGET_DEBUG(target, "reset happened some time ago, ignore"); + cortex_m->dcb_dhcsr &= ~S_RESET_ST; + } + } cortex_m_cumulate_dhcsr_sticky(cortex_m, cortex_m->dcb_dhcsr); if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) { @@ -2536,7 +2784,7 @@ static int cortex_m_init_arch_info(struct target *target, armv7m_init_arch_info(target, armv7m); /* default reset mode is to use srst if fitted - * if not it will use CORTEX_M3_RESET_VECTRESET */ + * if not it will use CORTEX_M_RESET_VECTRESET */ cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET; armv7m->arm.dap = dap; @@ -2593,8 +2841,7 @@ static int cortex_m_verify_pointer(struct command_invocation *cmd, /* * Only stuff below this line should need to verify that its target - * is a Cortex-M3. Everything else should have indirected through the - * cortexm3_target structure, which is only used with CM3 targets. + * is a Cortex-M with available DAP access (not a HLA adapter). */ COMMAND_HANDLER(handle_cortex_m_vector_catch_command) @@ -2653,7 +2900,7 @@ COMMAND_HANDLER(handle_cortex_m_vector_catch_command) break; } if (i == ARRAY_SIZE(vec_ids)) { - LOG_TARGET_ERROR(target, "No CM3 vector '%s'", CMD_ARGV[CMD_ARGC]); + LOG_TARGET_ERROR(target, "No Cortex-M vector '%s'", CMD_ARGV[CMD_ARGC]); return ERROR_COMMAND_SYNTAX_ERROR; } } @@ -2692,14 +2939,14 @@ COMMAND_HANDLER(handle_cortex_m_mask_interrupts_command) struct cortex_m_common *cortex_m = target_to_cm(target); int retval; - static const struct jim_nvp nvp_maskisr_modes[] = { + static const struct nvp nvp_maskisr_modes[] = { { .name = "auto", .value = CORTEX_M_ISRMASK_AUTO }, { .name = "off", .value = CORTEX_M_ISRMASK_OFF }, { .name = "on", .value = CORTEX_M_ISRMASK_ON }, { .name = "steponly", .value = CORTEX_M_ISRMASK_STEPONLY }, { .name = NULL, .value = -1 }, }; - const struct jim_nvp *n; + const struct nvp *n; retval = cortex_m_verify_pointer(CMD, cortex_m); @@ -2707,19 +2954,19 @@ COMMAND_HANDLER(handle_cortex_m_mask_interrupts_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } if (CMD_ARGC > 0) { - n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); + n = nvp_name2value(nvp_maskisr_modes, CMD_ARGV[0]); if (!n->name) return ERROR_COMMAND_SYNTAX_ERROR; cortex_m->isrmasking_mode = n->value; cortex_m_set_maskints_for_halt(target); } - n = jim_nvp_value2name_simple(nvp_maskisr_modes, cortex_m->isrmasking_mode); + n = nvp_value2name(nvp_maskisr_modes, cortex_m->isrmasking_mode); command_print(CMD, "cortex_m interrupt mask %s", n->name); return ERROR_OK; @@ -2792,6 +3039,9 @@ static const struct command_registration cortex_m_exec_command_handlers[] = { .help = "configure software reset handling", .usage = "['sysresetreq'|'vectreset']", }, + { + .chain = smp_command_handlers, + }, COMMAND_REGISTRATION_DONE }; static const struct command_registration cortex_m_command_handlers[] = { diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index 5554014162..a585b786b9 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_CORTEX_M_H @@ -28,7 +17,7 @@ #include "armv7m.h" #include "helper/bits.h" -#define CORTEX_M_COMMON_MAGIC 0x1A451A45 +#define CORTEX_M_COMMON_MAGIC 0x1A451A45U #define SYSTEM_CONTROL_BASE 0x400FE000 @@ -42,21 +31,35 @@ #define CPUID 0xE000ED00 -#define ARM_CPUID_PARTNO_POS 4 -#define ARM_CPUID_PARTNO_MASK (0xFFF << ARM_CPUID_PARTNO_POS) +#define ARM_CPUID_IMPLEMENTOR_POS 24 +#define ARM_CPUID_IMPLEMENTOR_MASK (0xFF << ARM_CPUID_IMPLEMENTOR_POS) +#define ARM_CPUID_PARTNO_POS 4 +#define ARM_CPUID_PARTNO_MASK (0xFFF << ARM_CPUID_PARTNO_POS) + +#define ARM_MAKE_CPUID(impl, partno) ((((impl) << ARM_CPUID_IMPLEMENTOR_POS) & ARM_CPUID_IMPLEMENTOR_MASK) | \ + (((partno) << ARM_CPUID_PARTNO_POS) & ARM_CPUID_PARTNO_MASK)) -enum cortex_m_partno { +/** Known Arm Cortex masked CPU Ids + * This includes the implementor and part number, but _not_ the revision or + * patch fields. + */ +enum cortex_m_impl_part { CORTEX_M_PARTNO_INVALID, - CORTEX_M0_PARTNO = 0xC20, - CORTEX_M1_PARTNO = 0xC21, - CORTEX_M3_PARTNO = 0xC23, - CORTEX_M4_PARTNO = 0xC24, - CORTEX_M7_PARTNO = 0xC27, - CORTEX_M0P_PARTNO = 0xC60, - CORTEX_M23_PARTNO = 0xD20, - CORTEX_M33_PARTNO = 0xD21, - CORTEX_M35P_PARTNO = 0xD31, - CORTEX_M55_PARTNO = 0xD22, + STAR_MC1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0x132), /* FIXME - confirm implementor! */ + CORTEX_M0_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC20), + CORTEX_M1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC21), + CORTEX_M3_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC23), + CORTEX_M4_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC24), + CORTEX_M7_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC27), + CORTEX_M0P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC60), + CORTEX_M23_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD20), + CORTEX_M33_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD21), + CORTEX_M35P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD31), + CORTEX_M55_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD22), + CORTEX_M85_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD23), + INFINEON_SLX2_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_INFINEON, 0xDB0), + REALTEK_M200_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd20), + REALTEK_M300_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd22), }; /* Relevant Cortex-M flags, used in struct cortex_m_part_info.flags */ @@ -65,7 +68,7 @@ enum cortex_m_partno { #define CORTEX_M_F_TAR_AUTOINCR_BLOCK_4K BIT(2) struct cortex_m_part_info { - enum cortex_m_partno partno; + enum cortex_m_impl_part impl_part; const char *name; enum arm_arch arch; uint32_t flags; @@ -78,6 +81,9 @@ struct cortex_m_part_info { #define DCB_DEMCR 0xE000EDFC #define DCB_DSCSR 0xE000EE08 +#define DAUTHSTATUS 0xE000EFB8 +#define DAUTHSTATUS_SID_MASK 0x00000030 + #define DCRSR_WNR BIT(16) #define DWT_CTRL 0xE0001000 @@ -88,7 +94,8 @@ struct cortex_m_part_info { #define DWT_FUNCTION0 0xE0001028 #define DWT_DEVARCH 0xE0001FBC -#define DWT_DEVARCH_ARMV8M 0x101A02 +#define DWT_DEVARCH_ARMV8M_V2_0 0x101A02 +#define DWT_DEVARCH_ARMV8M_V2_1 0x111A02 #define FP_CTRL 0xE0002000 #define FP_REMAP 0xE0002004 @@ -210,11 +217,15 @@ enum cortex_m_isrmasking_mode { }; struct cortex_m_common { - int common_magic; + unsigned int common_magic; + + struct armv7m_common armv7m; /* Context information */ uint32_t dcb_dhcsr; uint32_t dcb_dhcsr_cumulated_sticky; + /* DCB DHCSR has been at least once read, so the sticky bits have been reset */ + bool dcb_dhcsr_sticky_is_recent; uint32_t nvic_dfsr; /* Debug Fault Status Register - shows reason for debug halt */ uint32_t nvic_icsr; /* Interrupt Control State Register - shows active and pending IRQ */ @@ -237,11 +248,10 @@ struct cortex_m_common { enum cortex_m_isrmasking_mode isrmasking_mode; const struct cortex_m_part_info *core_info; - struct armv7m_common armv7m; bool slow_register_read; /* A register has not been ready, poll S_REGRDY */ - int apsel; + uint64_t apsel; /* Whether this target has the erratum that makes C_MASKINTS not apply to * already pending interrupts */ @@ -296,11 +306,11 @@ target_to_cortex_m_safe(struct target *target) } /** - * @returns cached value of Cortex-M part number + * @returns cached value of the cpuid, masked for implementation and part. * or CORTEX_M_PARTNO_INVALID if the magic number does not match * or core_info is not initialised. */ -static inline enum cortex_m_partno cortex_m_get_partno_safe(struct target *target) +static inline enum cortex_m_impl_part cortex_m_get_impl_part(struct target *target) { struct cortex_m_common *cortex_m = target_to_cortex_m_safe(target); if (!cortex_m) @@ -309,7 +319,7 @@ static inline enum cortex_m_partno cortex_m_get_partno_safe(struct target *targe if (!cortex_m->core_info) return CORTEX_M_PARTNO_INVALID; - return cortex_m->core_info->partno; + return cortex_m->core_info->impl_part; } int cortex_m_examine(struct target *target); diff --git a/src/target/dsp563xx.c b/src/target/dsp563xx.c index fdec95faf2..1e7180318a 100644 --- a/src/target/dsp563xx.c +++ b/src/target/dsp563xx.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009-2011 by Mathias Kuester * * mkdorg@users.sourceforge.net * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -923,7 +912,7 @@ static int dsp563xx_examine(struct target *target) { uint32_t chip; - if (target->tap->hasidcode == false) { + if (!target->tap->has_idcode) { LOG_ERROR("no IDCODE present on device"); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -1307,7 +1296,7 @@ static int dsp563xx_step(struct target *target, struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1385,14 +1374,14 @@ static int dsp563xx_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, - int timeout_ms, void *arch_info) + unsigned int timeout_ms, void *arch_info) { int i; int retval = ERROR_OK; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted (run target algo)"); return ERROR_TARGET_NOT_HALTED; } @@ -1716,7 +1705,7 @@ static int dsp563xx_write_memory_core(struct target *target, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2151,7 +2140,7 @@ COMMAND_HANDLER(dsp563xx_mem_command) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], count); } - buffer = calloc(count, sizeof(uint32_t)); + buffer = calloc(count, 4); if (read_mem == 1) { err = dsp563xx_read_memory(target, mem_type, address, sizeof(uint32_t), diff --git a/src/target/dsp563xx.h b/src/target/dsp563xx.h index 5c3e1d3c76..9468bf3054 100644 --- a/src/target/dsp563xx.h +++ b/src/target/dsp563xx.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009-2011 by Mathias Kuester * * mkdorg@users.sourceforge.net * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_DSP563XX_H diff --git a/src/target/dsp563xx_once.c b/src/target/dsp563xx_once.c index 624474d1b6..866f33152d 100644 --- a/src/target/dsp563xx_once.c +++ b/src/target/dsp563xx_once.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 by Mathias Kuester * * mkdorg@users.sourceforge.net * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -71,7 +60,7 @@ static inline int dsp563xx_once_ir_exec(struct jtag_tap *tap, int flush, uint8_t { int err; - err = dsp563xx_write_dr_u8(tap, 0, instr | (ex << 5) | (go << 6) | (rw << 7), 8, 0); + err = dsp563xx_write_dr_u8(tap, NULL, instr | (ex << 5) | (go << 6) | (rw << 7), 8, 0); if (err != ERROR_OK) return err; if (flush) @@ -237,7 +226,7 @@ int dsp563xx_once_reg_write(struct jtag_tap *tap, int flush, uint8_t reg, uint32 err = dsp563xx_once_ir_exec(tap, flush, reg, 0, 0, 0); if (err != ERROR_OK) return err; - err = dsp563xx_write_dr_u32(tap, 0x00, data, 24, 0); + err = dsp563xx_write_dr_u32(tap, NULL, data, 24, 0); if (err != ERROR_OK) return err; if (flush) @@ -253,7 +242,7 @@ int dsp563xx_once_execute_sw_ir(struct jtag_tap *tap, int flush, uint32_t opcode err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 1, 0); if (err != ERROR_OK) return err; - err = dsp563xx_write_dr_u32(tap, 0, opcode, 24, 0); + err = dsp563xx_write_dr_u32(tap, NULL, opcode, 24, 0); if (err != ERROR_OK) return err; if (flush) @@ -269,7 +258,7 @@ int dsp563xx_once_execute_dw_ir(struct jtag_tap *tap, int flush, uint32_t opcode err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 0, 0); if (err != ERROR_OK) return err; - err = dsp563xx_write_dr_u32(tap, 0, opcode, 24, 0); + err = dsp563xx_write_dr_u32(tap, NULL, opcode, 24, 0); if (err != ERROR_OK) return err; if (flush) { @@ -281,7 +270,7 @@ int dsp563xx_once_execute_dw_ir(struct jtag_tap *tap, int flush, uint32_t opcode err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 1, 0); if (err != ERROR_OK) return err; - err = dsp563xx_write_dr_u32(tap, 0, operand, 24, 0); + err = dsp563xx_write_dr_u32(tap, NULL, operand, 24, 0); if (err != ERROR_OK) return err; if (flush) { diff --git a/src/target/dsp563xx_once.h b/src/target/dsp563xx_once.h index 811c08698e..8715488374 100644 --- a/src/target/dsp563xx_once.h +++ b/src/target/dsp563xx_once.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2009 by Mathias Kuester * * mkdorg@users.sourceforge.net * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_DSP563XX_ONCE_H diff --git a/src/target/dsp5680xx.c b/src/target/dsp5680xx.c index 939b09d36a..c90bca3c1f 100644 --- a/src/target/dsp5680xx.c +++ b/src/target/dsp5680xx.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Rodrigo L. Rosa * * rodrigorosa.LG@gmail.com * * * * Based on dsp563xx_once.h written by Mathias Kuester * * mkdorg@users.sourceforge.net * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -27,7 +16,7 @@ #include "target_type.h" #include "dsp5680xx.h" -struct dsp5680xx_common dsp5680xx_context; +static struct dsp5680xx_common dsp5680xx_context; #define _E "DSP5680XX_ERROR:%d\nAt:%s:%d:%s" #define err_check(r, c, m) if (r != ERROR_OK) {LOG_ERROR(_E, c, __func__, __LINE__, m); return r; } @@ -2211,8 +2200,8 @@ int dsp5680xx_f_lock(struct target *target) struct jtag_tap *tap_chp; struct jtag_tap *tap_cpu; - uint16_t lock_word[] = { HFM_LOCK_FLASH }; - retval = dsp5680xx_f_wr(target, (uint8_t *) (lock_word), HFM_LOCK_ADDR_L, 2, 1); + uint16_t lock_word = HFM_LOCK_FLASH; + retval = dsp5680xx_f_wr(target, (uint8_t *)&lock_word, HFM_LOCK_ADDR_L, 2, 1); err_check_propagate(retval); jtag_add_reset(0, 1); diff --git a/src/target/dsp5680xx.h b/src/target/dsp5680xx.h index b969417f80..152f446977 100644 --- a/src/target/dsp5680xx.h +++ b/src/target/dsp5680xx.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Rodrigo L. Rosa * * rodrigorosa.LG@gmail.com * * * * Based on dsp563xx_once.h written by Mathias Kuester * * mkdorg@users.sourceforge.net * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_DSP5680XX_H @@ -289,8 +278,6 @@ struct dsp5680xx_common { bool debug_mode_enabled; }; -extern struct dsp5680xx_common dsp5680xx_context; - static inline struct dsp5680xx_common *target_to_dsp5680xx(struct target *target) { diff --git a/src/target/embeddedice.c b/src/target/embeddedice.c index a29508baf3..7aef153b58 100644 --- a/src/target/embeddedice.c +++ b/src/target/embeddedice.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/embeddedice.h b/src/target/embeddedice.h index f57f141aa2..32acd705a5 100644 --- a/src/target/embeddedice.h +++ b/src/target/embeddedice.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005, 2006 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_EMBEDDEDICE_H diff --git a/src/target/esirisc.c b/src/target/esirisc.c index aadd111ee1..0f76b5982e 100644 --- a/src/target/esirisc.c +++ b/src/target/esirisc.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * * James Zhao <hjz@squareup.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -329,8 +318,10 @@ static int esirisc_flush_caches(struct target *target) LOG_DEBUG("-"); - if (target->state != TARGET_HALTED) + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; + } int retval = esirisc_jtag_flush_caches(jtag_info); if (retval != ERROR_OK) { @@ -866,8 +857,10 @@ static int esirisc_resume_or_step(struct target *target, int current, target_add LOG_DEBUG("-"); - if (target->state != TARGET_HALTED) + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; + } if (!debug_execution) { target_free_all_working_areas(target); @@ -1255,7 +1248,7 @@ static int esirisc_arch_state(struct target *target) return ERROR_OK; } -static const char *esirisc_get_gdb_arch(struct target *target) +static const char *esirisc_get_gdb_arch(const struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); @@ -1493,6 +1486,32 @@ static struct reg_cache *esirisc_build_reg_cache(struct target *target) return cache; } +static void esirisc_free_reg_cache(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + struct reg_cache *cache = esirisc->reg_cache; + struct reg *reg_list = cache->reg_list; + + for (int i = 0; i < esirisc->num_regs; ++i) { + struct reg *reg = reg_list + esirisc_regs[i].number; + + free(reg->arch_info); + free(reg->value); + free(reg->reg_data_type); + } + + for (size_t i = 0; i < ARRAY_SIZE(esirisc_csrs); ++i) { + struct reg *reg = reg_list + esirisc_csrs[i].number; + + free(reg->arch_info); + free(reg->value); + free(reg->reg_data_type); + } + + free(reg_list); + free(cache); +} + static int esirisc_identify(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); @@ -1591,6 +1610,19 @@ static int esirisc_init_target(struct command_context *cmd_ctx, struct target *t return ERROR_OK; } +static void esirisc_deinit_target(struct target *target) +{ + struct esirisc_common *esirisc = target_to_esirisc(target); + + if (!target_was_examined(target)) + return; + + esirisc_free_reg_cache(target); + + free(esirisc->gdb_arch); + free(esirisc); +} + static int esirisc_examine(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); @@ -1829,5 +1861,6 @@ struct target_type esirisc_target = { .target_create = esirisc_target_create, .init_target = esirisc_init_target, + .deinit_target = esirisc_deinit_target, .examine = esirisc_examine, }; diff --git a/src/target/esirisc.h b/src/target/esirisc.h index ad14223ad2..6f8cd14722 100644 --- a/src/target/esirisc.h +++ b/src/target/esirisc.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * * James Zhao <hjz@squareup.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ESIRISC_H @@ -117,7 +106,7 @@ struct esirisc_reg { int (*write)(struct reg *reg); }; -static inline struct esirisc_common *target_to_esirisc(struct target *target) +static inline struct esirisc_common *target_to_esirisc(const struct target *target) { return (struct esirisc_common *)target->arch_info; } diff --git a/src/target/esirisc_jtag.c b/src/target/esirisc_jtag.c index dd5cd5a0ee..1ec1726e5c 100644 --- a/src/target/esirisc_jtag.c +++ b/src/target/esirisc_jtag.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * * James Zhao <hjz@squareup.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -141,7 +130,9 @@ static int esirisc_jtag_recv(struct esirisc_jtag *jtag_info, int num_in_bytes = DIV_ROUND_UP(num_in_bits, 8); struct scan_field fields[3]; - uint8_t r[num_in_bytes * 2]; + /* prevent zero-size variable length array */ + int r_size = num_in_bytes ? num_in_bytes * 2 : 1; + uint8_t r[r_size]; esirisc_jtag_set_instr(jtag_info, INSTR_DEBUG); diff --git a/src/target/esirisc_jtag.h b/src/target/esirisc_jtag.h index 5f8fe66b0d..98ec8af8d6 100644 --- a/src/target/esirisc_jtag.h +++ b/src/target/esirisc_jtag.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * * James Zhao <hjz@squareup.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ESIRISC_JTAG_H diff --git a/src/target/esirisc_regs.h b/src/target/esirisc_regs.h index 6ccda500b3..51e7e6188d 100644 --- a/src/target/esirisc_regs.h +++ b/src/target/esirisc_regs.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * * James Zhao <hjz@squareup.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ESIRISC_REGS_H diff --git a/src/target/esirisc_trace.c b/src/target/esirisc_trace.c index d17a65d63a..376ea1db74 100644 --- a/src/target/esirisc_trace.c +++ b/src/target/esirisc_trace.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/esirisc_trace.h b/src/target/esirisc_trace.h index c3cc6e9918..9c08d96b49 100644 --- a/src/target/esirisc_trace.h +++ b/src/target/esirisc_trace.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2018 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ESIRISC_TRACE_H diff --git a/src/target/espressif/Makefile.am b/src/target/espressif/Makefile.am new file mode 100644 index 0000000000..cf82ee995e --- /dev/null +++ b/src/target/espressif/Makefile.am @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +noinst_LTLIBRARIES += %D%/libespressif.la +%C%_libespressif_la_SOURCES = \ + %D%/esp_xtensa.c \ + %D%/esp_xtensa.h \ + %D%/esp_xtensa_smp.c \ + %D%/esp_xtensa_smp.h \ + %D%/esp_xtensa_semihosting.c \ + %D%/esp_xtensa_semihosting.h \ + %D%/esp_xtensa_apptrace.c \ + %D%/esp_xtensa_apptrace.h \ + %D%/esp_xtensa_algorithm.c \ + %D%/esp_xtensa_algorithm.h \ + %D%/esp32_apptrace.c \ + %D%/esp32_apptrace.h \ + %D%/esp32.c \ + %D%/esp32s2.c \ + %D%/esp32s3.c \ + %D%/esp.c \ + %D%/esp.h \ + %D%/esp32_sysview.c \ + %D%/esp32_sysview.h \ + %D%/segger_sysview.h \ + %D%/esp_semihosting.c \ + %D%/esp_semihosting.h \ + %D%/esp_algorithm.c \ + %D%/esp_algorithm.h diff --git a/src/target/espressif/esp.c b/src/target/espressif/esp.c new file mode 100644 index 0000000000..600f6d7e99 --- /dev/null +++ b/src/target/espressif/esp.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Espressif chips common target API for OpenOCD * + * Copyright (C) 2021 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/log.h> +#include <helper/binarybuffer.h> +#include "target/target.h" +#include "esp.h" + +int esp_common_init(struct esp_common *esp, const struct esp_algorithm_hw *algo_hw) +{ + if (!esp) + return ERROR_FAIL; + + esp->algo_hw = algo_hw; + + return ERROR_OK; +} + +int esp_dbgstubs_table_read(struct target *target, struct esp_dbg_stubs *dbg_stubs) +{ + uint32_t table_size, table_start_id, desc_entry_id, gcov_entry_id; + uint32_t entries[ESP_DBG_STUB_ENTRY_MAX] = {0}; + uint8_t entry_buff[sizeof(entries)] = {0}; /* to avoid endiannes issues */ + + LOG_TARGET_DEBUG(target, "Read debug stubs info %" PRIx32 " / %d", dbg_stubs->base, dbg_stubs->entries_count); + + /* First of, read 2 entries to get magic num and table size */ + int res = target_read_buffer(target, dbg_stubs->base, sizeof(uint32_t) * 2, entry_buff); + if (res != ERROR_OK) { + LOG_ERROR("%s: Failed to read first debug stub entry!", target_name(target)); + return res; + } + entries[0] = target_buffer_get_u32(target, entry_buff); + entries[1] = target_buffer_get_u32(target, entry_buff + sizeof(uint32_t)); + + if (entries[0] != ESP_DBG_STUB_MAGIC_NUM_VAL) { + /* idf with the old table entry structure */ + table_size = 2; + table_start_id = 0; + desc_entry_id = 0; + gcov_entry_id = 1; + } else { + table_size = entries[1]; + table_start_id = ESP_DBG_STUB_TABLE_START; + desc_entry_id = ESP_DBG_STUB_TABLE_START; + gcov_entry_id = ESP_DBG_STUB_ENTRY_FIRST; + + /* discard unsupported entries */ + if (table_size > ESP_DBG_STUB_ENTRY_MAX) + table_size = ESP_DBG_STUB_ENTRY_MAX; + + /* now read the remaining entries */ + res = target_read_buffer(target, dbg_stubs->base + 2 * sizeof(uint32_t), sizeof(uint32_t) * table_size - 2, + entry_buff + sizeof(uint32_t) * 2); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read debug stubs info!"); + return res; + } + for (unsigned int i = 2; i < table_size; ++i) + entries[i] = target_buffer_get_u32(target, entry_buff + sizeof(uint32_t) * i); + + dbg_stubs->entries[ESP_DBG_STUB_CAPABILITIES] = entries[ESP_DBG_STUB_CAPABILITIES]; + } + + dbg_stubs->entries[ESP_DBG_STUB_DESC] = entries[desc_entry_id]; + dbg_stubs->entries[ESP_DBG_STUB_ENTRY_GCOV] = entries[gcov_entry_id]; + + for (enum esp_dbg_stub_id i = ESP_DBG_STUB_DESC; i < ESP_DBG_STUB_ENTRY_MAX; i++) { + LOG_DEBUG("Check dbg stub %d - %x", i, dbg_stubs->entries[i]); + if (dbg_stubs->entries[i]) { + LOG_DEBUG("New dbg stub %d at %x", dbg_stubs->entries_count, dbg_stubs->entries[i]); + dbg_stubs->entries_count++; + } + } + if (dbg_stubs->entries_count < table_size - table_start_id) + LOG_WARNING("Not full dbg stub table %d of %d", dbg_stubs->entries_count, table_size - table_start_id); + + return ERROR_OK; +} diff --git a/src/target/espressif/esp.h b/src/target/espressif/esp.h new file mode 100644 index 0000000000..6e0a2d2d35 --- /dev/null +++ b/src/target/espressif/esp.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Espressif chips common target API for OpenOCD * + * Copyright (C) 2021 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESP_H +#define OPENOCD_TARGET_ESP_H + +#include <stdint.h> +#include <helper/bits.h> + +/* must be in sync with ESP-IDF version */ +/** Size of the pre-compiled target buffer for stub trampoline. + * @note Must be in sync with ESP-IDF version */ +#define ESP_DBG_STUBS_CODE_BUF_SIZE 32 /* TODO: move this info to esp_dbg_stubs_desc */ +/** Size of the pre-compiled target buffer for stack. + * @note Must be in sync with ESP-IDF version */ +#define ESP_DBG_STUBS_STACK_MIN_SIZE 2048/* TODO: move this info to esp_dbg_stubs_desc */ + +/** + * Debug stubs table entries IDs + * + * @note Must be in sync with ESP-IDF version + */ +enum esp_dbg_stub_id { + ESP_DBG_STUB_ENTRY_MAGIC_NUM, + ESP_DBG_STUB_TABLE_SIZE, + ESP_DBG_STUB_TABLE_START, + ESP_DBG_STUB_DESC = ESP_DBG_STUB_TABLE_START, /*< Stubs descriptor ID */ + ESP_DBG_STUB_ENTRY_FIRST, + ESP_DBG_STUB_ENTRY_GCOV = ESP_DBG_STUB_ENTRY_FIRST, /*< GCOV stub ID */ + ESP_DBG_STUB_CAPABILITIES, + /* add new stub entries here */ + ESP_DBG_STUB_ENTRY_MAX, +}; + +#define ESP_DBG_STUB_MAGIC_NUM_VAL 0xFEEDBEEF +#define ESP_DBG_STUB_CAP_GCOV_THREAD BIT(0) + +/** + * Debug stubs descriptor. ID: ESP_DBG_STUB_DESC + * + * @note Must be in sync with ESP-IDF version + */ +struct esp_dbg_stubs_desc { + /** Address of pre-compiled target buffer for stub trampoline. + * Size of the buffer is ESP_DBG_STUBS_CODE_BUF_SIZE + */ + uint32_t tramp_addr; + /** Pre-compiled target buffer's addr for stack. The size of the buffer is ESP_DBG_STUBS_STACK_MIN_SIZE. + * Target has the buffer which is used for the stack of onboard algorithms. + * If stack size required by algorithm exceeds ESP_DBG_STUBS_STACK_MIN_SIZE, + * it should be allocated using onboard function pointed by 'data_alloc' and + * freed by 'data_free'. They fit to the minimal stack. See below. + */ + uint32_t min_stack_addr; + /** Address of malloc-like function to allocate buffer on target. */ + uint32_t data_alloc; + /** Address of free-like function to free buffer allocated with data_alloc. */ + uint32_t data_free; +}; + +/** + * Debug stubs info. + */ +struct esp_dbg_stubs { + /** Address. */ + uint32_t base; + /** Table contents. */ + uint32_t entries[ESP_DBG_STUB_ENTRY_MAX]; + /** Number of table entries. */ + uint32_t entries_count; + /** Debug stubs decsriptor. */ + struct esp_dbg_stubs_desc desc; +}; + +struct esp_common { + const struct esp_algorithm_hw *algo_hw; + struct esp_dbg_stubs dbg_stubs; +}; + +int esp_common_init(struct esp_common *esp, const struct esp_algorithm_hw *algo_hw); +int esp_dbgstubs_table_read(struct target *target, struct esp_dbg_stubs *dbg_stubs); + +#endif /* OPENOCD_TARGET_ESP_H */ diff --git a/src/target/espressif/esp32.c b/src/target/espressif/esp32.c new file mode 100644 index 0000000000..324aa3993b --- /dev/null +++ b/src/target/espressif/esp32.c @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * ESP32 target API for OpenOCD * + * Copyright (C) 2016-2019 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/time_support.h> +#include <target/target.h> +#include <target/target_type.h> +#include <target/smp.h> +#include <target/semihosting_common.h> +#include "assert.h" +#include "esp_xtensa_smp.h" + +/* +This is a JTAG driver for the ESP32, the are two Tensilica cores inside +the ESP32 chip. For more information please have a look into ESP32 target +implementation. +*/ + +/* ESP32 memory map */ +#define ESP32_RTC_DATA_LOW 0x50000000 +#define ESP32_RTC_DATA_HIGH 0x50002000 +#define ESP32_DR_REG_LOW 0x3ff00000 +#define ESP32_DR_REG_HIGH 0x3ff71000 +#define ESP32_SYS_RAM_LOW 0x60000000UL +#define ESP32_SYS_RAM_HIGH (ESP32_SYS_RAM_LOW + 0x20000000UL) +#define ESP32_RTC_SLOW_MEM_BASE ESP32_RTC_DATA_LOW + +/* ESP32 WDT */ +#define ESP32_WDT_WKEY_VALUE 0x50d83aa1 +#define ESP32_TIMG0_BASE 0x3ff5f000 +#define ESP32_TIMG1_BASE 0x3ff60000 +#define ESP32_TIMGWDT_CFG0_OFF 0x48 +#define ESP32_TIMGWDT_PROTECT_OFF 0x64 +#define ESP32_TIMG0WDT_CFG0 (ESP32_TIMG0_BASE + ESP32_TIMGWDT_CFG0_OFF) +#define ESP32_TIMG1WDT_CFG0 (ESP32_TIMG1_BASE + ESP32_TIMGWDT_CFG0_OFF) +#define ESP32_TIMG0WDT_PROTECT (ESP32_TIMG0_BASE + ESP32_TIMGWDT_PROTECT_OFF) +#define ESP32_TIMG1WDT_PROTECT (ESP32_TIMG1_BASE + ESP32_TIMGWDT_PROTECT_OFF) +#define ESP32_RTCCNTL_BASE 0x3ff48000 +#define ESP32_RTCWDT_CFG_OFF 0x8C +#define ESP32_RTCWDT_PROTECT_OFF 0xA4 +#define ESP32_RTCWDT_CFG (ESP32_RTCCNTL_BASE + ESP32_RTCWDT_CFG_OFF) +#define ESP32_RTCWDT_PROTECT (ESP32_RTCCNTL_BASE + ESP32_RTCWDT_PROTECT_OFF) + +#define ESP32_TRACEMEM_BLOCK_SZ 0x4000 + +/* ESP32 dport regs */ +#define ESP32_DR_REG_DPORT_BASE ESP32_DR_REG_LOW +#define ESP32_DPORT_APPCPU_CTRL_B_REG (ESP32_DR_REG_DPORT_BASE + 0x030) +#define ESP32_DPORT_APPCPU_CLKGATE_EN BIT(0) +/* ESP32 RTC regs */ +#define ESP32_RTC_CNTL_SW_CPU_STALL_REG (ESP32_RTCCNTL_BASE + 0xac) +#define ESP32_RTC_CNTL_SW_CPU_STALL_DEF 0x0 + +/* 0 - don't care, 1 - TMS low, 2 - TMS high */ +enum esp32_flash_bootstrap { + FBS_DONTCARE = 0, + FBS_TMSLOW, + FBS_TMSHIGH, +}; + +struct esp32_common { + struct esp_xtensa_smp_common esp_xtensa_smp; + enum esp32_flash_bootstrap flash_bootstrap; +}; + +static inline struct esp32_common *target_to_esp32(struct target *target) +{ + return container_of(target->arch_info, struct esp32_common, esp_xtensa_smp); +} + +/* Reset ESP32 peripherals. + * Postconditions: all peripherals except RTC_CNTL are reset, CPU's PC is undefined, PRO CPU is halted, + * APP CPU is in reset + * How this works: + * 0. make sure target is halted; if not, try to halt it; if that fails, try to reset it (via OCD) and then halt + * 1. set CPU initial PC to 0x50000000 (ESP32_SMP_RTC_DATA_LOW) by clearing RTC_CNTL_{PRO,APP}CPU_STAT_VECTOR_SEL + * 2. load stub code into ESP32_SMP_RTC_DATA_LOW; once executed, stub code will disable watchdogs and + * make CPU spin in an idle loop. + * 3. trigger SoC reset using RTC_CNTL_SW_SYS_RST bit + * 4. wait for the OCD to be reset + * 5. halt the target and wait for it to be halted (at this point CPU is in the idle loop) + * 6. restore initial PC and the contents of ESP32_SMP_RTC_DATA_LOW + * TODO: some state of RTC_CNTL is not reset during SW_SYS_RST. Need to reset that manually. */ + +static const uint8_t esp32_reset_stub_code[] = { +#include "../../../contrib/loaders/reset/espressif/esp32/cpu_reset_handler_code.inc" +}; + +static int esp32_soc_reset(struct target *target) +{ + int res; + struct target_list *head; + struct xtensa *xtensa; + + LOG_DEBUG("start"); + /* In order to write to peripheral registers, target must be halted first */ + if (target->state != TARGET_HALTED) { + LOG_DEBUG("Target not halted before SoC reset, trying to halt it first"); + xtensa_halt(target); + res = target_wait_state(target, TARGET_HALTED, 1000); + if (res != ERROR_OK) { + LOG_DEBUG("Couldn't halt target before SoC reset, trying to do reset-halt"); + res = xtensa_assert_reset(target); + if (res != ERROR_OK) { + LOG_ERROR( + "Couldn't halt target before SoC reset! (xtensa_assert_reset returned %d)", + res); + return res; + } + alive_sleep(10); + xtensa_poll(target); + bool reset_halt_save = target->reset_halt; + target->reset_halt = true; + res = xtensa_deassert_reset(target); + target->reset_halt = reset_halt_save; + if (res != ERROR_OK) { + LOG_ERROR( + "Couldn't halt target before SoC reset! (xtensa_deassert_reset returned %d)", + res); + return res; + } + alive_sleep(10); + xtensa_poll(target); + xtensa_halt(target); + res = target_wait_state(target, TARGET_HALTED, 1000); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't halt target before SoC reset"); + return res; + } + } + } + + if (target->smp) { + foreach_smp_target(head, target->smp_targets) { + xtensa = target_to_xtensa(head->target); + /* if any of the cores is stalled unstall them */ + if (xtensa_dm_core_is_stalled(&xtensa->dbg_mod)) { + LOG_TARGET_DEBUG(head->target, "Unstall CPUs before SW reset!"); + res = target_write_u32(target, + ESP32_RTC_CNTL_SW_CPU_STALL_REG, + ESP32_RTC_CNTL_SW_CPU_STALL_DEF); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(head->target, "Failed to unstall CPUs before SW reset!"); + return res; + } + break; /* both cores are unstalled now, so exit the loop */ + } + } + } + + LOG_DEBUG("Loading stub code into RTC RAM"); + uint8_t slow_mem_save[sizeof(esp32_reset_stub_code)]; + + /* Save contents of RTC_SLOW_MEM which we are about to overwrite */ + res = target_read_buffer(target, ESP32_RTC_SLOW_MEM_BASE, sizeof(slow_mem_save), slow_mem_save); + if (res != ERROR_OK) { + LOG_ERROR("Failed to save contents of RTC_SLOW_MEM (%d)!", res); + return res; + } + + /* Write stub code into RTC_SLOW_MEM */ + res = target_write_buffer(target, ESP32_RTC_SLOW_MEM_BASE, sizeof(esp32_reset_stub_code), esp32_reset_stub_code); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write stub (%d)!", res); + return res; + } + + LOG_DEBUG("Resuming the target"); + xtensa = target_to_xtensa(target); + xtensa->suppress_dsr_errors = true; + res = xtensa_resume(target, 0, ESP32_RTC_SLOW_MEM_BASE + 4, 0, 0); + xtensa->suppress_dsr_errors = false; + if (res != ERROR_OK) { + LOG_ERROR("Failed to run stub (%d)!", res); + return res; + } + LOG_DEBUG("resume done, waiting for the target to come alive"); + + /* Wait for SoC to reset */ + alive_sleep(100); + int64_t timeout = timeval_ms() + 100; + bool get_timeout = false; + while (target->state != TARGET_RESET && target->state != TARGET_RUNNING) { + alive_sleep(10); + xtensa_poll(target); + if (timeval_ms() >= timeout) { + LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state=%d", + target->state); + get_timeout = true; + break; + } + } + + /* Halt the CPU again */ + LOG_DEBUG("halting the target"); + xtensa_halt(target); + res = target_wait_state(target, TARGET_HALTED, 1000); + if (res == ERROR_OK) { + LOG_DEBUG("restoring RTC_SLOW_MEM"); + res = target_write_buffer(target, ESP32_RTC_SLOW_MEM_BASE, sizeof(slow_mem_save), slow_mem_save); + if (res != ERROR_OK) + LOG_TARGET_ERROR(target, "Failed to restore contents of RTC_SLOW_MEM (%d)!", res); + } else { + LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be halted after SoC reset"); + } + + return get_timeout ? ERROR_TARGET_TIMEOUT : res; +} + +static int esp32_disable_wdts(struct target *target) +{ + /* TIMG1 WDT */ + int res = target_write_u32(target, ESP32_TIMG0WDT_PROTECT, ESP32_WDT_WKEY_VALUE); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_TIMG0WDT_PROTECT (%d)!", res); + return res; + } + res = target_write_u32(target, ESP32_TIMG0WDT_CFG0, 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_TIMG0WDT_CFG0 (%d)!", res); + return res; + } + /* TIMG2 WDT */ + res = target_write_u32(target, ESP32_TIMG1WDT_PROTECT, ESP32_WDT_WKEY_VALUE); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_TIMG1WDT_PROTECT (%d)!", res); + return res; + } + res = target_write_u32(target, ESP32_TIMG1WDT_CFG0, 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_TIMG1WDT_CFG0 (%d)!", res); + return res; + } + /* RTC WDT */ + res = target_write_u32(target, ESP32_RTCWDT_PROTECT, ESP32_WDT_WKEY_VALUE); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_RTCWDT_PROTECT (%d)!", res); + return res; + } + res = target_write_u32(target, ESP32_RTCWDT_CFG, 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_RTCWDT_CFG (%d)!", res); + return res; + } + return ERROR_OK; +} + +static int esp32_on_halt(struct target *target) +{ + int ret = esp32_disable_wdts(target); + if (ret == ERROR_OK) + ret = esp_xtensa_smp_on_halt(target); + return ret; +} + +static int esp32_arch_state(struct target *target) +{ + return ERROR_OK; +} + +static int esp32_virt2phys(struct target *target, + target_addr_t virtual, target_addr_t *physical) +{ + if (physical) { + *physical = virtual; + return ERROR_OK; + } + return ERROR_FAIL; +} + +/* The TDI pin is also used as a flash Vcc bootstrap pin. If we reset the CPU externally, the last state of the TDI pin + * can allow the power to an 1.8V flash chip to be raised to 3.3V, or the other way around. Users can use the + * esp32 flashbootstrap command to set a level, and this routine will make sure the tdi line will return to + * that when the jtag port is idle. */ + +static void esp32_queue_tdi_idle(struct target *target) +{ + struct esp32_common *esp32 = target_to_esp32(target); + static uint32_t value; + uint8_t t[4] = { 0, 0, 0, 0 }; + + if (esp32->flash_bootstrap == FBS_TMSLOW) + /* Make sure tdi is 0 at the exit of queue execution */ + value = 0; + else if (esp32->flash_bootstrap == FBS_TMSHIGH) + /* Make sure tdi is 1 at the exit of queue execution */ + value = 1; + else + return; + + /* Scan out 1 bit, do not move from IRPAUSE after we're done. */ + buf_set_u32(t, 0, 1, value); + jtag_add_plain_ir_scan(1, t, NULL, TAP_IRPAUSE); +} + +static int esp32_target_init(struct command_context *cmd_ctx, struct target *target) +{ + return esp_xtensa_smp_target_init(cmd_ctx, target); +} + +static const struct xtensa_debug_ops esp32_dbg_ops = { + .queue_enable = xtensa_dm_queue_enable, + .queue_reg_read = xtensa_dm_queue_reg_read, + .queue_reg_write = xtensa_dm_queue_reg_write +}; + +static const struct xtensa_power_ops esp32_pwr_ops = { + .queue_reg_read = xtensa_dm_queue_pwr_reg_read, + .queue_reg_write = xtensa_dm_queue_pwr_reg_write +}; + +static const struct esp_xtensa_smp_chip_ops esp32_chip_ops = { + .reset = esp32_soc_reset, + .on_halt = esp32_on_halt +}; + +static const struct esp_semihost_ops esp32_semihost_ops = { + .prepare = esp32_disable_wdts +}; + +static int esp32_target_create(struct target *target, Jim_Interp *interp) +{ + struct xtensa_debug_module_config esp32_dm_cfg = { + .dbg_ops = &esp32_dbg_ops, + .pwr_ops = &esp32_pwr_ops, + .tap = target->tap, + .queue_tdi_idle = esp32_queue_tdi_idle, + .queue_tdi_idle_arg = target + }; + + struct esp32_common *esp32 = calloc(1, sizeof(struct esp32_common)); + if (!esp32) { + LOG_ERROR("Failed to alloc memory for arch info!"); + return ERROR_FAIL; + } + + int ret = esp_xtensa_smp_init_arch_info(target, &esp32->esp_xtensa_smp, + &esp32_dm_cfg, &esp32_chip_ops, &esp32_semihost_ops); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to init arch info!"); + free(esp32); + return ret; + } + esp32->flash_bootstrap = FBS_DONTCARE; + + /* Assume running target. If different, the first poll will fix this. */ + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + return ERROR_OK; +} + +static COMMAND_HELPER(esp32_cmd_flashbootstrap_do, struct esp32_common *esp32) +{ + int state = -1; + + if (CMD_ARGC < 1) { + const char *st; + state = esp32->flash_bootstrap; + if (state == FBS_DONTCARE) + st = "Don't care"; + else if (state == FBS_TMSLOW) + st = "Low (3.3V)"; + else if (state == FBS_TMSHIGH) + st = "High (1.8V)"; + else + st = "None"; + command_print(CMD, "Current idle tms state: %s", st); + return ERROR_OK; + } + + if (!strcasecmp(CMD_ARGV[0], "none")) + state = FBS_DONTCARE; + else if (!strcasecmp(CMD_ARGV[0], "1.8")) + state = FBS_TMSHIGH; + else if (!strcasecmp(CMD_ARGV[0], "3.3")) + state = FBS_TMSLOW; + else if (!strcasecmp(CMD_ARGV[0], "high")) + state = FBS_TMSHIGH; + else if (!strcasecmp(CMD_ARGV[0], "low")) + state = FBS_TMSLOW; + + if (state == -1) { + command_print(CMD, + "Argument unknown. Please pick one of none, high, low, 1.8 or 3.3"); + return ERROR_FAIL; + } + esp32->flash_bootstrap = state; + return ERROR_OK; +} + +COMMAND_HANDLER(esp32_cmd_flashbootstrap) +{ + struct target *target = get_current_target(CMD_CTX); + + if (target->smp) { + struct target_list *head; + struct target *curr; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + int ret = CALL_COMMAND_HANDLER(esp32_cmd_flashbootstrap_do, + target_to_esp32(curr)); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(esp32_cmd_flashbootstrap_do, + target_to_esp32(target)); +} + +static const struct command_registration esp32_any_command_handlers[] = { + { + .name = "flashbootstrap", + .handler = esp32_cmd_flashbootstrap, + .mode = COMMAND_ANY, + .help = + "Set the idle state of the TMS pin, which at reset also is the voltage selector for the flash chip.", + .usage = "none|1.8|3.3|high|low", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration esp32_command_handlers[] = { + { + .chain = esp_xtensa_smp_command_handlers, + }, + { + .name = "esp", + .usage = "", + .chain = esp32_apptrace_command_handlers, + }, + { + .name = "esp32", + .usage = "", + .chain = smp_command_handlers, + }, + { + .name = "esp32", + .usage = "", + .chain = esp32_any_command_handlers, + }, + { + .name = "arm", + .mode = COMMAND_ANY, + .help = "ARM Command Group", + .usage = "", + .chain = semihosting_common_handlers + }, + COMMAND_REGISTRATION_DONE +}; + +/** Holds methods for Xtensa targets. */ +struct target_type esp32_target = { + .name = "esp32", + + .poll = esp_xtensa_smp_poll, + .arch_state = esp32_arch_state, + + .halt = xtensa_halt, + .resume = esp_xtensa_smp_resume, + .step = esp_xtensa_smp_step, + + .assert_reset = esp_xtensa_smp_assert_reset, + .deassert_reset = esp_xtensa_smp_deassert_reset, + .soft_reset_halt = esp_xtensa_smp_soft_reset_halt, + + .virt2phys = esp32_virt2phys, + .mmu = xtensa_mmu_is_enabled, + .read_memory = xtensa_read_memory, + .write_memory = xtensa_write_memory, + + .read_buffer = xtensa_read_buffer, + .write_buffer = xtensa_write_buffer, + + .checksum_memory = xtensa_checksum_memory, + + .get_gdb_arch = xtensa_get_gdb_arch, + .get_gdb_reg_list = xtensa_get_gdb_reg_list, + + .run_algorithm = xtensa_run_algorithm, + .start_algorithm = xtensa_start_algorithm, + .wait_algorithm = xtensa_wait_algorithm, + + .add_breakpoint = esp_xtensa_breakpoint_add, + .remove_breakpoint = esp_xtensa_breakpoint_remove, + + .add_watchpoint = esp_xtensa_smp_watchpoint_add, + .remove_watchpoint = esp_xtensa_smp_watchpoint_remove, + + .target_create = esp32_target_create, + .init_target = esp32_target_init, + .examine = xtensa_examine, + .deinit_target = esp_xtensa_target_deinit, + + .commands = esp32_command_handlers, +}; diff --git a/src/target/espressif/esp32_apptrace.c b/src/target/espressif/esp32_apptrace.c new file mode 100644 index 0000000000..125f366329 --- /dev/null +++ b/src/target/espressif/esp32_apptrace.c @@ -0,0 +1,1635 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * ESP32xx application tracing module for OpenOCD * + * Copyright (C) 2017 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif + +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif + +#ifndef _WIN32 +#include <netinet/tcp.h> +#include <sys/ioctl.h> +#endif + +#include <helper/list.h> +#include <helper/time_support.h> +#include <target/target.h> +#include <target/target_type.h> +#include <target/smp.h> +#include <server/server.h> +#include "esp_xtensa.h" +#include "esp_xtensa_smp.h" +#include "esp_xtensa_apptrace.h" +#include "esp32_apptrace.h" +#include "esp32_sysview.h" +#include "segger_sysview.h" + +#define ESP32_APPTRACE_USER_BLOCK_CORE(_v_) ((_v_) >> 15) +#define ESP32_APPTRACE_USER_BLOCK_LEN(_v_) ((_v_) & ~BIT(15)) + +#define ESP32_APPTRACE_USER_BLOCK_HDR_SZ 4 + +#define ESP_APPTRACE_CMD_MODE_GEN 0 +#define ESP_APPTRACE_CMD_MODE_SYSVIEW 1 +#define ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE 2 +#define ESP_APPTRACE_CMD_MODE_SYNC 3 + +#define ESP32_APPTRACE_TGT_STATE_TMO 5000 +#define ESP_APPTRACE_BLOCKS_POOL_SZ 10 + +struct esp32_apptrace_dest_file_data { + int fout; +}; + +struct esp32_apptrace_dest_tcp_data { + int sockfd; +}; + +struct esp32_apptrace_target_state { + int running; + uint32_t block_id; + uint32_t data_len; +}; + +struct esp_apptrace_target2host_hdr { + uint16_t block_sz; + uint16_t wr_sz; +}; +#define APPTRACE_BLOCK_SIZE_OFFSET 0 +#define APPTRACE_WR_SIZE_OFFSET 2 + +struct esp32_apptrace_block { + struct list_head node; + uint8_t *data; + uint32_t data_len; +}; + +static int esp32_apptrace_data_processor(void *priv); +static int esp32_apptrace_get_data_info(struct esp32_apptrace_cmd_ctx *ctx, + struct esp32_apptrace_target_state *target_state, + uint32_t *fired_target_num); +static int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx *ctx, + struct esp32_apptrace_target_state *targets); +static struct esp32_apptrace_block *esp32_apptrace_free_block_get(struct esp32_apptrace_cmd_ctx *ctx); +static int esp32_apptrace_handle_trace_block(struct esp32_apptrace_cmd_ctx *ctx, + struct esp32_apptrace_block *block); +static int esp32_sysview_start(struct esp32_apptrace_cmd_ctx *ctx); +static int esp32_sysview_stop(struct esp32_apptrace_cmd_ctx *ctx); + +static const bool s_time_stats_enable = true; + +/********************************************************************* +* Trace destination API +**********************************************************************/ + +static int esp32_apptrace_file_dest_write(void *priv, uint8_t *data, int size) +{ + struct esp32_apptrace_dest_file_data *dest_data = (struct esp32_apptrace_dest_file_data *)priv; + + int wr_sz = write(dest_data->fout, data, size); + if (wr_sz != size) { + LOG_ERROR("Failed to write %d bytes to out file (%d)! Written %d.", size, errno, wr_sz); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int esp32_apptrace_file_dest_cleanup(void *priv) +{ + struct esp32_apptrace_dest_file_data *dest_data = (struct esp32_apptrace_dest_file_data *)priv; + + if (dest_data->fout > 0) + close(dest_data->fout); + free(dest_data); + return ERROR_OK; +} + +static int esp32_apptrace_file_dest_init(struct esp32_apptrace_dest *dest, const char *dest_name) +{ + struct esp32_apptrace_dest_file_data *dest_data = calloc(1, sizeof(*dest_data)); + if (!dest_data) { + LOG_ERROR("Failed to alloc mem for file dest!"); + return ERROR_FAIL; + } + + LOG_INFO("Open file %s", dest_name); + dest_data->fout = open(dest_name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + if (dest_data->fout <= 0) { + LOG_ERROR("Failed to open file %s", dest_name); + free(dest_data); + return ERROR_FAIL; + } + + dest->priv = dest_data; + dest->write = esp32_apptrace_file_dest_write; + dest->clean = esp32_apptrace_file_dest_cleanup; + dest->log_progress = true; + + return ERROR_OK; +} + +static int esp32_apptrace_console_dest_write(void *priv, uint8_t *data, int size) +{ + LOG_USER_N("%.*s", size, data); + return ERROR_OK; +} + +static int esp32_apptrace_console_dest_cleanup(void *priv) +{ + return ERROR_OK; +} + +static int esp32_apptrace_console_dest_init(struct esp32_apptrace_dest *dest, const char *dest_name) +{ + dest->priv = NULL; + dest->write = esp32_apptrace_console_dest_write; + dest->clean = esp32_apptrace_console_dest_cleanup; + dest->log_progress = false; + + return ERROR_OK; +} + +static int esp32_apptrace_tcp_dest_write(void *priv, uint8_t *data, int size) +{ + struct esp32_apptrace_dest_tcp_data *dest_data = (struct esp32_apptrace_dest_tcp_data *)priv; + int wr_sz = write_socket(dest_data->sockfd, data, size); + if (wr_sz != size) { + LOG_ERROR("Failed to write %u bytes to out socket (%d)! Written %d.", size, errno, wr_sz); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int esp32_apptrace_tcp_dest_cleanup(void *priv) +{ + struct esp32_apptrace_dest_tcp_data *dest_data = (struct esp32_apptrace_dest_tcp_data *)priv; + + if (dest_data->sockfd > 0) + close_socket(dest_data->sockfd); + free(dest_data); + return ERROR_OK; +} + +static int esp32_apptrace_tcp_dest_init(struct esp32_apptrace_dest *dest, const char *dest_name) +{ + const char *port_sep = strchr(dest_name, ':'); + /* separator not found, or was the first or the last character */ + if (!port_sep || port_sep == dest_name || port_sep == dest_name + strlen(dest_name) - 1) { + LOG_ERROR("apptrace: Invalid connection URI, format should be tcp://host:port"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + size_t hostname_len = port_sep - dest_name; + + char hostname[64] = { 0 }; + if (hostname_len >= sizeof(hostname)) { + LOG_ERROR("apptrace: Hostname too long"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + memcpy(hostname, dest_name, hostname_len); + + const char *port_str = port_sep + 1; + struct addrinfo *ai; + int flags = 0; +#ifdef AI_NUMERICSERV + flags |= AI_NUMERICSERV; +#endif /* AI_NUMERICSERV */ + struct addrinfo hint = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + .ai_protocol = 0, + .ai_flags = flags + }; + int res = getaddrinfo(hostname, port_str, &hint, &ai); + if (res != 0) { + LOG_ERROR("apptrace: Failed to resolve host name: %s", hostname); + return ERROR_FAIL; + } + int sockfd = -1; + for (struct addrinfo *ai_it = ai; ai_it; ai_it = ai_it->ai_next) { + sockfd = socket(ai_it->ai_family, ai_it->ai_socktype, ai_it->ai_protocol); + if (sockfd < 0) { + LOG_DEBUG("apptrace: Failed to create socket (%d, %d, %d) (%s)", + ai_it->ai_family, + ai_it->ai_socktype, + ai_it->ai_protocol, + strerror(errno)); + continue; + } + + char cur_hostname[NI_MAXHOST]; + char cur_portname[NI_MAXSERV]; + res = + getnameinfo(ai_it->ai_addr, ai_it->ai_addrlen, cur_hostname, + sizeof(cur_hostname), + cur_portname, sizeof(cur_portname), + NI_NUMERICHOST | NI_NUMERICSERV); + if (res != 0) + continue; + + LOG_INFO("apptrace: Trying to connect to %s:%s", cur_hostname, cur_portname); + if (connect(sockfd, ai_it->ai_addr, ai_it->ai_addrlen) < 0) { + close_socket(sockfd); + sockfd = -1; + LOG_WARNING("apptrace: Connection failed (%s)", strerror(errno)); + continue; + } + break; + } + freeaddrinfo(ai); + if (sockfd < 0) { + LOG_ERROR("apptrace: Could not connect to %s:%s", hostname, port_str); + return ERROR_FAIL; + } + LOG_INFO("apptrace: Connected!"); + + struct esp32_apptrace_dest_tcp_data *dest_data = calloc(1, sizeof(struct esp32_apptrace_dest_tcp_data)); + if (!dest_data) { + LOG_ERROR("apptrace: Failed to alloc mem for tcp dest!"); + close_socket(sockfd); + return ERROR_FAIL; + } + + dest_data->sockfd = sockfd; + dest->priv = dest_data; + dest->write = esp32_apptrace_tcp_dest_write; + dest->clean = esp32_apptrace_tcp_dest_cleanup; + dest->log_progress = true; + + return ERROR_OK; +} + +int esp32_apptrace_dest_init(struct esp32_apptrace_dest dest[], const char *dest_paths[], unsigned int max_dests) +{ + int res; + unsigned int i; + + for (i = 0; i < max_dests; i++) { + if (strncmp(dest_paths[i], "file://", 7) == 0) + res = esp32_apptrace_file_dest_init(&dest[i], &dest_paths[i][7]); + else if (strncmp(dest_paths[i], "con:", 4) == 0) + res = esp32_apptrace_console_dest_init(&dest[i], NULL); + else if (strncmp(dest_paths[i], "tcp://", 6) == 0) + res = esp32_apptrace_tcp_dest_init(&dest[i], &dest_paths[i][6]); + else + break; + + if (res != ERROR_OK) { + LOG_ERROR("apptrace: Failed to init trace data destination '%s'!", dest_paths[i]); + return 0; + } + } + + return i; +} + +int esp32_apptrace_dest_cleanup(struct esp32_apptrace_dest dest[], unsigned int max_dests) +{ + for (unsigned int i = 0; i < max_dests; i++) { + if (dest[i].clean && dest[i].priv) { + int res = dest[i].clean(dest[i].priv); + dest[i].priv = NULL; + return res; + } + } + return ERROR_OK; +} + +/********************************************************************* +* Trace data blocks management API +**********************************************************************/ +static void esp32_apptrace_blocks_pool_cleanup(struct esp32_apptrace_cmd_ctx *ctx) +{ + struct esp32_apptrace_block *cur; + struct list_head *head = &ctx->free_trace_blocks; + struct list_head *tmp, *pos; + + list_for_each_safe(pos, tmp, head) { + cur = list_entry(pos, struct esp32_apptrace_block, node); + if (cur) { + list_del(&cur->node); + free(cur->data); + free(cur); + } + } + + head = &ctx->ready_trace_blocks; + + list_for_each_safe(pos, tmp, head) { + cur = list_entry(pos, struct esp32_apptrace_block, node); + if (cur) { + list_del(&cur->node); + free(cur->data); + free(cur); + } + } +} + +struct esp32_apptrace_block *esp32_apptrace_free_block_get(struct esp32_apptrace_cmd_ctx *ctx) +{ + struct esp32_apptrace_block *block = NULL; + + if (!list_empty(&ctx->free_trace_blocks)) { + /*get first */ + block = list_first_entry(&ctx->free_trace_blocks, struct esp32_apptrace_block, node); + list_del(&block->node); + } + + return block; +} + +static int esp32_apptrace_ready_block_put(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_block *block) +{ + LOG_DEBUG("esp32_apptrace_ready_block_put"); + /* add to ready blocks list */ + INIT_LIST_HEAD(&block->node); + list_add(&block->node, &ctx->ready_trace_blocks); + + return ERROR_OK; +} + +static struct esp32_apptrace_block *esp32_apptrace_ready_block_get(struct esp32_apptrace_cmd_ctx *ctx) +{ + if (list_empty(&ctx->ready_trace_blocks)) + return NULL; + + struct esp32_apptrace_block *block = + list_last_entry(&ctx->ready_trace_blocks, struct esp32_apptrace_block, node); + + /* remove it from ready list */ + list_del(&block->node); + + return block; +} + +static int esp32_apptrace_block_free(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_block *block) +{ + /* add to free blocks list */ + INIT_LIST_HEAD(&block->node); + list_add(&block->node, &ctx->free_trace_blocks); + + return ERROR_OK; +} + +static int esp32_apptrace_wait_tracing_finished(struct esp32_apptrace_cmd_ctx *ctx) +{ + int64_t timeout = timeval_ms() + (LOG_LEVEL_IS(LOG_LVL_DEBUG) ? 70000 : 5000); + while (!list_empty(&ctx->ready_trace_blocks)) { + alive_sleep(100); + if (timeval_ms() >= timeout) { + LOG_ERROR("Failed to wait for pended trace blocks!"); + return ERROR_FAIL; + } + } + /* signal timer callback to stop */ + ctx->running = 0; + target_unregister_timer_callback(esp32_apptrace_data_processor, ctx); + return ERROR_OK; +} + +/********************************************************************* +* Trace commands +**********************************************************************/ + +int esp32_apptrace_cmd_ctx_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, struct command_invocation *cmd, int mode) +{ + struct target *target = get_current_target(CMD_CTX); + + memset(cmd_ctx, 0, sizeof(struct esp32_apptrace_cmd_ctx)); + cmd_ctx->target = target; + cmd_ctx->mode = mode; + cmd_ctx->target_state = target->state; + cmd_ctx->cmd = cmd; + + if (target->smp) { + struct target_list *head; + struct target *curr; + unsigned int i = 0; + cmd_ctx->cores_num = 0; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + if (i == ESP32_APPTRACE_MAX_CORES_NUM) { + command_print(cmd, "Too many cores configured! Max %d cores are supported.", + ESP32_APPTRACE_MAX_CORES_NUM); + return ERROR_FAIL; + } + if (!target_was_examined(curr)) + continue; + cmd_ctx->cores_num++; + cmd_ctx->cpus[i++] = curr; + } + } else { + cmd_ctx->cores_num = 1; + cmd_ctx->cpus[0] = target; + } + /* some relies on ESP32_APPTRACE_MAX_CORES_NUM + * TODO: remove that dependency */ + assert(cmd_ctx->cores_num <= ESP32_APPTRACE_MAX_CORES_NUM && "Too many cores number!"); + + struct xtensa *xtensa = target->arch_info; + if (xtensa->common_magic == XTENSA_COMMON_MAGIC) { + cmd_ctx->hw = target_to_esp_xtensa(target)->apptrace.hw; + } else { /* TODO: riscv is not supported yet */ + command_print(cmd, "Unsupported target arch 0x%X", xtensa->common_magic); + return ERROR_FAIL; + } + + cmd_ctx->max_trace_block_sz = cmd_ctx->hw->max_block_size_get(cmd_ctx->cpus[0]); + if (cmd_ctx->max_trace_block_sz == 0) { + command_print(cmd, "Failed to get max trace block size!"); + return ERROR_FAIL; + } + LOG_INFO("Total trace memory: %" PRIu32 " bytes", cmd_ctx->max_trace_block_sz); + + INIT_LIST_HEAD(&cmd_ctx->ready_trace_blocks); + INIT_LIST_HEAD(&cmd_ctx->free_trace_blocks); + for (unsigned int i = 0; i < ESP_APPTRACE_BLOCKS_POOL_SZ; i++) { + struct esp32_apptrace_block *block = calloc(1, sizeof(struct esp32_apptrace_block)); + if (!block) { + command_print(cmd, "Failed to alloc trace buffer entry!"); + esp32_apptrace_blocks_pool_cleanup(cmd_ctx); + return ERROR_FAIL; + } + block->data = malloc(cmd_ctx->max_trace_block_sz); + if (!block->data) { + free(block); + command_print(cmd, "Failed to alloc trace buffer %" PRIu32 " bytes!", cmd_ctx->max_trace_block_sz); + esp32_apptrace_blocks_pool_cleanup(cmd_ctx); + return ERROR_FAIL; + } + INIT_LIST_HEAD(&block->node); + list_add(&block->node, &cmd_ctx->free_trace_blocks); + } + + cmd_ctx->running = 1; + if (cmd_ctx->mode != ESP_APPTRACE_CMD_MODE_SYNC) { + int res = target_register_timer_callback(esp32_apptrace_data_processor, + 0, + TARGET_TIMER_TYPE_PERIODIC, + cmd_ctx); + if (res != ERROR_OK) { + command_print(cmd, "Failed to start trace data timer callback (%d)!", res); + esp32_apptrace_blocks_pool_cleanup(cmd_ctx); + return ERROR_FAIL; + } + } + + if (s_time_stats_enable) { + cmd_ctx->stats.min_blk_read_time = 1000000.0; + cmd_ctx->stats.min_blk_proc_time = 1000000.0; + } + if (duration_start(&cmd_ctx->idle_time) != 0) { + command_print(cmd, "Failed to start idle time measurement!"); + esp32_apptrace_cmd_ctx_cleanup(cmd_ctx); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +int esp32_apptrace_cmd_ctx_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx) +{ + esp32_apptrace_blocks_pool_cleanup(cmd_ctx); + return ERROR_OK; +} + +#define ESP32_APPTRACE_CMD_NUM_ARG_CHECK(_cmd_, _arg_, _start_, _end_) \ + do { \ + if ((_arg_) == 0 && (_start_) == (_end_)) { \ + command_print(_cmd_, "Invalid '" # _arg_ "' arg!"); \ + return; \ + } \ + } while (0) + +void esp32_apptrace_cmd_args_parse(struct esp32_apptrace_cmd_ctx *cmd_ctx, + struct esp32_apptrace_cmd_data *cmd_data, + const char **argv, + int argc) +{ + char *end; + + cmd_data->poll_period = strtoul(argv[0], &end, 10); + ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->poll_period, argv[0], end); + if (argc > 1) { + cmd_data->max_len = strtoul(argv[1], &end, 10); + ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->max_len, argv[1], end); + if (argc > 2) { + int32_t tmo = strtol(argv[2], &end, 10); + ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, tmo, argv[2], end); + cmd_ctx->stop_tmo = 1.0 * tmo; + if (argc > 3) { + cmd_data->wait4halt = strtoul(argv[3], &end, 10); + ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->wait4halt, argv[3], end); + if (argc > 4) { + cmd_data->skip_len = strtoul(argv[4], &end, 10); + ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->skip_len, argv[4], end); + } + } + } + } +} + +static int esp32_apptrace_core_id_get(struct target *target, uint8_t *hdr_buf) +{ + return ESP32_APPTRACE_USER_BLOCK_CORE(target_buffer_get_u16(target, hdr_buf + APPTRACE_BLOCK_SIZE_OFFSET)); +} + +static uint32_t esp32_apptrace_usr_block_len_get(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len) +{ + *wr_len = ESP32_APPTRACE_USER_BLOCK_LEN(target_buffer_get_u16(target, hdr_buf + APPTRACE_WR_SIZE_OFFSET)); + return ESP32_APPTRACE_USER_BLOCK_LEN(target_buffer_get_u16(target, hdr_buf + APPTRACE_BLOCK_SIZE_OFFSET)); +} + +static int esp32_apptrace_cmd_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, + struct command_invocation *cmd, + int mode, + const char **argv, + int argc) +{ + struct esp32_apptrace_cmd_data *cmd_data; + + if (argc < 1) { + command_print(cmd, "Not enough args! Need trace data destination!"); + return ERROR_FAIL; + } + + int res = esp32_apptrace_cmd_ctx_init(cmd_ctx, cmd, mode); + if (res != ERROR_OK) + return res; + + cmd_data = calloc(1, sizeof(*cmd_data)); + assert(cmd_data && "No memory for command data!"); + cmd_ctx->cmd_priv = cmd_data; + + /*outfile1 [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] */ + res = esp32_apptrace_dest_init(&cmd_data->data_dest, argv, 1); + if (res != 1) { /* only one destination needs to be initialized */ + command_print(cmd, "Wrong args! Needs a trace data destination!"); + free(cmd_data); + goto on_error; + } + cmd_ctx->stop_tmo = -1.0; /* infinite */ + cmd_data->max_len = UINT32_MAX; + cmd_data->poll_period = 0 /*ms*/; + if (argc > 1) + /* parse remaining args */ + esp32_apptrace_cmd_args_parse(cmd_ctx, cmd_data, &argv[1], argc - 1); + + LOG_USER("App trace params: from %d cores, size %" PRId32 " bytes, stop_tmo %g s, poll period %" PRId32 + " ms, wait_rst %d, skip %" PRId32 " bytes", cmd_ctx->cores_num, + cmd_data->max_len, + cmd_ctx->stop_tmo, + cmd_data->poll_period, + cmd_data->wait4halt, + cmd_data->skip_len); + + cmd_ctx->trace_format.hdr_sz = ESP32_APPTRACE_USER_BLOCK_HDR_SZ; + cmd_ctx->trace_format.core_id_get = esp32_apptrace_core_id_get; + cmd_ctx->trace_format.usr_block_len_get = esp32_apptrace_usr_block_len_get; + return ERROR_OK; +on_error: + command_print(cmd, "Not enough args! Need %d trace data destinations!", cmd_ctx->cores_num); + cmd_ctx->running = 0; + esp32_apptrace_cmd_ctx_cleanup(cmd_ctx); + return res; +} + +static int esp32_apptrace_cmd_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx) +{ + struct esp32_apptrace_cmd_data *cmd_data = cmd_ctx->cmd_priv; + + esp32_apptrace_dest_cleanup(&cmd_data->data_dest, 1); + free(cmd_data); + cmd_ctx->cmd_priv = NULL; + esp32_apptrace_cmd_ctx_cleanup(cmd_ctx); + return ERROR_OK; +} + +static void esp32_apptrace_print_stats(struct esp32_apptrace_cmd_ctx *ctx) +{ + struct esp32_apptrace_cmd_data *cmd_data = ctx->cmd_priv; + uint32_t trace_sz = 0; + + if (cmd_data) + trace_sz = ctx->tot_len > cmd_data->skip_len ? ctx->tot_len - cmd_data->skip_len : 0; + LOG_USER("Tracing is %s. Size is %" PRId32 " of %" PRId32 " @ %f (%f) KiB/s", + !ctx->running ? "STOPPED" : "RUNNING", + trace_sz, + cmd_data ? cmd_data->max_len : 0, + duration_kbps(&ctx->read_time, ctx->tot_len), + duration_kbps(&ctx->read_time, ctx->raw_tot_len)); + LOG_USER("Data: blocks incomplete %" PRId32 ", lost bytes: %" PRId32, + ctx->stats.incompl_blocks, + ctx->stats.lost_bytes); + if (s_time_stats_enable) { + LOG_USER("Block read time [%f..%f] ms", + 1000 * ctx->stats.min_blk_read_time, + 1000 * ctx->stats.max_blk_read_time); + LOG_USER("Block proc time [%f..%f] ms", + 1000 * ctx->stats.min_blk_proc_time, + 1000 * ctx->stats.max_blk_proc_time); + } +} + +static int esp32_apptrace_wait4halt(struct esp32_apptrace_cmd_ctx *ctx, struct target *target) +{ + LOG_USER("Wait for halt..."); + while (!openocd_is_shutdown_pending()) { + int res = target_poll(target); + if (res != ERROR_OK) + return res; + if (target->state == TARGET_HALTED) { + LOG_USER("%s: HALTED", target->cmd_name); + break; + } + alive_sleep(500); + } + return ERROR_OK; +} + +int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx *ctx, + struct esp32_apptrace_target_state *targets) +{ + int res = ERROR_OK; + + memset(targets, 0, ctx->cores_num * sizeof(struct esp32_apptrace_target_state)); + /* halt all CPUs */ + LOG_DEBUG("Halt all targets!"); + for (unsigned int k = 0; k < ctx->cores_num; k++) { + if (!target_was_examined(ctx->cpus[k])) + continue; + if (ctx->cpus[k]->state == TARGET_HALTED) + continue; + res = target_halt(ctx->cpus[k]); + if (res != ERROR_OK) { + LOG_ERROR("Failed to halt target (%d)!", res); + return res; + } + res = target_wait_state(ctx->cpus[k], TARGET_HALTED, ESP32_APPTRACE_TGT_STATE_TMO); + if (res != ERROR_OK) { + LOG_ERROR("Failed to wait halt target %s / %d (%d)!", + target_name(ctx->cpus[k]), + ctx->cpus[k]->state, + res); + return res; + } + } + /* read current block statuses from CPUs */ + LOG_DEBUG("Read current block statuses"); + for (unsigned int k = 0; k < ctx->cores_num; k++) { + uint32_t stat; + res = ctx->hw->status_reg_read(ctx->cpus[k], &stat); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read trace status (%d)!", res); + return res; + } + /* check if some CPU stopped inside tracing regs update critical section */ + if (stat) { + if (ctx->hw->leave_trace_crit_section_start) { + res = ctx->hw->leave_trace_crit_section_start(ctx->cpus[k]); + if (res != ERROR_OK) + return res; + } + uint32_t bp_addr = stat; + res = breakpoint_add(ctx->cpus[k], bp_addr, 1, BKPT_HARD); + if (res != ERROR_OK) { + LOG_ERROR("Failed to set breakpoint (%d)!", res); + return res; + } + while (stat) { + /* allow this CPU to leave ERI write critical section */ + res = target_resume(ctx->cpus[k], 1, 0, 1, 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to resume target (%d)!", res); + breakpoint_remove(ctx->cpus[k], bp_addr); + return res; + } + /* wait for CPU to be halted on BP */ + enum target_debug_reason debug_reason = DBG_REASON_UNDEFINED; + while (debug_reason != DBG_REASON_BREAKPOINT) { + res = target_wait_state(ctx->cpus[k], TARGET_HALTED, + ESP32_APPTRACE_TGT_STATE_TMO); + if (res != ERROR_OK) { + LOG_ERROR("Failed to wait halt on bp (%d)!", res); + breakpoint_remove(ctx->cpus[k], bp_addr); + return res; + } + debug_reason = ctx->cpus[k]->debug_reason; + } + res = ctx->hw->status_reg_read(ctx->cpus[k], &stat); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read trace status (%d)!", res); + breakpoint_remove(ctx->cpus[k], bp_addr); + return res; + } + } + breakpoint_remove(ctx->cpus[k], bp_addr); + if (ctx->hw->leave_trace_crit_section_stop) { + res = ctx->hw->leave_trace_crit_section_stop(ctx->cpus[k]); + if (res != ERROR_OK) + return res; + } + } + res = ctx->hw->data_len_read(ctx->cpus[k], &targets[k].block_id, &targets[k].data_len); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read trace status (%d)!", res); + return res; + } + } + + return ERROR_OK; +} + +static int esp32_apptrace_connect_targets(struct esp32_apptrace_cmd_ctx *ctx, + bool conn, + bool resume_target) +{ + struct esp32_apptrace_target_state target_to_connect[ESP32_APPTRACE_MAX_CORES_NUM]; + + if (conn) + LOG_USER("Connect targets..."); + else + LOG_USER("Disconnect targets..."); + + int res = esp32_apptrace_safe_halt_targets(ctx, target_to_connect); + if (res != ERROR_OK) { + command_print(ctx->cmd, "Failed to halt targets (%d)!", res); + return res; + } + if (ctx->cores_num > 1) { + /* set block ids to the highest value */ + uint32_t max_id = 0; + for (unsigned int k = 0; k < ctx->cores_num; k++) { + if (target_to_connect[k].block_id > max_id) + max_id = target_to_connect[k].block_id; + } + for (unsigned int k = 0; k < ctx->cores_num; k++) + target_to_connect[k].block_id = max_id; + } + for (unsigned int k = 0; k < ctx->cores_num; k++) { + /* update host connected status */ + res = ctx->hw->ctrl_reg_write(ctx->cpus[k], + target_to_connect[k].block_id, + 0 /*ack target data*/, + conn, + false /*no host data*/); + if (res != ERROR_OK) { + command_print(ctx->cmd, "Failed to read trace status (%d)!", res); + return res; + } + } + if (resume_target) { + LOG_DEBUG("Resume targets"); + bool smp_resumed = false; + for (unsigned int k = 0; k < ctx->cores_num; k++) { + if (smp_resumed && ctx->cpus[k]->smp) { + /* in SMP mode we need to call target_resume for one core only */ + continue; + } + res = target_resume(ctx->cpus[k], 1, 0, 1, 0); + if (res != ERROR_OK) { + command_print(ctx->cmd, "Failed to resume target (%d)!", res); + return res; + } + if (ctx->cpus[k]->smp) + smp_resumed = true; + } + } + if (conn) + LOG_INFO("Targets connected."); + else + LOG_INFO("Targets disconnected."); + return ERROR_OK; +} + +int esp_apptrace_usr_block_write(const struct esp32_apptrace_hw *hw, struct target *target, + uint32_t block_id, + const uint8_t *data, + uint32_t size) +{ + struct esp_apptrace_host2target_hdr hdr = { .block_sz = size }; + uint32_t buf_sz[2] = { sizeof(hdr), size }; + const uint8_t *bufs[2] = { (const uint8_t *)&hdr, data }; + + if (size > hw->usr_block_max_size_get(target)) { + LOG_ERROR("Too large user block %" PRId32, size); + return ERROR_FAIL; + } + + return hw->buffs_write(target, + ARRAY_SIZE(buf_sz), + buf_sz, + bufs, + block_id, + true /*ack target data*/, + true /*host data*/); +} + +static uint32_t esp32_apptrace_usr_block_check(struct esp32_apptrace_cmd_ctx *ctx, uint8_t *hdr_buf) +{ + uint32_t wr_len = 0; + uint32_t usr_len = ctx->trace_format.usr_block_len_get(ctx->target, hdr_buf, &wr_len); + if (usr_len != wr_len) { + LOG_ERROR("Incomplete block sz %" PRId32 ", wr %" PRId32, usr_len, wr_len); + ctx->stats.incompl_blocks++; + ctx->stats.lost_bytes += usr_len - wr_len; + } + return usr_len; +} + +int esp32_apptrace_get_data_info(struct esp32_apptrace_cmd_ctx *ctx, + struct esp32_apptrace_target_state *target_state, + uint32_t *fired_target_num) +{ + if (fired_target_num) + *fired_target_num = UINT32_MAX; + + for (unsigned int i = 0; i < ctx->cores_num; i++) { + int res = ctx->hw->data_len_read(ctx->cpus[i], &target_state[i].block_id, &target_state[i].data_len); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read data len on (%s)!", target_name(ctx->cpus[i])); + return res; + } + if (target_state[i].data_len) { + LOG_TARGET_DEBUG(ctx->cpus[i], "Block %" PRId32 ", len %" PRId32 " bytes on fired", + target_state[i].block_id, target_state[i].data_len); + if (fired_target_num) + *fired_target_num = i; + break; + } + } + return ERROR_OK; +} + +static int esp32_apptrace_process_data(struct esp32_apptrace_cmd_ctx *ctx, + unsigned int core_id, + uint8_t *data, + uint32_t data_len) +{ + struct esp32_apptrace_cmd_data *cmd_data = ctx->cmd_priv; + + LOG_DEBUG("Got block %" PRId32 " bytes [%x %x...%x %x]", data_len, data[12], data[13], + data[data_len - 2], data[data_len - 1]); + if (ctx->tot_len + data_len > cmd_data->skip_len) { + uint32_t wr_idx = 0, wr_chunk_len = data_len; + if (ctx->tot_len < cmd_data->skip_len) { + wr_chunk_len = (ctx->tot_len + wr_chunk_len) - cmd_data->skip_len; + wr_idx = cmd_data->skip_len - ctx->tot_len; + } + if (ctx->tot_len + wr_chunk_len > cmd_data->max_len) + wr_chunk_len -= (ctx->tot_len + wr_chunk_len - cmd_data->skip_len) - cmd_data->max_len; + if (wr_chunk_len > 0) { + int res = cmd_data->data_dest.write(cmd_data->data_dest.priv, data + wr_idx, wr_chunk_len); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write %" PRId32 " bytes to dest 0!", data_len); + return res; + } + } + ctx->tot_len += wr_chunk_len; + } else { + ctx->tot_len += data_len; + } + + if (cmd_data->data_dest.log_progress) + LOG_USER("%" PRId32 " ", ctx->tot_len); + /* check for stop condition */ + if (ctx->tot_len > cmd_data->skip_len && (ctx->tot_len - cmd_data->skip_len >= cmd_data->max_len)) { + ctx->running = 0; + if (duration_measure(&ctx->read_time) != 0) { + LOG_ERROR("Failed to stop trace read time measure!"); + return ERROR_FAIL; + } + } + return ERROR_OK; +} + +static int esp32_apptrace_handle_trace_block(struct esp32_apptrace_cmd_ctx *ctx, + struct esp32_apptrace_block *block) +{ + uint32_t processed = 0; + uint32_t hdr_sz = ctx->trace_format.hdr_sz; + + LOG_DEBUG("Got block %" PRId32 " bytes", block->data_len); + /* process user blocks one by one */ + while (processed < block->data_len) { + LOG_DEBUG("Process usr block %" PRId32 "/%" PRId32, processed, block->data_len); + /* process user block */ + uint32_t usr_len = esp32_apptrace_usr_block_check(ctx, block->data + processed); + int core_id = ctx->trace_format.core_id_get(ctx->target, block->data + processed); + /* process user data */ + int res = ctx->process_data(ctx, core_id, block->data + processed + hdr_sz, usr_len); + if (res != ERROR_OK) { + LOG_ERROR("Failed to process %" PRId32 " bytes!", usr_len); + return res; + } + processed += usr_len + hdr_sz; + } + return ERROR_OK; +} + +static int esp32_apptrace_data_processor(void *priv) +{ + struct esp32_apptrace_cmd_ctx *ctx = (struct esp32_apptrace_cmd_ctx *)priv; + + if (!ctx->running) + return ERROR_OK; + + struct esp32_apptrace_block *block = esp32_apptrace_ready_block_get(ctx); + if (!block) + return ERROR_OK; + + int res = esp32_apptrace_handle_trace_block(ctx, block); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len); + return res; + } + res = esp32_apptrace_block_free(ctx, block); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_ERROR("Failed to free ready block!"); + return res; + } + + return ERROR_OK; +} + +static int esp32_apptrace_check_connection(struct esp32_apptrace_cmd_ctx *ctx) +{ + if (!ctx) + return ERROR_FAIL; + + unsigned int busy_target_num = 0; + + for (unsigned int i = 0; i < ctx->cores_num; i++) { + bool conn = true; + int res = ctx->hw->ctrl_reg_read(ctx->cpus[i], NULL, NULL, &conn); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read apptrace control reg for cpu(%d) res(%d)!", i, res); + return res; + } + if (!conn) { + uint32_t stat = 0; + LOG_TARGET_WARNING(ctx->cpus[i], "apptrace connection is lost. Re-connect."); + res = ctx->hw->status_reg_read(ctx->cpus[i], &stat); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read trace status (%d)!", res); + return res; + } + if (stat) { + LOG_TARGET_WARNING(ctx->cpus[i], "in critical state. Retry in next poll"); + if (++busy_target_num == ctx->cores_num) { + LOG_WARNING("No available core"); + return ERROR_WAIT; + } + continue; + } + res = ctx->hw->ctrl_reg_write(ctx->cpus[i], + 0, + 0, + true /*host connected*/, + false /*no host data*/); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write apptrace control reg for cpu(%d) res(%d)!", i, res); + return res; + } + if (ctx->stop_tmo != -1.0) { + /* re-start idle time measurement */ + if (duration_start(&ctx->idle_time) != 0) { + LOG_ERROR("Failed to re-start idle time measure!"); + return ERROR_FAIL; + } + } + } + } + + return ERROR_OK; +} + +static int esp32_apptrace_poll(void *priv) +{ + struct esp32_apptrace_cmd_ctx *ctx = (struct esp32_apptrace_cmd_ctx *)priv; + int res; + uint32_t fired_target_num = 0; + struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM]; + struct duration blk_proc_time; + + if (!ctx->running) { + if (ctx->auto_clean) + ctx->auto_clean(ctx); + return ERROR_FAIL; + } + + /* Check for connection is alive.For some reason target and therefore host_connected flag + * might have been reset */ + res = esp32_apptrace_check_connection(ctx); + if (res != ERROR_OK) { + if (res != ERROR_WAIT) + ctx->running = 0; + return res; + } + + /* check for data from target */ + res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_ERROR("Failed to read data len!"); + return res; + } + /* LOG_DEBUG("Block %d (%d bytes) on target (%s)!", target_state[0].block_id, + * target_state[0].data_len, target_name(ctx->cpus[0])); */ + if (fired_target_num == UINT32_MAX) { + /* no data has been received, but block could be switched due to the data transferred + * from host to target */ + if (ctx->cores_num > 1) { + uint32_t max_block_id = 0, min_block_id = ctx->hw->max_block_id; + /* find maximum block ID and set the same ID in control reg for both cores + * */ + for (unsigned int i = 0; i < ctx->cores_num; i++) { + if (max_block_id < target_state[i].block_id) + max_block_id = target_state[i].block_id; + if (min_block_id > target_state[i].block_id) + min_block_id = target_state[i].block_id; + } + /* handle block ID overflow */ + if (max_block_id == ctx->hw->max_block_id && min_block_id == 0) + max_block_id = 0; + for (unsigned int i = 0; i < ctx->cores_num; i++) { + if (max_block_id != target_state[i].block_id) { + LOG_TARGET_DEBUG(ctx->cpus[i], "Ack empty block %" PRId32 "!", max_block_id); + res = ctx->hw->ctrl_reg_write(ctx->cpus[i], + max_block_id, + 0 /*all read*/, + true /*host connected*/, + false /*no host data*/); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_TARGET_ERROR(ctx->cpus[i], "Failed to ack empty data block!"); + return res; + } + } + } + ctx->last_blk_id = max_block_id; + } + if (ctx->stop_tmo != -1.0) { + if (duration_measure(&ctx->idle_time) != 0) { + ctx->running = 0; + LOG_ERROR("Failed to measure idle time!"); + return ERROR_FAIL; + } + if (duration_elapsed(&ctx->idle_time) >= ctx->stop_tmo) { + ctx->running = 0; + LOG_ERROR("Data timeout!"); + return ERROR_FAIL; + } + } + return ERROR_OK;/* no data */ + } + /* sanity check */ + if (target_state[fired_target_num].data_len > ctx->max_trace_block_sz) { + ctx->running = 0; + LOG_ERROR("Too large block size %" PRId32 "!", target_state[fired_target_num].data_len); + return ERROR_FAIL; + } + if (ctx->tot_len == 0) { + if (duration_start(&ctx->read_time) != 0) { + ctx->running = 0; + LOG_ERROR("Failed to start trace read time measurement!"); + return ERROR_FAIL; + } + } + struct esp32_apptrace_block *block = esp32_apptrace_free_block_get(ctx); + if (!block) { + ctx->running = 0; + LOG_TARGET_ERROR(ctx->cpus[fired_target_num], "Failed to get free block for data!"); + return ERROR_FAIL; + } + if (s_time_stats_enable) { + /* read block */ + if (duration_start(&blk_proc_time) != 0) { + ctx->running = 0; + LOG_ERROR("Failed to start block read time measurement!"); + return ERROR_FAIL; + } + } + res = ctx->hw->data_read(ctx->cpus[fired_target_num], target_state[fired_target_num].data_len, block->data, + target_state[fired_target_num].block_id, + /* do not ack target data in sync mode, + esp32_apptrace_handle_trace_block() can write response data and will do ack thereafter */ + ctx->mode != ESP_APPTRACE_CMD_MODE_SYNC); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_TARGET_ERROR(ctx->cpus[fired_target_num], "Failed to read data!"); + return res; + } + ctx->last_blk_id = target_state[fired_target_num].block_id; + block->data_len = target_state[fired_target_num].data_len; + ctx->raw_tot_len += block->data_len; + if (s_time_stats_enable) { + if (duration_measure(&blk_proc_time) != 0) { + ctx->running = 0; + LOG_ERROR("Failed to measure block read time!"); + return ERROR_FAIL; + } + /* update stats */ + float brt = duration_elapsed(&blk_proc_time); + if (brt > ctx->stats.max_blk_read_time) + ctx->stats.max_blk_read_time = brt; + if (brt < ctx->stats.min_blk_read_time) + ctx->stats.min_blk_read_time = brt; + + if (duration_start(&blk_proc_time) != 0) { + ctx->running = 0; + LOG_ERROR("Failed to start block proc time measurement!"); + return ERROR_FAIL; + } + } + /* in sync mode do not ack target data on other cores, esp32_apptrace_handle_trace_block() can write response + * data and will do ack thereafter */ + if (ctx->mode != ESP_APPTRACE_CMD_MODE_SYNC) { + for (unsigned int i = 0; i < ctx->cores_num; i++) { + if (i == fired_target_num) + continue; + res = ctx->hw->ctrl_reg_write(ctx->cpus[i], + ctx->last_blk_id, + 0 /*all read*/, + true /*host connected*/, + false /*no host data*/); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_TARGET_ERROR(ctx->cpus[i], "Failed to ack data!"); + return res; + } + LOG_TARGET_DEBUG(ctx->cpus[i], "Ack block %" PRId32, ctx->last_blk_id); + } + res = esp32_apptrace_ready_block_put(ctx, block); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_TARGET_ERROR(ctx->cpus[fired_target_num], "Failed to put ready block of data!"); + return res; + } + } else { + res = esp32_apptrace_handle_trace_block(ctx, block); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len); + return res; + } + res = esp32_apptrace_block_free(ctx, block); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_ERROR("Failed to free ready block!"); + return res; + } + } + if (ctx->stop_tmo != -1.0) { + /* start idle time measurement */ + if (duration_start(&ctx->idle_time) != 0) { + ctx->running = 0; + LOG_ERROR("Failed to start idle time measure!"); + return ERROR_FAIL; + } + } + if (s_time_stats_enable) { + if (duration_measure(&blk_proc_time) != 0) { + ctx->running = 0; + LOG_ERROR("Failed to stop block proc time measure!"); + return ERROR_FAIL; + } + /* update stats */ + float bt = duration_elapsed(&blk_proc_time); + if (bt > ctx->stats.max_blk_proc_time) + ctx->stats.max_blk_proc_time = bt; + if (bt < ctx->stats.min_blk_proc_time) + ctx->stats.min_blk_proc_time = bt; + } + return ERROR_OK; +} + +static inline bool is_sysview_mode(int mode) +{ + return mode == ESP_APPTRACE_CMD_MODE_SYSVIEW || mode == ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE; +} + +static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx) +{ + if (duration_measure(&ctx->read_time) != 0) + LOG_ERROR("Failed to stop trace read time measurement!"); + int res = target_unregister_timer_callback(esp32_apptrace_poll, ctx); + if (res != ERROR_OK) + LOG_ERROR("Failed to unregister target timer handler (%d)!", res); + if (is_sysview_mode(ctx->mode)) { + /* stop tracing */ + res = esp32_sysview_stop(ctx); + if (res != ERROR_OK) + LOG_ERROR("sysview: Failed to stop tracing!"); + } + /* data processor is alive, so wait for all received blocks to be processed */ + res = esp32_apptrace_wait_tracing_finished(ctx); + if (res != ERROR_OK) + LOG_ERROR("Failed to wait for pended blocks (%d)!", res); + res = esp32_apptrace_connect_targets(ctx, false, ctx->target_state == TARGET_RUNNING); + if (res != ERROR_OK) + LOG_ERROR("Failed to disconnect targets (%d)!", res); + esp32_apptrace_print_stats(ctx); + res = esp32_apptrace_cmd_cleanup(ctx); + if (res != ERROR_OK) + LOG_ERROR("Failed to cleanup cmd ctx (%d)!", res); +} + +/* this function must be called after connecting to targets */ +static int esp32_sysview_start(struct esp32_apptrace_cmd_ctx *ctx) +{ + uint8_t cmds[] = { SEGGER_SYSVIEW_COMMAND_ID_START }; + uint32_t fired_target_num = 0; + struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM] = {{0}}; + struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv; + + /* get current block id */ + int res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num); + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to read target data info!"); + return res; + } + if (fired_target_num == UINT32_MAX) { + /* it can happen that there is no pending target data, but block was switched + * in this case block_ids on both CPUs are equal, so select the first one */ + fired_target_num = 0; + } + /* start tracing */ + res = esp_apptrace_usr_block_write(ctx->hw, ctx->cpus[fired_target_num], target_state[fired_target_num].block_id, + cmds, sizeof(cmds)); + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to start tracing!"); + return res; + } + cmd_data->sv_trace_running = 1; + return res; +} + +static int esp32_sysview_stop(struct esp32_apptrace_cmd_ctx *ctx) +{ + uint32_t old_block_id, fired_target_num = 0, empty_target_num = 0; + struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM]; + struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv; + uint8_t cmds[] = { SEGGER_SYSVIEW_COMMAND_ID_STOP }; + struct duration wait_time; + + struct esp32_apptrace_block *block = esp32_apptrace_free_block_get(ctx); + if (!block) { + LOG_ERROR("Failed to get free block for data on (%s)!", target_name(ctx->cpus[fired_target_num])); + return ERROR_FAIL; + } + + /* halt all CPUs (not only one), otherwise it can happen that there is no target data and + * while we are queueing commands another CPU switches tracing block */ + int res = esp32_apptrace_safe_halt_targets(ctx, target_state); + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to halt targets (%d)!", res); + return res; + } + /* it can happen that there is no pending target data + * in this case block_ids on both CPUs are equal, so the first one will be selected */ + for (unsigned int k = 0; k < ctx->cores_num; k++) { + if (target_state[k].data_len) { + fired_target_num = k; + break; + } + } + if (target_state[fired_target_num].data_len) { + /* read pending data without ack, they will be acked when stop command is queued */ + res = ctx->hw->data_read(ctx->cpus[fired_target_num], target_state[fired_target_num].data_len, block->data, + target_state[fired_target_num].block_id, + false /*no ack target data*/); + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to read data on (%s)!", target_name(ctx->cpus[fired_target_num])); + return res; + } + /* process data */ + block->data_len = target_state[fired_target_num].data_len; + res = esp32_apptrace_handle_trace_block(ctx, block); + if (res != ERROR_OK) { + LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len); + return res; + } + } + /* stop tracing and ack target data */ + res = esp_apptrace_usr_block_write(ctx->hw, ctx->cpus[fired_target_num], target_state[fired_target_num].block_id, + cmds, + sizeof(cmds)); + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to stop tracing!"); + return res; + } + if (ctx->cores_num > 1) { + empty_target_num = fired_target_num ? 0 : 1; + /* ack target data on another CPU */ + res = ctx->hw->ctrl_reg_write(ctx->cpus[empty_target_num], target_state[fired_target_num].block_id, + 0 /*target data ack*/, + true /*host connected*/, + false /*no host data*/); + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to ack data on target '%s' (%d)!", + target_name(ctx->cpus[empty_target_num]), res); + return res; + } + } + /* resume targets to allow command processing */ + LOG_INFO("Resume targets"); + bool smp_resumed = false; + for (unsigned int k = 0; k < ctx->cores_num; k++) { + if (smp_resumed && ctx->cpus[k]->smp) { + /* in SMP mode we need to call target_resume for one core only */ + continue; + } + res = target_resume(ctx->cpus[k], 1, 0, 1, 0); + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to resume target '%s' (%d)!", target_name(ctx->cpus[k]), res); + return res; + } + if (ctx->cpus[k]->smp) + smp_resumed = true; + } + /* wait for block switch (command sent), so we can disconnect from targets */ + old_block_id = target_state[fired_target_num].block_id; + if (duration_start(&wait_time) != 0) { + LOG_ERROR("Failed to start trace stop timeout measurement!"); + return ERROR_FAIL; + } + /* we are waiting for the last data from tracing block and also there can be data in the pended + * data buffer */ + /* so we are expecting two TRX block switches at most or stopping due to timeout */ + while (cmd_data->sv_trace_running) { + res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num); + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to read targets data info!"); + return res; + } + if (fired_target_num == UINT32_MAX) { + /* it can happen that there is no pending (last) target data, but block was + * switched */ + /* in this case block_ids on both CPUs are equal, so select the first one */ + fired_target_num = 0; + } + if (target_state[fired_target_num].block_id != old_block_id) { + if (target_state[fired_target_num].data_len) { + /* read last data and ack them */ + res = ctx->hw->data_read(ctx->cpus[fired_target_num], + target_state[fired_target_num].data_len, + block->data, + target_state[fired_target_num].block_id, + true /*ack target data*/); + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to read last data on (%s)!", target_name(ctx->cpus[fired_target_num])); + } else { + if (ctx->cores_num > 1) { + /* ack target data on another CPU */ + empty_target_num = fired_target_num ? 0 : 1; + res = ctx->hw->ctrl_reg_write(ctx->cpus[empty_target_num], + target_state[fired_target_num].block_id, + 0 /*all read*/, + true /*host connected*/, + false /*no host data*/); + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to ack data on target '%s' (%d)!", + target_name(ctx->cpus[empty_target_num]), res); + return res; + } + } + /* process data */ + block->data_len = target_state[fired_target_num].data_len; + res = esp32_apptrace_handle_trace_block(ctx, block); + if (res != ERROR_OK) { + LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", + block->data_len); + return res; + } + } + old_block_id = target_state[fired_target_num].block_id; + } + } + if (duration_measure(&wait_time) != 0) { + LOG_ERROR("Failed to start trace stop timeout measurement!"); + return ERROR_FAIL; + } + const float stop_tmo = LOG_LEVEL_IS(LOG_LVL_DEBUG) ? 30.0 : 0.5; + if (duration_elapsed(&wait_time) >= stop_tmo) { + LOG_INFO("Stop waiting for the last data due to timeout."); + break; + } + } + return res; +} + +static int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const char **argv, int argc) +{ + static struct esp32_apptrace_cmd_ctx s_at_cmd_ctx; + struct esp32_apptrace_cmd_data *cmd_data; + int res = ERROR_FAIL; + enum target_state old_state; + struct target *target = get_current_target(CMD_CTX); + + if (argc < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* command can be invoked on unexamined core, if so find examined one */ + if (target->smp && !target_was_examined(target)) { + struct target_list *head; + struct target *curr; + LOG_WARNING("Current target '%s' was not examined!", target_name(target)); + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + if (target_was_examined(curr)) { + target = curr; + LOG_WARNING("Run command on target '%s'", target_name(target)); + break; + } + } + } + old_state = target->state; + + if (strcmp(argv[0], "start") == 0) { + if (is_sysview_mode(mode)) { + /* init cmd context */ + res = esp32_sysview_cmd_init(&s_at_cmd_ctx, + cmd, + mode, + mode == ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE, + &argv[1], + argc - 1); + if (res != ERROR_OK) { + command_print(cmd, "Failed to init cmd ctx (%d)!", res); + return res; + } + cmd_data = s_at_cmd_ctx.cmd_priv; + if (cmd_data->skip_len != 0) { + s_at_cmd_ctx.running = 0; + esp32_sysview_cmd_cleanup(&s_at_cmd_ctx); + command_print(cmd, "Data skipping not supported!"); + return ERROR_FAIL; + } + s_at_cmd_ctx.process_data = esp32_sysview_process_data; + } else { + res = esp32_apptrace_cmd_init(&s_at_cmd_ctx, + cmd, + mode, + &argv[1], + argc - 1); + if (res != ERROR_OK) { + command_print(cmd, "Failed to init cmd ctx (%d)!", res); + return res; + } + cmd_data = s_at_cmd_ctx.cmd_priv; + s_at_cmd_ctx.process_data = esp32_apptrace_process_data; + } + s_at_cmd_ctx.auto_clean = esp32_apptrace_cmd_stop; + if (cmd_data->wait4halt) { + res = esp32_apptrace_wait4halt(&s_at_cmd_ctx, target); + if (res != ERROR_OK) { + command_print(cmd, "Failed to wait for halt target (%d)!", res); + goto _on_start_error; + } + } + res = esp32_apptrace_connect_targets(&s_at_cmd_ctx, true, old_state == TARGET_RUNNING); + if (res != ERROR_OK) { + command_print(cmd, "Failed to connect to targets (%d)!", res); + goto _on_start_error; + } + if (is_sysview_mode(mode)) { + /* start tracing */ + res = esp32_sysview_start(&s_at_cmd_ctx); + if (res != ERROR_OK) { + esp32_apptrace_connect_targets(&s_at_cmd_ctx, false, old_state == TARGET_RUNNING); + s_at_cmd_ctx.running = 0; + esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx); + command_print(cmd, "sysview: Failed to start tracing!"); + return res; + } + } + res = target_register_timer_callback(esp32_apptrace_poll, + cmd_data->poll_period, + TARGET_TIMER_TYPE_PERIODIC, + &s_at_cmd_ctx); + if (res != ERROR_OK) { + command_print(cmd, "Failed to register target timer handler (%d)!", res); + goto _on_start_error; + } + } else if (strcmp(argv[0], "stop") == 0) { + if (!s_at_cmd_ctx.running) { + command_print(cmd, "Tracing is not running!"); + return ERROR_FAIL; + } + esp32_apptrace_cmd_stop(&s_at_cmd_ctx); + return ERROR_OK; + } else if (strcmp(argv[0], "status") == 0) { + if (s_at_cmd_ctx.running && duration_measure(&s_at_cmd_ctx.read_time) != 0) + LOG_ERROR("Failed to measure trace read time!"); + esp32_apptrace_print_stats(&s_at_cmd_ctx); + return ERROR_OK; + } else if (strcmp(argv[0], "dump") == 0) { + if (is_sysview_mode(mode)) { + command_print(cmd, "Not supported!"); + return ERROR_FAIL; + } + /* [dump outfile] - post-mortem dump without connection to targets */ + res = esp32_apptrace_cmd_init(&s_at_cmd_ctx, + cmd, + mode, + &argv[1], + argc - 1); + if (res != ERROR_OK) { + command_print(cmd, "Failed to init cmd ctx (%d)!", res); + return res; + } + s_at_cmd_ctx.stop_tmo = 0.01; /* use small stop tmo */ + s_at_cmd_ctx.process_data = esp32_apptrace_process_data; + /* check for exit signal and command completion */ + while (!openocd_is_shutdown_pending() && s_at_cmd_ctx.running) { + res = esp32_apptrace_poll(&s_at_cmd_ctx); + if (res != ERROR_OK) { + LOG_ERROR("Failed to poll target for trace data (%d)!", res); + break; + } + /* let registered timer callbacks to run */ + target_call_timer_callbacks(); + } + if (s_at_cmd_ctx.running) { + /* data processor is alive, so wait for all received blocks to be processed */ + res = esp32_apptrace_wait_tracing_finished(&s_at_cmd_ctx); + if (res != ERROR_OK) + LOG_ERROR("Failed to wait for pended blocks (%d)!", res); + } + esp32_apptrace_print_stats(&s_at_cmd_ctx); + res = esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx); + if (res != ERROR_OK) + command_print(cmd, "Failed to cleanup cmd ctx (%d)!", res); + } else { + command_print(cmd, "Invalid action '%s'!", argv[0]); + } + + return res; + +_on_start_error: + s_at_cmd_ctx.running = 0; + if (is_sysview_mode(mode)) + esp32_sysview_cmd_cleanup(&s_at_cmd_ctx); + else + esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx); + return res; +} + +COMMAND_HANDLER(esp32_cmd_apptrace) +{ + return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_GEN, CMD_ARGV, CMD_ARGC); +} + +COMMAND_HANDLER(esp32_cmd_sysview) +{ + return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_SYSVIEW, CMD_ARGV, CMD_ARGC); +} + +COMMAND_HANDLER(esp32_cmd_sysview_mcore) +{ + return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE, CMD_ARGV, CMD_ARGC); +} + +const struct command_registration esp32_apptrace_command_handlers[] = { + { + .name = "apptrace", + .handler = esp32_cmd_apptrace, + .mode = COMMAND_EXEC, + .help = + "App Tracing: application level trace control. Starts, stops or queries tracing process status.", + .usage = + "(start <destination> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status) | (dump <destination>)", + }, + { + .name = "sysview", + .handler = esp32_cmd_sysview, + .mode = COMMAND_EXEC, + .help = + "App Tracing: SEGGER SystemView compatible trace control. Starts, stops or queries tracing process status.", + .usage = + "(start file://<outfile1> [file://<outfile2>] [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status)", + }, + { + .name = "sysview_mcore", + .handler = esp32_cmd_sysview_mcore, + .mode = COMMAND_EXEC, + .help = + "App Tracing: Espressif multi-core SystemView trace control. Starts, stops or queries tracing process status.", + .usage = + "(start file://<outfile> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status)", + }, + COMMAND_REGISTRATION_DONE +}; diff --git a/src/target/espressif/esp32_apptrace.h b/src/target/espressif/esp32_apptrace.h new file mode 100644 index 0000000000..3873342226 --- /dev/null +++ b/src/target/espressif/esp32_apptrace.h @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * ESP32 application trace module * + * Copyright (C) 2017-2019 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESP32_APPTRACE_H +#define OPENOCD_TARGET_ESP32_APPTRACE_H + +#include <helper/command.h> +#include <helper/time_support.h> +#include <target/target.h> + +#define ESP32_APPTRACE_MAX_CORES_NUM 2 + +struct esp32_apptrace_hw { + uint32_t max_block_id; + uint32_t (*max_block_size_get)(struct target *target); + int (*status_reg_read)(struct target *target, uint32_t *stat); + int (*ctrl_reg_write)(struct target *target, + uint32_t block_id, + uint32_t len, + bool conn, + bool data); + int (*ctrl_reg_read)(struct target *target, + uint32_t *block_id, + uint32_t *len, + bool *conn); + int (*data_len_read)(struct target *target, + uint32_t *block_id, + uint32_t *len); + int (*data_read)(struct target *target, + uint32_t size, + uint8_t *buffer, + uint32_t block_id, + bool ack); + uint32_t (*usr_block_max_size_get)(struct target *target); + int (*buffs_write)(struct target *target, + uint32_t bufs_num, + uint32_t buf_sz[], + const uint8_t *bufs[], + uint32_t block_id, + bool ack, + bool data); + int (*leave_trace_crit_section_start)(struct target *target); + int (*leave_trace_crit_section_stop)(struct target *target); +}; + +struct esp_apptrace_host2target_hdr { + uint16_t block_sz; +}; + +struct esp32_apptrace_dest { + void *priv; + int (*write)(void *priv, uint8_t *data, int size); + int (*clean)(void *priv); + bool log_progress; +}; + +struct esp32_apptrace_format { + uint32_t hdr_sz; + int (*core_id_get)(struct target *target, uint8_t *hdr_buf); + uint32_t (*usr_block_len_get)(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len); +}; + +struct esp32_apptrace_cmd_stats { + uint32_t incompl_blocks; + uint32_t lost_bytes; + float min_blk_read_time; + float max_blk_read_time; + float min_blk_proc_time; + float max_blk_proc_time; +}; + +struct esp32_apptrace_cmd_ctx { + volatile int running; + int mode; + /* TODO: use subtargets from target arch info */ + struct target *cpus[ESP32_APPTRACE_MAX_CORES_NUM]; + /* TODO: use cores num from target */ + unsigned int cores_num; + const struct esp32_apptrace_hw *hw; + enum target_state target_state; + uint32_t last_blk_id; + struct list_head free_trace_blocks; + struct list_head ready_trace_blocks; + uint32_t max_trace_block_sz; + struct esp32_apptrace_format trace_format; + int (*process_data)(struct esp32_apptrace_cmd_ctx *ctx, unsigned int core_id, uint8_t *data, uint32_t data_len); + void (*auto_clean)(struct esp32_apptrace_cmd_ctx *ctx); + uint32_t tot_len; + uint32_t raw_tot_len; + float stop_tmo; + struct esp32_apptrace_cmd_stats stats; + struct duration read_time; + struct duration idle_time; + void *cmd_priv; + struct target *target; + struct command_invocation *cmd; +}; + +struct esp32_apptrace_cmd_data { + struct esp32_apptrace_dest data_dest; + uint32_t poll_period; + uint32_t max_len; + uint32_t skip_len; + bool wait4halt; +}; + +int esp32_apptrace_cmd_ctx_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, struct command_invocation *cmd, int mode); +int esp32_apptrace_cmd_ctx_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx); +void esp32_apptrace_cmd_args_parse(struct esp32_apptrace_cmd_ctx *cmd_ctx, + struct esp32_apptrace_cmd_data *cmd_data, + const char **argv, + int argc); +int esp32_apptrace_dest_init(struct esp32_apptrace_dest dest[], const char *dest_paths[], unsigned int max_dests); +int esp32_apptrace_dest_cleanup(struct esp32_apptrace_dest dest[], unsigned int max_dests); +int esp_apptrace_usr_block_write(const struct esp32_apptrace_hw *hw, struct target *target, + uint32_t block_id, + const uint8_t *data, + uint32_t size); + +extern const struct command_registration esp32_apptrace_command_handlers[]; + +#endif /* OPENOCD_TARGET_ESP32_APPTRACE_H */ diff --git a/src/target/espressif/esp32_sysview.c b/src/target/espressif/esp32_sysview.c new file mode 100644 index 0000000000..2fe2157780 --- /dev/null +++ b/src/target/espressif/esp32_sysview.c @@ -0,0 +1,554 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * ESP32 sysview tracing module * + * Copyright (C) 2020 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/log.h> +#include "esp32_apptrace.h" +#include "esp32_sysview.h" +#include "segger_sysview.h" + +/* in SystemView mode core ID is passed in event ID field */ +#define ESP32_SYSVIEW_USER_BLOCK_CORE(_v_) (0) /* not used */ +#define ESP32_SYSVIEW_USER_BLOCK_LEN(_v_) (_v_) +#define ESP32_SYSVIEW_USER_BLOCK_HDR_SZ 2 + +struct esp_sysview_target2host_hdr { + uint8_t block_sz; + uint8_t wr_sz; +}; +#define SYSVIEW_BLOCK_SIZE_OFFSET 0 +#define SYSVIEW_WR_SIZE_OFFSET 1 + +static int esp_sysview_trace_header_write(struct esp32_apptrace_cmd_ctx *ctx, bool mcore_format); +static int esp32_sysview_core_id_get(struct target *target, uint8_t *hdr_buf); +static uint32_t esp32_sysview_usr_block_len_get(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len); + +int esp32_sysview_cmd_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, + struct command_invocation *cmd, + int mode, + bool mcore_format, + const char **argv, + int argc) +{ + struct esp32_sysview_cmd_data *cmd_data; + + if (argc < 1) { + command_print(cmd, "Not enough args! Need trace data destination!"); + return ERROR_FAIL; + } + + int res = esp32_apptrace_cmd_ctx_init(cmd_ctx, cmd, mode); + if (res != ERROR_OK) + return res; + + int core_num = cmd_ctx->cores_num; + + if (!mcore_format && argc < core_num) { + command_print(cmd, "Not enough args! Need %d trace data destinations!", core_num); + res = ERROR_FAIL; + goto on_error; + } + + cmd_data = calloc(1, sizeof(*cmd_data)); + if (!cmd_data) { + command_print(cmd, "No memory for command data!"); + res = ERROR_FAIL; + goto on_error; + } + cmd_ctx->cmd_priv = cmd_data; + cmd_data->mcore_format = mcore_format; + + /*outfile1 [outfile2] [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] */ + int dests_num = esp32_apptrace_dest_init(cmd_data->data_dests, argv, !mcore_format ? core_num : 1); + if (!mcore_format && dests_num < core_num) { + command_print(cmd, "Not enough args! Need %d trace data destinations!", core_num); + free(cmd_data); + res = ERROR_FAIL; + goto on_error; + } + cmd_data->apptrace.max_len = UINT32_MAX; + cmd_data->apptrace.poll_period = 0 /*ms*/; + cmd_ctx->stop_tmo = -1.0; /* infinite */ + if (argc > dests_num) { + /* parse remaining args */ + esp32_apptrace_cmd_args_parse(cmd_ctx, + &cmd_data->apptrace, + &argv[dests_num], + argc - dests_num); + } + LOG_USER("App trace params: from %d cores, size %u bytes, stop_tmo %g s, " + "poll period %u ms, wait_rst %d, skip %u bytes", + cmd_ctx->cores_num, + cmd_data->apptrace.max_len, + cmd_ctx->stop_tmo, + cmd_data->apptrace.poll_period, + cmd_data->apptrace.wait4halt, + cmd_data->apptrace.skip_len); + + cmd_ctx->trace_format.hdr_sz = ESP32_SYSVIEW_USER_BLOCK_HDR_SZ; + cmd_ctx->trace_format.core_id_get = esp32_sysview_core_id_get; + cmd_ctx->trace_format.usr_block_len_get = esp32_sysview_usr_block_len_get; + + res = esp_sysview_trace_header_write(cmd_ctx, mcore_format); + if (res != ERROR_OK) { + command_print(cmd, "Failed to write trace header (%d)!", res); + esp32_apptrace_dest_cleanup(cmd_data->data_dests, core_num); + free(cmd_data); + return res; + } + return ERROR_OK; +on_error: + cmd_ctx->running = 0; + esp32_apptrace_cmd_ctx_cleanup(cmd_ctx); + return res; +} + +int esp32_sysview_cmd_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx) +{ + struct esp32_sysview_cmd_data *cmd_data = cmd_ctx->cmd_priv; + + esp32_apptrace_dest_cleanup(cmd_data->data_dests, cmd_ctx->cores_num); + free(cmd_data); + cmd_ctx->cmd_priv = NULL; + esp32_apptrace_cmd_ctx_cleanup(cmd_ctx); + return ERROR_OK; +} + +static int esp32_sysview_core_id_get(struct target *target, uint8_t *hdr_buf) +{ + /* for sysview compressed apptrace header is used, so core id is encoded in sysview packet */ + return 0; +} + +static uint32_t esp32_sysview_usr_block_len_get(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len) +{ + *wr_len = ESP32_SYSVIEW_USER_BLOCK_LEN(hdr_buf[SYSVIEW_WR_SIZE_OFFSET]); + return ESP32_SYSVIEW_USER_BLOCK_LEN(hdr_buf[SYSVIEW_BLOCK_SIZE_OFFSET]); +} + +static int esp_sysview_trace_header_write(struct esp32_apptrace_cmd_ctx *ctx, bool mcore_format) +{ + struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv; + char *hdr_str; + int dests_num; + + if (!mcore_format) { + hdr_str = ";\n" + "; Version " SYSVIEW_MIN_VER_STRING "\n" + "; Author Espressif Inc\n" + ";\n"; + dests_num = ctx->cores_num; + } else { + hdr_str = ";\n" + "; Version " SYSVIEW_MIN_VER_STRING "\n" + "; Author Espressif Inc\n" + "; ESP_Extension\n" + ";\n"; + dests_num = 1; + } + + int hdr_len = strlen(hdr_str); + for (int i = 0; i < dests_num; i++) { + int res = cmd_data->data_dests[i].write(cmd_data->data_dests[i].priv, + (uint8_t *)hdr_str, + hdr_len); + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to write %u bytes to dest %d!", hdr_len, i); + return ERROR_FAIL; + } + } + return ERROR_OK; +} + +static void sysview_encode_u32(uint8_t **dest, uint32_t val) +{ + uint8_t *sv_ptr = *dest; + while (val > 0x7F) { + *sv_ptr++ = (uint8_t)(val | 0x80); + val >>= 7; + } + *sv_ptr++ = (uint8_t)val; + *dest = sv_ptr; +} + +static uint32_t esp_sysview_decode_u32(uint8_t **ptr) +{ + uint32_t val = 0; + for (int k = 0;; k++, (*ptr)++) { + if (**ptr & 0x80) { + val |= (uint32_t)(**ptr & ~0x80) << 7 * k; + } else { + val |= (uint32_t)**ptr << 7 * k; + (*ptr)++; + break; + } + } + return val; +} + +static uint16_t esp_sysview_decode_plen(uint8_t **ptr) +{ + uint16_t payload_len = 0; + uint8_t *p = *ptr; + /* here pkt points to encoded payload length */ + if (*p & 0x80) { + payload_len = *(p + 1); /* higher part */ + payload_len = (payload_len << 7) | (*p & ~0x80);/* lower 7 bits */ + p += 2; /* payload len (2 bytes) */ + } else { + payload_len = *p; + p++; /* payload len (1 byte) */ + } + *ptr = p; + + return payload_len; +} + +static uint16_t esp_sysview_get_predef_payload_len(uint16_t id, uint8_t *pkt) +{ + uint16_t len; + uint8_t *ptr = pkt; + + switch (id) { + case SYSVIEW_EVTID_OVERFLOW: + case SYSVIEW_EVTID_ISR_ENTER: + case SYSVIEW_EVTID_TASK_START_EXEC: + case SYSVIEW_EVTID_TASK_START_READY: + case SYSVIEW_EVTID_TASK_CREATE: + case SYSVIEW_EVTID_SYSTIME_CYCLES: + case SYSVIEW_EVTID_USER_START: + case SYSVIEW_EVTID_USER_STOP: + case SYSVIEW_EVTID_TIMER_ENTER: + /*ENCODE_U32 */ + esp_sysview_decode_u32(&ptr); + len = ptr - pkt; + break; + case SYSVIEW_EVTID_TASK_STOP_READY: + case SYSVIEW_EVTID_SYSTIME_US: + /*2*ENCODE_U32 */ + esp_sysview_decode_u32(&ptr); + esp_sysview_decode_u32(&ptr); + len = ptr - pkt; + break; + case SYSVIEW_EVTID_SYSDESC: + /*str(128 + 1) */ + len = *ptr + 1; + break; + case SYSVIEW_EVTID_TASK_INFO: + case SYSVIEW_EVTID_MODULEDESC: + /*2*ENCODE_U32 + str */ + esp_sysview_decode_u32(&ptr); + esp_sysview_decode_u32(&ptr); + /* TODO: add support for strings longer then 255 bytes */ + len = ptr - pkt + *ptr + 1; + break; + case SYSVIEW_EVTID_STACK_INFO: + /*4*ENCODE_U32 */ + esp_sysview_decode_u32(&ptr); + esp_sysview_decode_u32(&ptr); + esp_sysview_decode_u32(&ptr); + esp_sysview_decode_u32(&ptr); + len = ptr - pkt; + break; + case SYSVIEW_EVTID_ISR_EXIT: + case SYSVIEW_EVTID_TASK_STOP_EXEC: + case SYSVIEW_EVTID_TRACE_START: + case SYSVIEW_EVTID_TRACE_STOP: + case SYSVIEW_EVTID_IDLE: + case SYSVIEW_EVTID_ISR_TO_SCHEDULER: + case SYSVIEW_EVTID_TIMER_EXIT: + len = 0; + break; + + /*case SYSVIEW_EVTID_NOP: */ + default: + LOG_ERROR("sysview: Unsupported predef event %d!", id); + len = 0; + } + return len; +} + +static uint16_t esp_sysview_parse_packet(uint8_t *pkt_buf, + uint32_t *pkt_len, + unsigned int *pkt_core_id, + uint32_t *delta, + uint32_t *delta_len, + bool clear_core_bit) +{ + uint8_t *pkt = pkt_buf; + uint16_t event_id = 0, payload_len = 0; + + *pkt_core_id = 0; + *pkt_len = 0; + /* 1-2 byte of message type, 0-2 byte of payload length, payload, 1-5 bytes of timestamp. */ + if (*pkt & 0x80) { + if (*(pkt + 1) & (1 << 6)) { + if (clear_core_bit) + *(pkt + 1) &= ~(1 << 6); /* clear core_id bit */ + *pkt_core_id = 1; + } + event_id = *(pkt + 1) & ~(1 << 6); /* higher part */ + event_id = (event_id << 7) | (*pkt & ~0x80); /* lower 7 bits */ + pkt += 2; /* event_id (2 bytes) */ + /* here pkt points to encoded payload length */ + payload_len = esp_sysview_decode_plen(&pkt); + } else { + if (*pkt & (1 << 6)) { + if (clear_core_bit) + *pkt &= ~(1 << 6); /* clear core_id bit */ + *pkt_core_id = 1; + } + /* event_id (1 byte) */ + event_id = *pkt & ~(1 << 6); + pkt++; + if (event_id < 24) + payload_len = esp_sysview_get_predef_payload_len(event_id, pkt); + else + payload_len = esp_sysview_decode_plen(&pkt); + } + pkt += payload_len; + uint8_t *delta_start = pkt; + *delta = esp_sysview_decode_u32(&pkt); + *delta_len = pkt - delta_start; + *pkt_len = pkt - pkt_buf; + LOG_DEBUG("sysview: evt %d len %d plen %d dlen %d", + event_id, + *pkt_len, + payload_len, + *delta_len); + return event_id; +} + +static int esp32_sysview_write_packet(struct esp32_sysview_cmd_data *cmd_data, + int pkt_core_id, uint32_t pkt_len, uint8_t *pkt_buf, uint32_t delta_len, uint8_t *delta_buf) +{ + if (!cmd_data->data_dests[pkt_core_id].write) + return ERROR_FAIL; + + int res = cmd_data->data_dests[pkt_core_id].write(cmd_data->data_dests[pkt_core_id].priv, pkt_buf, pkt_len); + + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to write %u bytes to dest %d!", pkt_len, pkt_core_id); + return res; + } + if (delta_len) { + /* write packet with modified delta */ + res = cmd_data->data_dests[pkt_core_id].write(cmd_data->data_dests[pkt_core_id].priv, delta_buf, delta_len); + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to write %u bytes of delta to dest %d!", delta_len, pkt_core_id); + return res; + } + } + return ERROR_OK; +} + +static int esp32_sysview_process_packet(struct esp32_apptrace_cmd_ctx *ctx, + unsigned int pkt_core_id, uint16_t event_id, uint32_t delta, uint32_t delta_len, + uint32_t pkt_len, uint8_t *pkt_buf) +{ + struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv; + int pkt_core_changed = 0; + uint32_t new_delta_len = 0; + uint8_t new_delta_buf[10]; + uint32_t wr_len = pkt_len; + + if (ctx->cores_num > 1) { + if (cmd_data->sv_last_core_id == pkt_core_id) { + /* if this packet is for the same core as the prev one acc delta and write packet unmodified */ + cmd_data->sv_acc_time_delta += delta; + } else { + /* if this packet is for another core then prev one set acc delta to the packet's delta */ + uint8_t *delta_ptr = new_delta_buf; + sysview_encode_u32(&delta_ptr, delta + cmd_data->sv_acc_time_delta); + cmd_data->sv_acc_time_delta = delta; + wr_len -= delta_len; + new_delta_len = delta_ptr - new_delta_buf; + pkt_core_changed = 1; + } + cmd_data->sv_last_core_id = pkt_core_id; + } + if (pkt_core_id >= ctx->cores_num) { + LOG_WARNING("sysview: invalid core ID in packet %d, must be less then %d! Event id %d", + pkt_core_id, + ctx->cores_num, + event_id); + return ERROR_FAIL; + } + int res = esp32_sysview_write_packet(cmd_data, + pkt_core_id, + wr_len, + pkt_buf, + new_delta_len, + new_delta_buf); + if (res != ERROR_OK) + return res; + for (unsigned int i = 0; i < ctx->cores_num; i++) { + if (pkt_core_id == i) + continue; + switch (event_id) { + /* messages below should be sent to trace destinations for all cores */ + case SYSVIEW_EVTID_TRACE_START: + case SYSVIEW_EVTID_TRACE_STOP: + case SYSVIEW_EVTID_SYSTIME_CYCLES: + case SYSVIEW_EVTID_SYSTIME_US: + case SYSVIEW_EVTID_SYSDESC: + case SYSVIEW_EVTID_TASK_INFO: + case SYSVIEW_EVTID_STACK_INFO: + case SYSVIEW_EVTID_MODULEDESC: + case SYSVIEW_EVTID_INIT: + case SYSVIEW_EVTID_NUMMODULES: + case SYSVIEW_EVTID_OVERFLOW: + case SYSVIEW_EVTID_TASK_START_READY: + /* if packet's source core has changed */ + wr_len = pkt_len; + if (pkt_core_changed) { + /* clone packet with unmodified delta */ + new_delta_len = 0; + } else { + /* clone packet with modified delta */ + uint8_t *delta_ptr = new_delta_buf; + sysview_encode_u32(&delta_ptr, cmd_data->sv_acc_time_delta /*delta has been accumulated above*/); + wr_len -= delta_len; + new_delta_len = delta_ptr - new_delta_buf; + } + LOG_DEBUG("sysview: Redirect %d bytes of event %d to dest %d", wr_len, event_id, i); + res = esp32_sysview_write_packet(cmd_data, + i, + wr_len, + pkt_buf, + new_delta_len, + new_delta_buf); + if (res != ERROR_OK) + return res; + /* messages above are cloned to trace files for both cores, + * so reset acc time delta, both files have actual delta + * info */ + cmd_data->sv_acc_time_delta = 0; + break; + default: + break; + } + } + return ERROR_OK; +} + +int esp32_sysview_process_data(struct esp32_apptrace_cmd_ctx *ctx, + unsigned int core_id, + uint8_t *data, + uint32_t data_len) +{ + struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv; + + LOG_DEBUG("sysview: Read from target %d bytes [%x %x %x %x]", + data_len, + data[0], + data[1], + data[2], + data[3]); + int res; + uint32_t processed = 0; + if (core_id >= ctx->cores_num) { + LOG_ERROR("sysview: Invalid core id %d in user block!", core_id); + return ERROR_FAIL; + } + if (cmd_data->mcore_format) + core_id = 0; + if (ctx->tot_len == 0) { + /* handle sync seq */ + if (data_len < SYSVIEW_SYNC_LEN) { + LOG_ERROR("sysview: Invalid init seq len %d!", data_len); + return ERROR_FAIL; + } + LOG_DEBUG("sysview: Process %d sync bytes", SYSVIEW_SYNC_LEN); + uint8_t sync_seq[SYSVIEW_SYNC_LEN] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + if (memcmp(data, sync_seq, SYSVIEW_SYNC_LEN) != 0) { + LOG_ERROR("sysview: Invalid init seq [%x %x %x %x %x %x %x %x %x %x]", + data[0], data[1], data[2], data[3], data[4], data[5], data[6], + data[7], data[8], data[9]); + return ERROR_FAIL; + } + res = cmd_data->data_dests[core_id].write(cmd_data->data_dests[core_id].priv, + data, + SYSVIEW_SYNC_LEN); + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to write %u sync bytes to dest %d!", + SYSVIEW_SYNC_LEN, + core_id); + return res; + } + if (!cmd_data->mcore_format) { + for (unsigned int i = 0; i < ctx->cores_num; i++) { + if (core_id == i) + continue; + res = + cmd_data->data_dests[i].write(cmd_data->data_dests[i].priv, + data, + SYSVIEW_SYNC_LEN); + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to write %u sync bytes to dest %d!", SYSVIEW_SYNC_LEN, core_id ? 0 : 1); + return res; + } + } + } + ctx->tot_len += SYSVIEW_SYNC_LEN; + processed += SYSVIEW_SYNC_LEN; + } + while (processed < data_len) { + unsigned int pkt_core_id; + uint32_t delta_len = 0; + uint32_t pkt_len = 0, delta = 0; + uint16_t event_id = esp_sysview_parse_packet(data + processed, + &pkt_len, + &pkt_core_id, + &delta, + &delta_len, + !cmd_data->mcore_format); + LOG_DEBUG("sysview: Process packet: core %d, %d id, %d bytes [%x %x %x %x]", + pkt_core_id, + event_id, + pkt_len, + data[processed + 0], + data[processed + 1], + data[processed + 2], + data[processed + 3]); + if (!cmd_data->mcore_format) { + res = esp32_sysview_process_packet(ctx, + pkt_core_id, + event_id, + delta, + delta_len, + pkt_len, + data + processed); + if (res != ERROR_OK) + return res; + } else { + res = cmd_data->data_dests[0].write(cmd_data->data_dests[0].priv, data + processed, pkt_len); + if (res != ERROR_OK) { + LOG_ERROR("sysview: Failed to write %u bytes to dest %d!", pkt_len, 0); + return res; + } + } + if (event_id == SYSVIEW_EVTID_TRACE_STOP) + cmd_data->sv_trace_running = 0; + ctx->tot_len += pkt_len; + processed += pkt_len; + } + LOG_USER("%u ", ctx->tot_len); + /* check for stop condition */ + if (ctx->tot_len > cmd_data->apptrace.skip_len && + (ctx->tot_len - cmd_data->apptrace.skip_len >= cmd_data->apptrace.max_len)) { + ctx->running = 0; + if (duration_measure(&ctx->read_time) != 0) { + LOG_ERROR("Failed to stop trace read time measure!"); + return ERROR_FAIL; + } + } + return ERROR_OK; +} diff --git a/src/target/espressif/esp32_sysview.h b/src/target/espressif/esp32_sysview.h new file mode 100644 index 0000000000..230ce46329 --- /dev/null +++ b/src/target/espressif/esp32_sysview.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * ESP32 sysview tracing module * + * Copyright (C) 2020 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESP32_SYSVIEW_H +#define OPENOCD_TARGET_ESP32_SYSVIEW_H + +#include <stdint.h> +#include "esp32_apptrace.h" + +struct esp32_sysview_cmd_data { + /* Should be the first field. Generic apptrace command handling code accesses it */ + struct esp32_apptrace_cmd_data apptrace; + struct esp32_apptrace_dest data_dests[ESP32_APPTRACE_MAX_CORES_NUM]; + bool mcore_format; + uint32_t sv_acc_time_delta; + unsigned int sv_last_core_id; + int sv_trace_running; +}; + +struct esp32_apptrace_cmd_ctx; + +int esp32_sysview_cmd_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, + struct command_invocation *cmd, + int mode, + bool mcore_format, + const char **argv, + int argc); +int esp32_sysview_cmd_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx); +int esp32_sysview_process_data(struct esp32_apptrace_cmd_ctx *ctx, + unsigned int core_id, + uint8_t *data, + uint32_t data_len); + +#endif /* OPENOCD_TARGET_ESP32_SYSVIEW_H */ diff --git a/src/target/espressif/esp32s2.c b/src/target/espressif/esp32s2.c new file mode 100644 index 0000000000..2abde479ea --- /dev/null +++ b/src/target/espressif/esp32s2.c @@ -0,0 +1,540 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * ESP32-S2 target for OpenOCD * + * Copyright (C) 2019 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/time_support.h> +#include "assert.h" +#include <target/target.h> +#include <target/target_type.h> +#include <target/semihosting_common.h> +#include "esp_xtensa.h" +#include "esp_xtensa_semihosting.h" + +#define ESP32_S2_RTC_DATA_LOW 0x50000000 +#define ESP32_S2_RTC_DATA_HIGH 0x50002000 +#define ESP32_S2_DR_REG_LOW 0x3f400000 +#define ESP32_S2_DR_REG_HIGH 0x3f4d3FFC +#define ESP32_S2_SYS_RAM_LOW 0x60000000UL +#define ESP32_S2_SYS_RAM_HIGH (ESP32_S2_SYS_RAM_LOW + 0x20000000UL) + +/* ESP32 WDT */ +#define ESP32_S2_WDT_WKEY_VALUE 0x50d83aa1 +#define ESP32_S2_TIMG0_BASE 0x3f41F000 +#define ESP32_S2_TIMG1_BASE 0x3f420000 +#define ESP32_S2_TIMGWDT_CFG0_OFF 0x48 +#define ESP32_S2_TIMGWDT_PROTECT_OFF 0x64 +#define ESP32_S2_TIMG0WDT_CFG0 (ESP32_S2_TIMG0_BASE + ESP32_S2_TIMGWDT_CFG0_OFF) +#define ESP32_S2_TIMG1WDT_CFG0 (ESP32_S2_TIMG1_BASE + ESP32_S2_TIMGWDT_CFG0_OFF) +#define ESP32_S2_TIMG0WDT_PROTECT (ESP32_S2_TIMG0_BASE + ESP32_S2_TIMGWDT_PROTECT_OFF) +#define ESP32_S2_TIMG1WDT_PROTECT (ESP32_S2_TIMG1_BASE + ESP32_S2_TIMGWDT_PROTECT_OFF) +#define ESP32_S2_RTCCNTL_BASE 0x3f408000 +#define ESP32_S2_RTCWDT_CFG_OFF 0x94 +#define ESP32_S2_RTCWDT_PROTECT_OFF 0xAC +#define ESP32_S2_SWD_CONF_OFF 0xB0 +#define ESP32_S2_SWD_WPROTECT_OFF 0xB4 +#define ESP32_S2_RTC_CNTL_DIG_PWC_REG_OFF 0x8C +#define ESP32_S2_RTC_CNTL_DIG_PWC_REG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_RTC_CNTL_DIG_PWC_REG_OFF) +#define ESP32_S2_RTCWDT_CFG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_RTCWDT_CFG_OFF) +#define ESP32_S2_RTCWDT_PROTECT (ESP32_S2_RTCCNTL_BASE + ESP32_S2_RTCWDT_PROTECT_OFF) +#define ESP32_S2_SWD_CONF_REG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_SWD_CONF_OFF) +#define ESP32_S2_SWD_WPROTECT_REG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_SWD_WPROTECT_OFF) +#define ESP32_S2_SWD_AUTO_FEED_EN_M BIT(31) +#define ESP32_S2_SWD_WKEY_VALUE 0x8F1D312AU +#define ESP32_S2_OPTIONS0 (ESP32_S2_RTCCNTL_BASE + 0x0000) +#define ESP32_S2_SW_SYS_RST_M 0x80000000 +#define ESP32_S2_SW_SYS_RST_V 0x1 +#define ESP32_S2_SW_SYS_RST_S 31 +#define ESP32_S2_SW_STALL_PROCPU_C0_M ((ESP32_S2_SW_STALL_PROCPU_C0_V) << (ESP32_S2_SW_STALL_PROCPU_C0_S)) +#define ESP32_S2_SW_STALL_PROCPU_C0_V 0x3 +#define ESP32_S2_SW_STALL_PROCPU_C0_S 2 +#define ESP32_S2_SW_CPU_STALL (ESP32_S2_RTCCNTL_BASE + 0x00B8) +#define ESP32_S2_SW_STALL_PROCPU_C1_M ((ESP32_S2_SW_STALL_PROCPU_C1_V) << (ESP32_S2_SW_STALL_PROCPU_C1_S)) +#define ESP32_S2_SW_STALL_PROCPU_C1_V 0x3FU +#define ESP32_S2_SW_STALL_PROCPU_C1_S 26 +#define ESP32_S2_CLK_CONF (ESP32_S2_RTCCNTL_BASE + 0x0074) +#define ESP32_S2_CLK_CONF_DEF 0x1583218 +#define ESP32_S2_STORE4 (ESP32_S2_RTCCNTL_BASE + 0x00BC) +#define ESP32_S2_STORE5 (ESP32_S2_RTCCNTL_BASE + 0x00C0) +#define ESP32_S2_DPORT_PMS_OCCUPY_3 0x3F4C10E0 + +#define ESP32_S2_TRACEMEM_BLOCK_SZ 0x4000 + +#define ESP32_S2_DR_REG_UART_BASE 0x3f400000 +#define ESP32_S2_REG_UART_BASE(i) (ESP32_S2_DR_REG_UART_BASE + (i) * 0x10000) +#define ESP32_S2_UART_DATE_REG(i) (ESP32_S2_REG_UART_BASE(i) + 0x74) +struct esp32s2_common { + struct esp_xtensa_common esp_xtensa; +}; + +static int esp32s2_soc_reset(struct target *target); +static int esp32s2_disable_wdts(struct target *target); + +static int esp32s2_assert_reset(struct target *target) +{ + return ERROR_OK; +} + +static int esp32s2_deassert_reset(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + + LOG_TARGET_DEBUG(target, "begin"); + + int res = xtensa_deassert_reset(target); + if (res != ERROR_OK) + return res; + + /* restore configured value + esp32s2_soc_reset() modified it, but can not restore just after SW reset for some reason (???) */ + res = xtensa_smpbreak_write(xtensa, xtensa->smp_break); + if (res != ERROR_OK) { + LOG_ERROR("Failed to restore smpbreak (%d)!", res); + return res; + } + return ERROR_OK; +} + +static int esp32s2_soft_reset_halt(struct target *target) +{ + LOG_TARGET_DEBUG(target, "begin"); + + /* Reset the SoC first */ + int res = esp32s2_soc_reset(target); + if (res != ERROR_OK) + return res; + return xtensa_soft_reset_halt(target); +} + +static int esp32s2_set_peri_reg_mask(struct target *target, + target_addr_t addr, + uint32_t mask, + uint32_t val) +{ + uint32_t reg_val; + int res = target_read_u32(target, addr, ®_val); + if (res != ERROR_OK) + return res; + reg_val = (reg_val & (~mask)) | val; + res = target_write_u32(target, addr, reg_val); + if (res != ERROR_OK) + return res; + + return ERROR_OK; +} + +static int esp32s2_stall_set(struct target *target, bool stall) +{ + LOG_TARGET_DEBUG(target, "begin"); + + int res = esp32s2_set_peri_reg_mask(target, + ESP32_S2_SW_CPU_STALL, + ESP32_S2_SW_STALL_PROCPU_C1_M, + stall ? 0x21U << ESP32_S2_SW_STALL_PROCPU_C1_S : 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_SW_CPU_STALL (%d)!", res); + return res; + } + res = esp32s2_set_peri_reg_mask(target, + ESP32_S2_OPTIONS0, + ESP32_S2_SW_STALL_PROCPU_C0_M, + stall ? 0x2 << ESP32_S2_SW_STALL_PROCPU_C0_S : 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_OPTIONS0 (%d)!", res); + return res; + } + return ERROR_OK; +} + +static inline int esp32s2_stall(struct target *target) +{ + return esp32s2_stall_set(target, true); +} + +static inline int esp32s2_unstall(struct target *target) +{ + return esp32s2_stall_set(target, false); +} + +/* Reset ESP32-S2's peripherals. +Postconditions: all peripherals except RTC_CNTL are reset, CPU's PC is undefined, PRO CPU is halted, APP CPU is in reset +How this works: +0. make sure target is halted; if not, try to halt it; if that fails, try to reset it (via OCD) and then halt +1. Resets clock related registers +2. Stalls CPU +3. trigger SoC reset using RTC_CNTL_SW_SYS_RST bit +4. CPU is reset and stalled at the first reset vector instruction +5. wait for the OCD to be reset +6. halt the target +7. Unstalls CPU +8. Disables WDTs and trace memory mapping +*/ +static int esp32s2_soc_reset(struct target *target) +{ + int res; + struct xtensa *xtensa = target_to_xtensa(target); + + LOG_DEBUG("start"); + + /* In order to write to peripheral registers, target must be halted first */ + if (target->state != TARGET_HALTED) { + LOG_TARGET_DEBUG(target, "Target not halted before SoC reset, trying to halt it first"); + xtensa_halt(target); + res = target_wait_state(target, TARGET_HALTED, 1000); + if (res != ERROR_OK) { + LOG_TARGET_DEBUG(target, "Couldn't halt target before SoC reset, trying to do reset-halt"); + res = xtensa_assert_reset(target); + if (res != ERROR_OK) { + LOG_TARGET_ERROR( + target, + "Couldn't halt target before SoC reset! (xtensa_assert_reset returned %d)", + res); + return res; + } + alive_sleep(10); + xtensa_poll(target); + int reset_halt_save = target->reset_halt; + target->reset_halt = 1; + res = xtensa_deassert_reset(target); + target->reset_halt = reset_halt_save; + if (res != ERROR_OK) { + LOG_TARGET_ERROR( + target, + "Couldn't halt target before SoC reset! (xtensa_deassert_reset returned %d)", + res); + return res; + } + alive_sleep(10); + xtensa_poll(target); + xtensa_halt(target); + res = target_wait_state(target, TARGET_HALTED, 1000); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Couldn't halt target before SoC reset"); + return res; + } + } + } + + assert(target->state == TARGET_HALTED); + + /* Set some clock-related RTC registers to the default values */ + res = target_write_u32(target, ESP32_S2_STORE4, 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_STORE4 (%d)!", res); + return res; + } + res = target_write_u32(target, ESP32_S2_STORE5, 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_STORE5 (%d)!", res); + return res; + } + res = target_write_u32(target, ESP32_S2_RTC_CNTL_DIG_PWC_REG, 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_RTC_CNTL_DIG_PWC_REG (%d)!", res); + return res; + } + res = target_write_u32(target, ESP32_S2_CLK_CONF, ESP32_S2_CLK_CONF_DEF); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_CLK_CONF (%d)!", res); + return res; + } + /* Stall CPU */ + res = esp32s2_stall(target); + if (res != ERROR_OK) + return res; + /* enable stall */ + res = xtensa_smpbreak_write(xtensa, OCDDCR_RUNSTALLINEN); + if (res != ERROR_OK) { + LOG_ERROR("Failed to set smpbreak (%d)!", res); + return res; + } + /* Reset CPU */ + xtensa->suppress_dsr_errors = true; + res = esp32s2_set_peri_reg_mask(target, + ESP32_S2_OPTIONS0, + ESP32_S2_SW_SYS_RST_M, + BIT(ESP32_S2_SW_SYS_RST_S)); + xtensa->suppress_dsr_errors = false; + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_OPTIONS0 (%d)!", res); + return res; + } + /* Wait for SoC to reset */ + alive_sleep(100); + int64_t timeout = timeval_ms() + 100; + while (target->state != TARGET_RESET && target->state != TARGET_RUNNING) { + alive_sleep(10); + xtensa_poll(target); + if (timeval_ms() >= timeout) { + LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state=%d", + target->state); + return ERROR_TARGET_TIMEOUT; + } + } + + xtensa_halt(target); + res = target_wait_state(target, TARGET_HALTED, 1000); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Couldn't halt target before SoC reset"); + return res; + } + /* Unstall CPU */ + res = esp32s2_unstall(target); + if (res != ERROR_OK) + return res; + /* Disable WDTs */ + res = esp32s2_disable_wdts(target); + if (res != ERROR_OK) + return res; + /* Disable trace memory mapping */ + res = target_write_u32(target, ESP32_S2_DPORT_PMS_OCCUPY_3, 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_DPORT_PMS_OCCUPY_3 (%d)!", res); + return res; + } + return ERROR_OK; +} + +static int esp32s2_disable_wdts(struct target *target) +{ + /* TIMG1 WDT */ + int res = target_write_u32(target, ESP32_S2_TIMG0WDT_PROTECT, ESP32_S2_WDT_WKEY_VALUE); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_TIMG0WDT_PROTECT (%d)!", res); + return res; + } + res = target_write_u32(target, ESP32_S2_TIMG0WDT_CFG0, 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_TIMG0WDT_CFG0 (%d)!", res); + return res; + } + /* TIMG2 WDT */ + res = target_write_u32(target, ESP32_S2_TIMG1WDT_PROTECT, ESP32_S2_WDT_WKEY_VALUE); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_TIMG1WDT_PROTECT (%d)!", res); + return res; + } + res = target_write_u32(target, ESP32_S2_TIMG1WDT_CFG0, 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_TIMG1WDT_CFG0 (%d)!", res); + return res; + } + /* RTC WDT */ + res = target_write_u32(target, ESP32_S2_RTCWDT_PROTECT, ESP32_S2_WDT_WKEY_VALUE); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_RTCWDT_PROTECT (%d)!", res); + return res; + } + res = target_write_u32(target, ESP32_S2_RTCWDT_CFG, 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_RTCWDT_CFG (%d)!", res); + return res; + } + /* Enable SWD auto-feed */ + res = target_write_u32(target, ESP32_S2_SWD_WPROTECT_REG, ESP32_S2_SWD_WKEY_VALUE); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_SWD_WPROTECT_REG (%d)!", res); + return res; + } + uint32_t swd_conf_reg = 0; + res = target_read_u32(target, ESP32_S2_SWD_CONF_REG, &swd_conf_reg); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read ESP32_S2_SWD_CONF_REG (%d)!", res); + return res; + } + swd_conf_reg |= ESP32_S2_SWD_AUTO_FEED_EN_M; + res = target_write_u32(target, ESP32_S2_SWD_CONF_REG, swd_conf_reg); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S2_SWD_CONF_REG (%d)!", res); + return res; + } + return ERROR_OK; +} + +static int esp32s2_arch_state(struct target *target) +{ + return ERROR_OK; +} + +static int esp32s2_on_halt(struct target *target) +{ + int ret = esp32s2_disable_wdts(target); + if (ret == ERROR_OK) + ret = esp_xtensa_on_halt(target); + return ret; +} + +static int esp32s2_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) +{ + int ret = xtensa_step(target, current, address, handle_breakpoints); + if (ret == ERROR_OK) { + esp32s2_on_halt(target); + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + return ret; +} + +static int esp32s2_poll(struct target *target) +{ + enum target_state old_state = target->state; + int ret = esp_xtensa_poll(target); + if (ret != ERROR_OK) + return ret; + + if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) { + /* Call any event callbacks that are applicable */ + if (old_state == TARGET_DEBUG_RUNNING) { + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); + } else { + if (esp_xtensa_semihosting(target, &ret) == SEMIHOSTING_HANDLED) { + struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); + if (ret == ERROR_OK && esp_xtensa->semihost.need_resume) { + esp_xtensa->semihost.need_resume = false; + /* Resume xtensa_resume will handle BREAK instruction. */ + ret = target_resume(target, 1, 0, 1, 0); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to resume target"); + return ret; + } + } + return ret; + } + esp32s2_on_halt(target); + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + } + + return ret; +} + +static int esp32s2_virt2phys(struct target *target, + target_addr_t virtual, target_addr_t *physical) +{ + *physical = virtual; + return ERROR_OK; +} + +static int esp32s2_target_init(struct command_context *cmd_ctx, struct target *target) +{ + int ret = esp_xtensa_target_init(cmd_ctx, target); + if (ret != ERROR_OK) + return ret; + + return esp_xtensa_semihosting_init(target); +} + +static const struct xtensa_debug_ops esp32s2_dbg_ops = { + .queue_enable = xtensa_dm_queue_enable, + .queue_reg_read = xtensa_dm_queue_reg_read, + .queue_reg_write = xtensa_dm_queue_reg_write +}; + +static const struct xtensa_power_ops esp32s2_pwr_ops = { + .queue_reg_read = xtensa_dm_queue_pwr_reg_read, + .queue_reg_write = xtensa_dm_queue_pwr_reg_write +}; + +static const struct esp_semihost_ops esp32s2_semihost_ops = { + .prepare = esp32s2_disable_wdts +}; + +static int esp32s2_target_create(struct target *target, Jim_Interp *interp) +{ + struct xtensa_debug_module_config esp32s2_dm_cfg = { + .dbg_ops = &esp32s2_dbg_ops, + .pwr_ops = &esp32s2_pwr_ops, + .tap = target->tap, + .queue_tdi_idle = NULL, + .queue_tdi_idle_arg = NULL + }; + + /* creates xtensa object */ + struct esp32s2_common *esp32 = calloc(1, sizeof(*esp32)); + if (!esp32) { + LOG_ERROR("Failed to alloc memory for arch info!"); + return ERROR_FAIL; + } + + int ret = esp_xtensa_init_arch_info(target, &esp32->esp_xtensa, &esp32s2_dm_cfg, &esp32s2_semihost_ops); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to init arch info!"); + free(esp32); + return ret; + } + + /* Assume running target. If different, the first poll will fix this */ + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + return ERROR_OK; +} + +static const struct command_registration esp32s2_command_handlers[] = { + { + .chain = xtensa_command_handlers, + }, + { + .name = "esp", + .usage = "", + .chain = esp32_apptrace_command_handlers, + }, + { + .name = "arm", + .mode = COMMAND_ANY, + .help = "ARM Command Group", + .usage = "", + .chain = semihosting_common_handlers + }, + COMMAND_REGISTRATION_DONE +}; + +/* Holds methods for Xtensa targets. */ +struct target_type esp32s2_target = { + .name = "esp32s2", + + .poll = esp32s2_poll, + .arch_state = esp32s2_arch_state, + + .halt = xtensa_halt, + .resume = xtensa_resume, + .step = esp32s2_step, + + .assert_reset = esp32s2_assert_reset, + .deassert_reset = esp32s2_deassert_reset, + .soft_reset_halt = esp32s2_soft_reset_halt, + + .virt2phys = esp32s2_virt2phys, + .mmu = xtensa_mmu_is_enabled, + .read_memory = xtensa_read_memory, + .write_memory = xtensa_write_memory, + + .read_buffer = xtensa_read_buffer, + .write_buffer = xtensa_write_buffer, + + .checksum_memory = xtensa_checksum_memory, + + .get_gdb_arch = xtensa_get_gdb_arch, + .get_gdb_reg_list = xtensa_get_gdb_reg_list, + + .run_algorithm = xtensa_run_algorithm, + .start_algorithm = xtensa_start_algorithm, + .wait_algorithm = xtensa_wait_algorithm, + + .add_breakpoint = esp_xtensa_breakpoint_add, + .remove_breakpoint = esp_xtensa_breakpoint_remove, + + .add_watchpoint = xtensa_watchpoint_add, + .remove_watchpoint = xtensa_watchpoint_remove, + + .target_create = esp32s2_target_create, + .init_target = esp32s2_target_init, + .examine = xtensa_examine, + .deinit_target = esp_xtensa_target_deinit, + + .commands = esp32s2_command_handlers, +}; diff --git a/src/target/espressif/esp32s3.c b/src/target/espressif/esp32s3.c new file mode 100644 index 0000000000..22e1630e16 --- /dev/null +++ b/src/target/espressif/esp32s3.c @@ -0,0 +1,424 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * ESP32-S3 target API for OpenOCD * + * Copyright (C) 2020 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/time_support.h> +#include <target/target.h> +#include <target/target_type.h> +#include <target/smp.h> +#include <target/semihosting_common.h> +#include "assert.h" +#include "esp_xtensa_smp.h" + +/* +This is a JTAG driver for the ESP32_S3, the are two Tensilica cores inside +the ESP32_S3 chip. For more information please have a look into ESP32_S3 target +implementation. +*/ + +/* ESP32_S3 memory map */ +#define ESP32_S3_RTC_DATA_LOW 0x50000000 +#define ESP32_S3_RTC_DATA_HIGH 0x50002000 +#define ESP32_S3_EXTRAM_DATA_LOW 0x3D000000 +#define ESP32_S3_EXTRAM_DATA_HIGH 0x3E000000 +#define ESP32_S3_SYS_RAM_LOW 0x60000000UL +#define ESP32_S3_SYS_RAM_HIGH (ESP32_S3_SYS_RAM_LOW + 0x10000000UL) +#define ESP32_S3_RTC_SLOW_MEM_BASE ESP32_S3_RTC_DATA_LOW + +/* ESP32_S3 WDT */ +#define ESP32_S3_WDT_WKEY_VALUE 0x50D83AA1 +#define ESP32_S3_TIMG0_BASE 0x6001F000 +#define ESP32_S3_TIMG1_BASE 0x60020000 +#define ESP32_S3_TIMGWDT_CFG0_OFF 0x48 +#define ESP32_S3_TIMGWDT_PROTECT_OFF 0x64 +#define ESP32_S3_TIMG0WDT_CFG0 (ESP32_S3_TIMG0_BASE + ESP32_S3_TIMGWDT_CFG0_OFF) +#define ESP32_S3_TIMG1WDT_CFG0 (ESP32_S3_TIMG1_BASE + ESP32_S3_TIMGWDT_CFG0_OFF) +#define ESP32_S3_TIMG0WDT_PROTECT (ESP32_S3_TIMG0_BASE + ESP32_S3_TIMGWDT_PROTECT_OFF) +#define ESP32_S3_TIMG1WDT_PROTECT (ESP32_S3_TIMG1_BASE + ESP32_S3_TIMGWDT_PROTECT_OFF) +#define ESP32_S3_RTCCNTL_BASE 0x60008000 +#define ESP32_S3_RTCWDT_CFG_OFF 0x98 +#define ESP32_S3_RTCWDT_PROTECT_OFF 0xB0 +#define ESP32_S3_SWD_CONF_OFF 0xB0 +#define ESP32_S3_SWD_WPROTECT_OFF 0xB4 +#define ESP32_S3_RTCWDT_CFG (ESP32_S3_RTCCNTL_BASE + ESP32_S3_RTCWDT_CFG_OFF) +#define ESP32_S3_RTCWDT_PROTECT (ESP32_S3_RTCCNTL_BASE + ESP32_S3_RTCWDT_PROTECT_OFF) +#define ESP32_S3_SWD_CONF_REG (ESP32_S3_RTCCNTL_BASE + ESP32_S3_SWD_CONF_OFF) +#define ESP32_S3_SWD_WPROTECT_REG (ESP32_S3_RTCCNTL_BASE + ESP32_S3_SWD_WPROTECT_OFF) +#define ESP32_S3_SWD_AUTO_FEED_EN_M BIT(31) +#define ESP32_S3_SWD_WKEY_VALUE 0x8F1D312AU + +#define ESP32_S3_TRACEMEM_BLOCK_SZ 0x4000 + +/* ESP32_S3 dport regs */ +#define ESP32_S3_DR_REG_SYSTEM_BASE 0x600c0000 +#define ESP32_S3_SYSTEM_CORE_1_CONTROL_0_REG (ESP32_S3_DR_REG_SYSTEM_BASE + 0x014) +#define ESP32_S3_SYSTEM_CONTROL_CORE_1_CLKGATE_EN BIT(1) + +/* ESP32_S3 RTC regs */ +#define ESP32_S3_RTC_CNTL_SW_CPU_STALL_REG (ESP32_S3_RTCCNTL_BASE + 0xBC) +#define ESP32_S3_RTC_CNTL_SW_CPU_STALL_DEF 0x0 + +struct esp32s3_common { + struct esp_xtensa_smp_common esp_xtensa_smp; +}; + +/* Reset ESP32-S3's peripherals. + * 1. OpenOCD makes sure the target is halted; if not, tries to halt it. + * If that fails, tries to reset it (via OCD) and then halt. + * 2. OpenOCD loads the stub code into RTC_SLOW_MEM. + * 3. Executes the stub code from address 0x50000004. + * 4. The stub code changes the reset vector to 0x50000000, and triggers + * a system reset using RTC_CNTL_SW_SYS_RST bit. + * 5. Once the PRO CPU is out of reset, it executes the stub code from address 0x50000000. + * The stub code disables the watchdog, re-enables JTAG and the APP CPU, + * restores the reset vector, and enters an infinite loop. + * 6. OpenOCD waits until it can talk to the OCD module again, then halts the target. + * 7. OpenOCD restores the contents of RTC_SLOW_MEM. + * + * End result: all the peripherals except RTC_CNTL are reset, CPU's PC is undefined, + * PRO CPU is halted, APP CPU is in reset. + */ + +static const uint8_t esp32s3_reset_stub_code[] = { +#include "../../../contrib/loaders/reset/espressif/esp32s3/cpu_reset_handler_code.inc" +}; + +static int esp32s3_soc_reset(struct target *target) +{ + int res; + struct target_list *head; + struct xtensa *xtensa; + + LOG_DEBUG("start"); + /* In order to write to peripheral registers, target must be halted first */ + if (target->state != TARGET_HALTED) { + LOG_DEBUG("Target not halted before SoC reset, trying to halt it first"); + xtensa_halt(target); + res = target_wait_state(target, TARGET_HALTED, 1000); + if (res != ERROR_OK) { + LOG_DEBUG("Couldn't halt target before SoC reset, trying to do reset-halt"); + res = xtensa_assert_reset(target); + if (res != ERROR_OK) { + LOG_ERROR( + "Couldn't halt target before SoC reset! (xtensa_assert_reset returned %d)", + res); + return res; + } + alive_sleep(10); + xtensa_poll(target); + bool reset_halt_save = target->reset_halt; + target->reset_halt = true; + res = xtensa_deassert_reset(target); + target->reset_halt = reset_halt_save; + if (res != ERROR_OK) { + LOG_ERROR( + "Couldn't halt target before SoC reset! (xtensa_deassert_reset returned %d)", + res); + return res; + } + alive_sleep(10); + xtensa_poll(target); + xtensa_halt(target); + res = target_wait_state(target, TARGET_HALTED, 1000); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't halt target before SoC reset"); + return res; + } + } + } + + if (target->smp) { + foreach_smp_target(head, target->smp_targets) { + xtensa = target_to_xtensa(head->target); + /* if any of the cores is stalled unstall them */ + if (xtensa_dm_core_is_stalled(&xtensa->dbg_mod)) { + LOG_TARGET_DEBUG(head->target, "Unstall CPUs before SW reset!"); + res = target_write_u32(target, + ESP32_S3_RTC_CNTL_SW_CPU_STALL_REG, + ESP32_S3_RTC_CNTL_SW_CPU_STALL_DEF); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(head->target, "Failed to unstall CPUs before SW reset!"); + return res; + } + break; /* both cores are unstalled now, so exit the loop */ + } + } + } + + LOG_DEBUG("Loading stub code into RTC RAM"); + uint8_t slow_mem_save[sizeof(esp32s3_reset_stub_code)]; + + /* Save contents of RTC_SLOW_MEM which we are about to overwrite */ + res = target_read_buffer(target, ESP32_S3_RTC_SLOW_MEM_BASE, sizeof(slow_mem_save), slow_mem_save); + if (res != ERROR_OK) { + LOG_ERROR("Failed to save contents of RTC_SLOW_MEM (%d)!", res); + return res; + } + + /* Write stub code into RTC_SLOW_MEM */ + res = target_write_buffer(target, + ESP32_S3_RTC_SLOW_MEM_BASE, + sizeof(esp32s3_reset_stub_code), + esp32s3_reset_stub_code); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write stub (%d)!", res); + return res; + } + + LOG_DEBUG("Resuming the target"); + xtensa = target_to_xtensa(target); + xtensa->suppress_dsr_errors = true; + res = xtensa_resume(target, 0, ESP32_S3_RTC_SLOW_MEM_BASE + 4, 0, 0); + xtensa->suppress_dsr_errors = false; + if (res != ERROR_OK) { + LOG_ERROR("Failed to run stub (%d)!", res); + return res; + } + LOG_DEBUG("resume done, waiting for the target to come alive"); + + /* Wait for SoC to reset */ + alive_sleep(100); + int64_t timeout = timeval_ms() + 100; + bool get_timeout = false; + while (target->state != TARGET_RESET && target->state != TARGET_RUNNING) { + alive_sleep(10); + xtensa_poll(target); + if (timeval_ms() >= timeout) { + LOG_TARGET_ERROR(target, + "Timed out waiting for CPU to be reset, target state=%d", + target->state); + get_timeout = true; + break; + } + } + + /* Halt the CPU again */ + LOG_DEBUG("halting the target"); + xtensa_halt(target); + res = target_wait_state(target, TARGET_HALTED, 1000); + if (res == ERROR_OK) { + LOG_DEBUG("restoring RTC_SLOW_MEM"); + res = target_write_buffer(target, ESP32_S3_RTC_SLOW_MEM_BASE, sizeof(slow_mem_save), slow_mem_save); + if (res != ERROR_OK) + LOG_TARGET_ERROR(target, "Failed to restore contents of RTC_SLOW_MEM (%d)!", res); + } else { + LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be halted after SoC reset"); + } + + return get_timeout ? ERROR_TARGET_TIMEOUT : res; +} + +static int esp32s3_disable_wdts(struct target *target) +{ + /* TIMG1 WDT */ + int res = target_write_u32(target, ESP32_S3_TIMG0WDT_PROTECT, ESP32_S3_WDT_WKEY_VALUE); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S3_TIMG0WDT_PROTECT (%d)!", res); + return res; + } + res = target_write_u32(target, ESP32_S3_TIMG0WDT_CFG0, 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S3_TIMG0WDT_CFG0 (%d)!", res); + return res; + } + /* TIMG2 WDT */ + res = target_write_u32(target, ESP32_S3_TIMG1WDT_PROTECT, ESP32_S3_WDT_WKEY_VALUE); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S3_TIMG1WDT_PROTECT (%d)!", res); + return res; + } + res = target_write_u32(target, ESP32_S3_TIMG1WDT_CFG0, 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S3_TIMG1WDT_CFG0 (%d)!", res); + return res; + } + /* RTC WDT */ + res = target_write_u32(target, ESP32_S3_RTCWDT_PROTECT, ESP32_S3_WDT_WKEY_VALUE); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S3_RTCWDT_PROTECT (%d)!", res); + return res; + } + res = target_write_u32(target, ESP32_S3_RTCWDT_CFG, 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S3_RTCWDT_CFG (%d)!", res); + return res; + } + /* Enable SWD auto-feed */ + res = target_write_u32(target, ESP32_S3_SWD_WPROTECT_REG, ESP32_S3_SWD_WKEY_VALUE); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S3_SWD_WPROTECT_REG (%d)!", res); + return res; + } + uint32_t swd_conf_reg = 0; + res = target_read_u32(target, ESP32_S3_SWD_CONF_REG, &swd_conf_reg); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read ESP32_S3_SWD_CONF_REG (%d)!", res); + return res; + } + swd_conf_reg |= ESP32_S3_SWD_AUTO_FEED_EN_M; + res = target_write_u32(target, ESP32_S3_SWD_CONF_REG, swd_conf_reg); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write ESP32_S3_SWD_CONF_REG (%d)!", res); + return res; + } + return ERROR_OK; +} + +static int esp32s3_on_halt(struct target *target) +{ + int ret = esp32s3_disable_wdts(target); + if (ret == ERROR_OK) + ret = esp_xtensa_smp_on_halt(target); + return ret; +} + +static int esp32s3_arch_state(struct target *target) +{ + return ERROR_OK; +} + +static int esp32s3_virt2phys(struct target *target, + target_addr_t virtual, target_addr_t *physical) +{ + if (physical) { + *physical = virtual; + return ERROR_OK; + } + return ERROR_FAIL; +} + +static int esp32s3_target_init(struct command_context *cmd_ctx, struct target *target) +{ + return esp_xtensa_smp_target_init(cmd_ctx, target); +} + +static const struct xtensa_debug_ops esp32s3_dbg_ops = { + .queue_enable = xtensa_dm_queue_enable, + .queue_reg_read = xtensa_dm_queue_reg_read, + .queue_reg_write = xtensa_dm_queue_reg_write +}; + +static const struct xtensa_power_ops esp32s3_pwr_ops = { + .queue_reg_read = xtensa_dm_queue_pwr_reg_read, + .queue_reg_write = xtensa_dm_queue_pwr_reg_write +}; + +static const struct esp_xtensa_smp_chip_ops esp32s3_chip_ops = { + .reset = esp32s3_soc_reset, + .on_halt = esp32s3_on_halt +}; + +static const struct esp_semihost_ops esp32s3_semihost_ops = { + .prepare = esp32s3_disable_wdts +}; + +static int esp32s3_target_create(struct target *target, Jim_Interp *interp) +{ + struct xtensa_debug_module_config esp32s3_dm_cfg = { + .dbg_ops = &esp32s3_dbg_ops, + .pwr_ops = &esp32s3_pwr_ops, + .tap = target->tap, + .queue_tdi_idle = NULL, + .queue_tdi_idle_arg = NULL + }; + + struct esp32s3_common *esp32s3 = calloc(1, sizeof(struct esp32s3_common)); + if (!esp32s3) { + LOG_ERROR("Failed to alloc memory for arch info!"); + return ERROR_FAIL; + } + + int ret = esp_xtensa_smp_init_arch_info(target, + &esp32s3->esp_xtensa_smp, + &esp32s3_dm_cfg, + &esp32s3_chip_ops, + &esp32s3_semihost_ops); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to init arch info!"); + free(esp32s3); + return ret; + } + + /* Assume running target. If different, the first poll will fix this. */ + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + return ERROR_OK; +} + +static const struct command_registration esp32s3_command_handlers[] = { + { + .usage = "", + .chain = esp_xtensa_smp_command_handlers, + }, + { + .name = "esp", + .usage = "", + .chain = esp32_apptrace_command_handlers, + }, + { + .name = "esp32", + .usage = "", + .chain = smp_command_handlers, + }, + { + .name = "arm", + .mode = COMMAND_ANY, + .help = "ARM Command Group", + .usage = "", + .chain = semihosting_common_handlers + }, + COMMAND_REGISTRATION_DONE +}; + +/** Holds methods for Xtensa targets. */ +struct target_type esp32s3_target = { + .name = "esp32s3", + + .poll = esp_xtensa_smp_poll, + .arch_state = esp32s3_arch_state, + + .halt = xtensa_halt, + .resume = esp_xtensa_smp_resume, + .step = esp_xtensa_smp_step, + + .assert_reset = esp_xtensa_smp_assert_reset, + .deassert_reset = esp_xtensa_smp_deassert_reset, + .soft_reset_halt = esp_xtensa_smp_soft_reset_halt, + + .virt2phys = esp32s3_virt2phys, + .mmu = xtensa_mmu_is_enabled, + .read_memory = xtensa_read_memory, + .write_memory = xtensa_write_memory, + + .read_buffer = xtensa_read_buffer, + .write_buffer = xtensa_write_buffer, + + .checksum_memory = xtensa_checksum_memory, + + .get_gdb_arch = xtensa_get_gdb_arch, + .get_gdb_reg_list = xtensa_get_gdb_reg_list, + + .run_algorithm = xtensa_run_algorithm, + .start_algorithm = xtensa_start_algorithm, + .wait_algorithm = xtensa_wait_algorithm, + + .add_breakpoint = esp_xtensa_breakpoint_add, + .remove_breakpoint = esp_xtensa_breakpoint_remove, + + .add_watchpoint = esp_xtensa_smp_watchpoint_add, + .remove_watchpoint = esp_xtensa_smp_watchpoint_remove, + + .target_create = esp32s3_target_create, + .init_target = esp32s3_target_init, + .examine = xtensa_examine, + .deinit_target = esp_xtensa_target_deinit, + + .commands = esp32s3_command_handlers, +}; diff --git a/src/target/espressif/esp_algorithm.c b/src/target/espressif/esp_algorithm.c new file mode 100644 index 0000000000..79f610b922 --- /dev/null +++ b/src/target/espressif/esp_algorithm.c @@ -0,0 +1,595 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Espressif chips common algorithm API for OpenOCD * + * Copyright (C) 2022 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/align.h> +#include <target/algorithm.h> +#include <target/target.h> +#include "esp_algorithm.h" + +#define DEFAULT_ALGORITHM_TIMEOUT_MS 40000 /* ms */ + +static int esp_algorithm_read_stub_logs(struct target *target, struct esp_algorithm_stub *stub) +{ + if (!stub || stub->log_buff_addr == 0 || stub->log_buff_size == 0) + return ERROR_FAIL; + + uint32_t len = 0; + int retval = target_read_u32(target, stub->log_buff_addr, &len); + if (retval != ERROR_OK) + return retval; + + /* sanity check. log_buff_size = sizeof(len) + sizeof(log_buff) */ + if (len == 0 || len > stub->log_buff_size - 4) + return ERROR_FAIL; + + uint8_t *log_buff = calloc(1, len); + if (!log_buff) { + LOG_ERROR("Failed to allocate memory for the stub log!"); + return ERROR_FAIL; + } + retval = target_read_memory(target, stub->log_buff_addr + 4, 1, len, log_buff); + if (retval == ERROR_OK) + LOG_OUTPUT("%*.*s", len, len, log_buff); + free(log_buff); + return retval; +} + +static int esp_algorithm_run_image(struct target *target, + struct esp_algorithm_run_data *run, + uint32_t num_args, + va_list ap) +{ + struct working_area **mem_handles = NULL; + + if (!run || !run->hw) + return ERROR_FAIL; + + int retval = run->hw->algo_init(target, run, num_args, ap); + if (retval != ERROR_OK) + return retval; + + /* allocate memory arguments and fill respective reg params */ + if (run->mem_args.count > 0) { + mem_handles = calloc(run->mem_args.count, sizeof(*mem_handles)); + if (!mem_handles) { + LOG_ERROR("Failed to alloc target mem handles!"); + retval = ERROR_FAIL; + goto _cleanup; + } + /* alloc memory args target buffers */ + for (uint32_t i = 0; i < run->mem_args.count; i++) { + /* small hack: if we need to update some reg param this field holds + * appropriate user argument number, */ + /* otherwise should hold UINT_MAX */ + uint32_t usr_param_num = run->mem_args.params[i].address; + static struct working_area *area; + retval = target_alloc_working_area(target, run->mem_args.params[i].size, &area); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to alloc target buffer!"); + retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + goto _cleanup; + } + mem_handles[i] = area; + run->mem_args.params[i].address = area->address; + if (usr_param_num != UINT_MAX) /* if we need update some register param with mem param value */ + esp_algorithm_user_arg_set_uint(run, usr_param_num, run->mem_args.params[i].address); + } + } + + if (run->usr_func_init) { + retval = run->usr_func_init(target, run, run->usr_func_arg); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to prepare algorithm host side args stub (%d)!", retval); + goto _cleanup; + } + } + + LOG_DEBUG("Algorithm start @ " TARGET_ADDR_FMT ", stack %d bytes @ " TARGET_ADDR_FMT, + run->stub.tramp_mapped_addr, run->stack_size, run->stub.stack_addr); + retval = target_start_algorithm(target, + run->mem_args.count, run->mem_args.params, + run->reg_args.count, run->reg_args.params, + run->stub.tramp_mapped_addr, 0, + run->stub.ainfo); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to start algorithm (%d)!", retval); + goto _cleanup; + } + + if (run->usr_func) { + /* give target algorithm stub time to init itself, then user func can communicate to it safely */ + alive_sleep(100); + retval = run->usr_func(target, run->usr_func_arg); + if (retval != ERROR_OK) + LOG_ERROR("Failed to exec algorithm user func (%d)!", retval); + } + uint32_t timeout_ms = 0; /* do not wait if 'usr_func' returned error */ + if (retval == ERROR_OK) + timeout_ms = run->timeout_ms ? run->timeout_ms : DEFAULT_ALGORITHM_TIMEOUT_MS; + LOG_DEBUG("Wait algorithm completion"); + retval = target_wait_algorithm(target, + run->mem_args.count, run->mem_args.params, + run->reg_args.count, run->reg_args.params, + 0, timeout_ms, + run->stub.ainfo); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to wait algorithm (%d)!", retval); + /* target has been forced to stop in target_wait_algorithm() */ + } + esp_algorithm_read_stub_logs(target, &run->stub); + + if (run->usr_func_done) + run->usr_func_done(target, run, run->usr_func_arg); + + if (retval != ERROR_OK) { + LOG_ERROR("Algorithm run failed (%d)!", retval); + } else { + run->ret_code = esp_algorithm_user_arg_get_uint(run, 0); + LOG_DEBUG("Got algorithm RC 0x%" PRIx32, run->ret_code); + } + +_cleanup: + /* free memory arguments */ + if (mem_handles) { + for (uint32_t i = 0; i < run->mem_args.count; i++) { + if (mem_handles[i]) + target_free_working_area(target, mem_handles[i]); + } + free(mem_handles); + } + run->hw->algo_cleanup(target, run); + + return retval; +} + +static int esp_algorithm_run_debug_stub(struct target *target, + struct esp_algorithm_run_data *run, + uint32_t num_args, + va_list ap) +{ + if (!run || !run->hw) + return ERROR_FAIL; + + int retval = run->hw->algo_init(target, run, num_args, ap); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("Algorithm start @ " TARGET_ADDR_FMT ", stack %d bytes @ " TARGET_ADDR_FMT, + run->stub.tramp_mapped_addr, run->stack_size, run->stub.stack_addr); + retval = target_start_algorithm(target, + run->mem_args.count, run->mem_args.params, + run->reg_args.count, run->reg_args.params, + run->stub.tramp_mapped_addr, 0, + run->stub.ainfo); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to start algorithm (%d)!", retval); + goto _cleanup; + } + + uint32_t timeout_ms = 0; /* do not wait if 'usr_func' returned error */ + if (retval == ERROR_OK) + timeout_ms = run->timeout_ms ? run->timeout_ms : DEFAULT_ALGORITHM_TIMEOUT_MS; + LOG_DEBUG("Wait algorithm completion"); + retval = target_wait_algorithm(target, + run->mem_args.count, run->mem_args.params, + run->reg_args.count, run->reg_args.params, + 0, timeout_ms, + run->stub.ainfo); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to wait algorithm (%d)!", retval); + /* target has been forced to stop in target_wait_algorithm() */ + } + + if (retval != ERROR_OK) { + LOG_ERROR("Algorithm run failed (%d)!", retval); + } else { + run->ret_code = esp_algorithm_user_arg_get_uint(run, 0); + LOG_DEBUG("Got algorithm RC 0x%" PRIx32, run->ret_code); + } + +_cleanup: + run->hw->algo_cleanup(target, run); + + return retval; +} + +static void reverse_binary(const uint8_t *src, uint8_t *dest, size_t length) +{ + size_t remaining = length % 4; + size_t offset = 0; + size_t aligned_len = ALIGN_UP(length, 4); + + if (remaining > 0) { + /* Put extra bytes to the beginning with padding */ + memset(dest + remaining, 0xFF, 4 - remaining); + for (size_t i = 0; i < remaining; i++) + dest[i] = src[length - remaining + i]; + length -= remaining; /* reverse the others */ + offset = 4; + } + + for (size_t i = offset; i < aligned_len; i += 4) { + dest[i + 0] = src[length - i + offset - 4]; + dest[i + 1] = src[length - i + offset - 3]; + dest[i + 2] = src[length - i + offset - 2]; + dest[i + 3] = src[length - i + offset - 1]; + } +} + +static int load_section_from_image(struct target *target, + struct esp_algorithm_run_data *run, + int section_num, + bool reverse) +{ + if (!run) + return ERROR_FAIL; + + struct imagesection *section = &run->image.image.sections[section_num]; + uint32_t sec_wr = 0; + uint8_t buf[1024]; + + assert(sizeof(buf) % 4 == 0); + + while (sec_wr < section->size) { + uint32_t nb = section->size - sec_wr > sizeof(buf) ? sizeof(buf) : section->size - sec_wr; + size_t size_read = 0; + int retval = image_read_section(&run->image.image, section_num, sec_wr, nb, buf, &size_read); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read stub section (%d)!", retval); + return retval; + } + + if (reverse) { + size_t aligned_len = ALIGN_UP(size_read, 4); + uint8_t reversed_buf[aligned_len]; + + /* Send original size to allow padding */ + reverse_binary(buf, reversed_buf, size_read); + + /* + The address range accessed via the instruction bus is in reverse order (word-wise) compared to access + via the data bus. That is to say, address + 0x3FFE_0000 and 0x400B_FFFC access the same word + 0x3FFE_0004 and 0x400B_FFF8 access the same word + 0x3FFE_0008 and 0x400B_FFF4 access the same word + ... + The data bus and instruction bus of the CPU are still both little-endian, + so the byte order of individual words is not reversed between address spaces. + For example, address + 0x3FFE_0000 accesses the least significant byte in the word accessed by 0x400B_FFFC. + 0x3FFE_0001 accesses the second least significant byte in the word accessed by 0x400B_FFFC. + 0x3FFE_0002 accesses the second most significant byte in the word accessed by 0x400B_FFFC. + For more details, please refer to ESP32 TRM, Internal SRAM1 section. + */ + retval = target_write_buffer(target, run->image.dram_org - sec_wr - aligned_len, aligned_len, reversed_buf); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write stub section!"); + return retval; + } + } else { + retval = target_write_buffer(target, section->base_address + sec_wr, size_read, buf); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write stub section!"); + return retval; + } + } + + sec_wr += size_read; + } + + return ERROR_OK; +} + +/* + * Configuration: + * ---------------------------- + * The linker scripts defines the memory layout for the stub code. + * The OpenOCD script specifies the workarea address and it's size + * Sections defined in the linker are organized to share the same addresses with the workarea. + * code and data sections are located in Internal SRAM1 and OpenOCD fills these sections using the data bus. + */ +int esp_algorithm_load_func_image(struct target *target, struct esp_algorithm_run_data *run) +{ + int retval; + size_t tramp_sz = 0; + const uint8_t *tramp = NULL; + struct duration algo_time; + bool alloc_code_working_area = true; + + if (!run || !run->hw) + return ERROR_FAIL; + + if (duration_start(&algo_time) != 0) { + LOG_ERROR("Failed to start algo time measurement!"); + return ERROR_FAIL; + } + + if (run->hw->stub_tramp_get) { + tramp = run->hw->stub_tramp_get(target, &tramp_sz); + if (!tramp) + return ERROR_FAIL; + } + + LOG_DEBUG("stub: base 0x%x, start 0x%" PRIx32 ", %d sections", + run->image.image.base_address_set ? (unsigned int)run->image.image.base_address : 0, + run->image.image.start_address, + run->image.image.num_sections); + run->stub.entry = run->image.image.start_address; + + /* [code + trampoline] + <padding> + [data] */ + + /* ESP32 has reversed memory region. It will use the last part of DRAM, the others will use the first part. + * To avoid complexity for the backup/restore process, we will allocate a workarea for all IRAM region from + * the beginning. In that case no need to have a padding area. + */ + if (run->image.reverse) { + if (target_alloc_working_area(target, run->image.iram_len, &run->stub.code) != ERROR_OK) { + LOG_ERROR("no working area available, can't alloc space for stub code!"); + retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + goto _on_error; + } + alloc_code_working_area = false; + } + + uint32_t code_size = 0; + + /* Load code section */ + for (unsigned int i = 0; i < run->image.image.num_sections; i++) { + struct imagesection *section = &run->image.image.sections[i]; + + if (section->size == 0) + continue; + + if (section->flags & ESP_IMAGE_ELF_PHF_EXEC) { + LOG_DEBUG("addr " TARGET_ADDR_FMT ", sz %d, flags %" PRIx64, + section->base_address, section->size, section->flags); + + if (alloc_code_working_area) { + retval = target_alloc_working_area(target, section->size, &run->stub.code); + if (retval != ERROR_OK) { + LOG_ERROR("no working area available, can't alloc space for stub code!"); + retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + goto _on_error; + } + } + + if (section->base_address == 0) { + section->base_address = run->stub.code->address; + /* sanity check, stub is compiled to be run from working area */ + } else if (run->stub.code->address != section->base_address) { + LOG_ERROR("working area " TARGET_ADDR_FMT " and stub code section " TARGET_ADDR_FMT + " address mismatch!", + section->base_address, + run->stub.code->address); + retval = ERROR_FAIL; + goto _on_error; + } + + retval = load_section_from_image(target, run, i, run->image.reverse); + if (retval != ERROR_OK) + goto _on_error; + + code_size += ALIGN_UP(section->size, 4); + break; /* Stub has one executable text section */ + } + } + + /* If exists, load trampoline to the code area */ + if (tramp) { + if (run->stub.tramp_addr == 0) { + if (alloc_code_working_area) { + /* alloc trampoline in code working area */ + if (target_alloc_working_area(target, tramp_sz, &run->stub.tramp) != ERROR_OK) { + LOG_ERROR("no working area available, can't alloc space for stub jumper!"); + retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + goto _on_error; + } + run->stub.tramp_addr = run->stub.tramp->address; + } + } + + size_t al_tramp_size = ALIGN_UP(tramp_sz, 4); + + if (run->image.reverse) { + target_addr_t reversed_tramp_addr = run->image.dram_org - code_size; + uint8_t reversed_tramp[al_tramp_size]; + + /* Send original size to allow padding */ + reverse_binary(tramp, reversed_tramp, tramp_sz); + run->stub.tramp_addr = reversed_tramp_addr - al_tramp_size; + LOG_DEBUG("Write reversed tramp to addr " TARGET_ADDR_FMT ", sz %zu", run->stub.tramp_addr, al_tramp_size); + retval = target_write_buffer(target, run->stub.tramp_addr, al_tramp_size, reversed_tramp); + } else { + LOG_DEBUG("Write tramp to addr " TARGET_ADDR_FMT ", sz %zu", run->stub.tramp_addr, tramp_sz); + retval = target_write_buffer(target, run->stub.tramp_addr, tramp_sz, tramp); + } + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write stub jumper!"); + goto _on_error; + } + + run->stub.tramp_mapped_addr = run->image.iram_org + code_size; + code_size += al_tramp_size; + LOG_DEBUG("Tramp mapped to addr " TARGET_ADDR_FMT, run->stub.tramp_mapped_addr); + } + + /* allocate dummy space until the data address */ + if (alloc_code_working_area) { + /* we dont need to restore padding area. */ + uint32_t backup_working_area_prev = target->backup_working_area; + target->backup_working_area = 0; + if (target_alloc_working_area(target, run->image.iram_len - code_size, &run->stub.padding) != ERROR_OK) { + LOG_ERROR("no working area available, can't alloc space for stub code!"); + retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + goto _on_error; + } + target->backup_working_area = backup_working_area_prev; + } + + /* Load the data section */ + for (unsigned int i = 0; i < run->image.image.num_sections; i++) { + struct imagesection *section = &run->image.image.sections[i]; + + if (section->size == 0) + continue; + + if (!(section->flags & ESP_IMAGE_ELF_PHF_EXEC)) { + LOG_DEBUG("addr " TARGET_ADDR_FMT ", sz %d, flags %" PRIx64, section->base_address, section->size, + section->flags); + /* target_alloc_working_area() aligns the whole working area size to 4-byte boundary. + We alloc one area for both DATA and BSS, so align each of them ourselves. */ + uint32_t data_sec_sz = ALIGN_UP(section->size, 4); + LOG_DEBUG("DATA sec size %" PRIu32 " -> %" PRIu32, section->size, data_sec_sz); + uint32_t bss_sec_sz = ALIGN_UP(run->image.bss_size, 4); + LOG_DEBUG("BSS sec size %" PRIu32 " -> %" PRIu32, run->image.bss_size, bss_sec_sz); + if (target_alloc_working_area(target, data_sec_sz + bss_sec_sz, &run->stub.data) != ERROR_OK) { + LOG_ERROR("no working area available, can't alloc space for stub data!"); + retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + goto _on_error; + } + if (section->base_address == 0) { + section->base_address = run->stub.data->address; + /* sanity check, stub is compiled to be run from working area */ + } else if (run->stub.data->address != section->base_address) { + LOG_ERROR("working area " TARGET_ADDR_FMT + " and stub data section " TARGET_ADDR_FMT + " address mismatch!", + section->base_address, + run->stub.data->address); + retval = ERROR_FAIL; + goto _on_error; + } + + retval = load_section_from_image(target, run, i, false); + if (retval != ERROR_OK) + goto _on_error; + } + } + + /* stack */ + if (run->stub.stack_addr == 0 && run->stack_size > 0) { + /* allocate stack in data working area */ + if (target_alloc_working_area(target, run->stack_size, &run->stub.stack) != ERROR_OK) { + LOG_ERROR("no working area available, can't alloc stub stack!"); + retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + goto _on_error; + } + run->stub.stack_addr = run->stub.stack->address + run->stack_size; + } + + if (duration_measure(&algo_time) != 0) { + LOG_ERROR("Failed to stop algo run measurement!"); + retval = ERROR_FAIL; + goto _on_error; + } + LOG_DEBUG("Stub loaded in %g ms", duration_elapsed(&algo_time) * 1000); + return ERROR_OK; + +_on_error: + esp_algorithm_unload_func_image(target, run); + return retval; +} + +int esp_algorithm_unload_func_image(struct target *target, struct esp_algorithm_run_data *run) +{ + if (!run) + return ERROR_FAIL; + + target_free_all_working_areas(target); + + run->stub.tramp = NULL; + run->stub.stack = NULL; + run->stub.code = NULL; + run->stub.data = NULL; + run->stub.padding = NULL; + + return ERROR_OK; +} + +int esp_algorithm_exec_func_image_va(struct target *target, + struct esp_algorithm_run_data *run, + uint32_t num_args, + va_list ap) +{ + if (!run || !run->image.image.start_address_set || run->image.image.start_address == 0) + return ERROR_FAIL; + + return esp_algorithm_run_image(target, run, num_args, ap); +} + +int esp_algorithm_load_onboard_func(struct target *target, target_addr_t func_addr, struct esp_algorithm_run_data *run) +{ + int res; + const uint8_t *tramp = NULL; + size_t tramp_sz = 0; + struct duration algo_time; + + if (!run || !run->hw) + return ERROR_FAIL; + + if (duration_start(&algo_time) != 0) { + LOG_ERROR("Failed to start algo time measurement!"); + return ERROR_FAIL; + } + + if (run->hw->stub_tramp_get) { + tramp = run->hw->stub_tramp_get(target, &tramp_sz); + if (!tramp) + return ERROR_FAIL; + } + + if (tramp_sz > run->on_board.code_buf_size) { + LOG_ERROR("Stub tramp size %zu bytes exceeds target buf size %d bytes!", + tramp_sz, run->on_board.code_buf_size); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + if (run->stack_size > run->on_board.min_stack_size) { + LOG_ERROR("Algorithm stack size not fit into the allocated target stack!"); + return ERROR_FAIL; + } + + run->stub.stack_addr = run->on_board.min_stack_addr + run->stack_size; + run->stub.tramp_addr = run->on_board.code_buf_addr; + run->stub.tramp_mapped_addr = run->stub.tramp_addr; + run->stub.entry = func_addr; + + if (tramp) { + res = target_write_buffer(target, run->stub.tramp_addr, tramp_sz, tramp); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write stub jumper!"); + esp_algorithm_unload_onboard_func(target, run); + return res; + } + } + + if (duration_measure(&algo_time) != 0) { + LOG_ERROR("Failed to stop algo run measurement!"); + return ERROR_FAIL; + } + LOG_DEBUG("Stub loaded in %g ms", duration_elapsed(&algo_time) * 1000); + + return ERROR_OK; +} + +int esp_algorithm_unload_onboard_func(struct target *target, struct esp_algorithm_run_data *run) +{ + return ERROR_OK; +} + +int esp_algorithm_exec_onboard_func_va(struct target *target, + struct esp_algorithm_run_data *run, + uint32_t num_args, + va_list ap) +{ + return esp_algorithm_run_debug_stub(target, run, num_args, ap); +} diff --git a/src/target/espressif/esp_algorithm.h b/src/target/espressif/esp_algorithm.h new file mode 100644 index 0000000000..11d2757776 --- /dev/null +++ b/src/target/espressif/esp_algorithm.h @@ -0,0 +1,420 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Espressif chips common algorithm API for OpenOCD * + * Copyright (C) 2022 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESP_ALGORITHM_H +#define OPENOCD_TARGET_ESP_ALGORITHM_H + +#include "helper/log.h" +#include "helper/binarybuffer.h" +#include <helper/time_support.h> +#include <target/algorithm.h> +#include <target/image.h> + +/** + * API defined below allows executing pieces of code on target without breaking the execution of the running program. + * This functionality can be useful for various debugging and maintenance procedures. + * @note ESP flashing code to load flasher stub on target and write/read/erase flash. + * Also ESP GCOV command uses some of these functions to run onboard routines to dump coverage info. + * Stub entry function can take up to 5 arguments and should be of the following form: + * + * int stub_entry([uint32_t a1 [, uint32_t a2 [, uint32_t a3 [, uint32_t a4 [, uint32_t a5]]]]]); + * + * The general scheme of stub code execution is shown below. + * + * ------- ----------- (initial frame) ---- + * | | -------(registers, stub entry, stub args)------> |trampoline | ---(stub args)---> | | + * | | | | | | + * |OpenOCD| <----------(stub-specific communications)---------------------------------------> |stub| + * | | | | | | + * | | <---------(target halted event, ret code)------- |tramp break| <---(ret code)---- | | + * ------- ----------- ---- + * + * Procedure of executing stub on target includes: + * 1) User prepares struct esp_algorithm_run_data and calls one of algorithm_run_xxx() functions. + * 2) Routine allocates all necessary stub code and data sections. + * 3) If a user specifies an initializer func esp_algorithm_usr_func_init_t it is called just before the stub starts. + * 4) If user specifies stub communication func esp_algorithm_usr_func_t (@see esp_flash_write/read in ESP flash driver) + * it is called just after the stub starts. When communication with stub is finished this function must return. + * 5) OpenOCD waits for the stub to finish (hit exit breakpoint). + * 6) If the user specified arguments cleanup func esp_algorithm_usr_func_done_t, + * it is called just after the stub finishes. + * + * There are two options to run code on target under OpenOCD control: + * - Run externally compiled stub code. + * - Run onboard pre-compiled code. @note For ESP chips debug stubs must be enabled in target code @see ESP IDF docs. + * The main difference between the execution of external stub code and target built-in functions is that + * in the latter case working areas can not be used to allocate target memory for code and data because they can overlap + * with code and data involved in onboard function execution. For example, if memory allocated in the working area + * for the stub stack will overlap with some on-board data used by the stub the stack will get overwritten. + * The same stands for allocations in target code space. + * + * External Code Execution + * ----------------------- + * To run external code on the target user should use esp_algorithm_run_func_image(). + * In this case all necessary memory (code/data) is allocated in working areas that have fixed configuration + * defined in target TCL file. Stub code is actually a standalone program, so all its segments must have known + * addresses due to position-dependent code nature. So stub must be linked in such a way that its code segment + * starts at the beginning of the working area for code space defined in TCL. The same restriction must be applied + * to stub's data segment and base addresses of working area for data space. @see ESP stub flasher LD scripts. + * Also in order to simplify memory allocation BSS section must follow the DATA section in the stub image. + * The size of the BSS section must be specified in the bss_size field of struct algorithm_image. + * Sample stub memory map is shown below. + * ___________________________________________ + * | data space working area start | + * | | + * | <stub .data segment> | + * |___________________________________________| + * | stub .bss start | + * | | + * | <stub .bss segment of size 'bss_size'> | + * |___________________________________________| + * | stub stack base | + * | | + * | <stub stack> | + * |___________________________________________| + * | | + * | <stub mem arg1> | + * |___________________________________________| + * | | + * | <stub mem arg2> | + * |___________________________________________| + * ___________________________________________ + * | code space working area start | + * | | + * | <stub .text segment> | + * |___________________________________________| + * | | + * | <stub trampoline with exit breakpoint> | + * |___________________________________________| + * + * For example on how to execute external code with memory arguments @see esp_algo_flash_blank_check in + * ESP flash driver. + * + * On-Board Code Execution + * ----------------------- + * To run on-board code on the target user should use esp_algorithm_run_onboard_func(). + * On-board code execution process does not need to allocate target memory for stub code and data, + * Because the stub is pre-compiled to the code running on the target. + * But it still needs memory for stub trampoline, stack, and memory arguments. + * Working areas can not be used due to possible memory layout conflicts with on-board stub code and data. + * Debug stubs functionality provided by ESP IDF allows OpenOCD to overcome the above problem. + * It provides a special descriptor which provides info necessary to safely allocate memory on target. + * @see struct esp_dbg_stubs_desc. + * That info is also used to locate memory for stub trampoline code. + * User can execute target function at any address, but @see ESP IDF debug stubs also provide a way to pass to the host + * an entry address of pre-defined registered stub functions. + * For example of an on-board code execution @see esp32_cmd_gcov() in ESP32 apptrace module. +*/ + +/** + * Algorithm image data. + * Helper struct to work with algorithms consisting of code and data segments. + */ +struct esp_algorithm_image { + /** Image. */ + struct image image; + /** BSS section size. */ + uint32_t bss_size; + /** IRAM start address in the linker script */ + uint32_t iram_org; + /** Total reserved IRAM size */ + uint32_t iram_len; + /** DRAM start address in the linker script */ + uint32_t dram_org; + /** Total reserved DRAM size */ + uint32_t dram_len; + /** IRAM DRAM address range reversed or not */ + bool reverse; +}; + +#define ESP_IMAGE_ELF_PHF_EXEC 0x1 + +/** + * Algorithm stub data. + */ +struct esp_algorithm_stub { + /** Entry addr. */ + target_addr_t entry; + /** Working area for code segment. */ + struct working_area *code; + /** Working area for data segment. */ + struct working_area *data; + /** Working area for trampoline. */ + struct working_area *tramp; + /** Working area for padding between code and data area. */ + struct working_area *padding; + /** Address of the target buffer for stub trampoline. If zero tramp->address will be used. */ + target_addr_t tramp_addr; + /** Tramp code area will be filled from dbus. + * We need to map it to the ibus to be able to initialize PC register to start algorithm execution from. + */ + target_addr_t tramp_mapped_addr; + /** Working area for stack. */ + struct working_area *stack; + /** Address of the target buffer for stack. If zero tramp->address will be used. */ + target_addr_t stack_addr; + /** Address of the log buffer */ + target_addr_t log_buff_addr; + /** Size of the log buffer */ + uint32_t log_buff_size; + /** Algorithm's arch-specific info. */ + void *ainfo; +}; + +/** + * Algorithm stub in-memory arguments. + */ +struct esp_algorithm_mem_args { + /** Memory params. */ + struct mem_param *params; + /** Number of memory params. */ + uint32_t count; +}; + +/** + * Algorithm stub register arguments. + */ +struct esp_algorithm_reg_args { + /** Algorithm register params. User args start from user_first_reg_param */ + struct reg_param *params; + /** Number of register params. */ + uint32_t count; + /** The first several reg_params can be used by stub itself (e.g. for trampoline). + * This is the index of the first reg_param available for user to pass args to algorithm stub. */ + uint32_t first_user_param; +}; + +struct esp_algorithm_run_data; + +/** + * @brief Algorithm run function. + * + * @param target Pointer to target. + * @param run Pointer to algo run data. + * @param arg Function specific argument. + * + * @return ERROR_OK on success, otherwise ERROR_XXX. + */ +typedef int (*esp_algorithm_func_t)(struct target *target, struct esp_algorithm_run_data *run, void *arg); + +/** + * @brief Host part of algorithm. + * This function will be called while stub is running on target. + * It can be used for communication with stub. + * + * @param target Pointer to target. + * @param usr_arg Function specific argument. + * + * @return ERROR_OK on success, otherwise ERROR_XXX. + */ +typedef int (*esp_algorithm_usr_func_t)(struct target *target, void *usr_arg); + +/** + * @brief Algorithm's arguments setup function. + * This function will be called just before stub start. + * It must return when all operations with running stub are completed. + * It can be used to prepare stub memory parameters. + * + * @param target Pointer to target. + * @param run Pointer to algo run data. + * @param usr_arg Function specific argument. The same as for esp_algorithm_usr_func_t. + * + * @return ERROR_OK on success, otherwise ERROR_XXX. + */ +typedef int (*esp_algorithm_usr_func_init_t)(struct target *target, + struct esp_algorithm_run_data *run, + void *usr_arg); + +/** + * @brief Algorithm's arguments cleanup function. + * This function will be called just after stub exit. + * It can be used to cleanup stub memory parameters. + * + * @param target Pointer to target. + * @param run Pointer to algo run data. + * @param usr_arg Function specific argument. The same as for esp_algorithm_usr_func_t. + * + * @return ERROR_OK on success, otherwise ERROR_XXX. + */ +typedef void (*esp_algorithm_usr_func_done_t)(struct target *target, + struct esp_algorithm_run_data *run, + void *usr_arg); + +struct esp_algorithm_hw { + int (*algo_init)(struct target *target, struct esp_algorithm_run_data *run, uint32_t num_args, va_list ap); + int (*algo_cleanup)(struct target *target, struct esp_algorithm_run_data *run); + const uint8_t *(*stub_tramp_get)(struct target *target, size_t *size); +}; + +/** + * Algorithm run data. + */ +struct esp_algorithm_run_data { + /** Algorithm completion timeout in ms. If 0, default value will be used */ + uint32_t timeout_ms; + /** Algorithm stack size. */ + uint32_t stack_size; + /** Algorithm register arguments. */ + struct esp_algorithm_reg_args reg_args; + /** Algorithm memory arguments. */ + struct esp_algorithm_mem_args mem_args; + /** Algorithm arch-specific info. For Xtensa this should point to struct xtensa_algorithm. */ + void *arch_info; + /** Algorithm return code. */ + int32_t ret_code; + /** Stub. */ + struct esp_algorithm_stub stub; + union { + struct { + /** Size of the pre-alocated on-board buffer for stub's code. */ + uint32_t code_buf_size; + /** Address of pre-compiled target buffer for stub trampoline. */ + target_addr_t code_buf_addr; + /** Size of the pre-alocated on-board buffer for stub's stack. */ + uint32_t min_stack_size; + /** Pre-compiled target buffer's addr for stack. */ + target_addr_t min_stack_addr; + } on_board; + struct esp_algorithm_image image; + }; + /** Host side algorithm function argument. */ + void *usr_func_arg; + /** Host side algorithm function. */ + esp_algorithm_usr_func_t usr_func; + /** Host side algorithm function setup routine. */ + esp_algorithm_usr_func_init_t usr_func_init; + /** Host side algorithm function cleanup routine. */ + esp_algorithm_usr_func_done_t usr_func_done; + /** Algorithm run function: see algorithm_run_xxx for example. */ + esp_algorithm_func_t algo_func; + /** HW specific API */ + const struct esp_algorithm_hw *hw; +}; + +int esp_algorithm_load_func_image(struct target *target, struct esp_algorithm_run_data *run); +int esp_algorithm_unload_func_image(struct target *target, struct esp_algorithm_run_data *run); + +int esp_algorithm_exec_func_image_va(struct target *target, + struct esp_algorithm_run_data *run, + uint32_t num_args, + va_list ap); + +/** + * @brief Loads and runs stub from specified image. + * This function should be used to run external stub code on target. + * + * @param target Pointer to target. + * @param run Pointer to algo run data. + * @param num_args Number of stub arguments that follow. + * + * @return ERROR_OK on success, otherwise ERROR_XXX. Stub return code is in run->ret_code. + */ +static inline int esp_algorithm_run_func_image_va(struct target *target, + struct esp_algorithm_run_data *run, + uint32_t num_args, + va_list ap) +{ + int ret = esp_algorithm_load_func_image(target, run); + if (ret != ERROR_OK) + return ret; + ret = esp_algorithm_exec_func_image_va(target, run, num_args, ap); + int rc = esp_algorithm_unload_func_image(target, run); + return ret != ERROR_OK ? ret : rc; +} + +static inline int esp_algorithm_run_func_image(struct target *target, + struct esp_algorithm_run_data *run, + uint32_t num_args, + ...) +{ + va_list ap; + va_start(ap, num_args); + int retval = esp_algorithm_run_func_image_va(target, run, num_args, ap); + va_end(ap); + return retval; +} + +int esp_algorithm_load_onboard_func(struct target *target, + target_addr_t func_addr, + struct esp_algorithm_run_data *run); +int esp_algorithm_unload_onboard_func(struct target *target, struct esp_algorithm_run_data *run); +int esp_algorithm_exec_onboard_func_va(struct target *target, + struct esp_algorithm_run_data *run, + uint32_t num_args, + va_list ap); + +/** + * @brief Runs pre-compiled on-board function. + * This function should be used to run on-board stub code. + * + * @param target Pointer to target. + * @param run Pointer to algo run data. + * @param func_entry Address of the function to run. + * @param num_args Number of function arguments that follow. + * + * @return ERROR_OK on success, otherwise ERROR_XXX. Stub return code is in run->ret_code. + */ +static inline int esp_algorithm_run_onboard_func_va(struct target *target, + struct esp_algorithm_run_data *run, + target_addr_t func_addr, + uint32_t num_args, + va_list ap) +{ + int ret = esp_algorithm_load_onboard_func(target, func_addr, run); + if (ret != ERROR_OK) + return ret; + ret = esp_algorithm_exec_onboard_func_va(target, run, num_args, ap); + if (ret != ERROR_OK) + return ret; + return esp_algorithm_unload_onboard_func(target, run); +} + +static inline int esp_algorithm_run_onboard_func(struct target *target, + struct esp_algorithm_run_data *run, + target_addr_t func_addr, + uint32_t num_args, + ...) +{ + va_list ap; + va_start(ap, num_args); + int retval = esp_algorithm_run_onboard_func_va(target, run, func_addr, num_args, ap); + va_end(ap); + return retval; +} + +/** + * @brief Set the value of an argument passed via registers to the stub main function. + */ +static inline void esp_algorithm_user_arg_set_uint(struct esp_algorithm_run_data *run, + int arg_num, + uint64_t val) +{ + struct reg_param *param = &run->reg_args.params[run->reg_args.first_user_param + arg_num]; + + assert(param->size <= 64); + + if (param->size <= 32) + buf_set_u32(param->value, 0, param->size, val); + else + buf_set_u64(param->value, 0, param->size, val); +} + +/** + * @brief Get the value of an argument passed via registers from the stub main function. + */ +static inline uint64_t esp_algorithm_user_arg_get_uint(struct esp_algorithm_run_data *run, int arg_num) +{ + struct reg_param *param = &run->reg_args.params[run->reg_args.first_user_param + arg_num]; + + assert(param->size <= 64); + + if (param->size <= 32) + return buf_get_u32(param->value, 0, param->size); + return buf_get_u64(param->value, 0, param->size); +} + +#endif /* OPENOCD_TARGET_ESP_ALGORITHM_H */ diff --git a/src/target/espressif/esp_semihosting.c b/src/target/espressif/esp_semihosting.c new file mode 100644 index 0000000000..51d499866d --- /dev/null +++ b/src/target/espressif/esp_semihosting.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Semihosting API for Espressif chips * + * Copyright (C) 2022 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/log.h> +#include <target/target.h> +#include <target/semihosting_common.h> +#include "esp_semihosting.h" +#include "esp_xtensa.h" + +static struct esp_semihost_data __attribute__((unused)) *target_to_esp_semihost_data(struct target *target) +{ + struct xtensa *xtensa = target->arch_info; + if (xtensa->common_magic == XTENSA_COMMON_MAGIC) + return &target_to_esp_xtensa(target)->semihost; + /* TODO: add riscv */ + LOG_ERROR("Unknown target arch!"); + return NULL; +} + +static int esp_semihosting_sys_seek(struct target *target, uint64_t fd, uint32_t pos, size_t whence) +{ + struct semihosting *semihosting = target->semihosting; + + semihosting->result = lseek(fd, pos, whence); + semihosting->sys_errno = errno; + LOG_TARGET_DEBUG(target, "lseek(%" PRIx64 ", %" PRIu32 " %" PRId64 ")=%d", fd, pos, semihosting->result, errno); + return ERROR_OK; +} + +int esp_semihosting_common(struct target *target) +{ + struct semihosting *semihosting = target->semihosting; + if (!semihosting) + /* Silently ignore if the semihosting field was not set. */ + return ERROR_OK; + + int retval = ERROR_NOT_IMPLEMENTED; + + /* Enough space to hold 4 long words. */ + uint8_t fields[4 * 8]; + + /* + * By default return an error. + * The actual result must be set by each function + */ + semihosting->result = -1; + semihosting->sys_errno = EIO; + + LOG_TARGET_DEBUG(target, "op=0x%x, param=0x%" PRIx64, semihosting->op, semihosting->param); + + switch (semihosting->op) { + case ESP_SEMIHOSTING_SYS_DRV_INFO: + /* Return success to make esp-idf application happy */ + retval = ERROR_OK; + semihosting->result = 0; + semihosting->sys_errno = 0; + break; + + case ESP_SEMIHOSTING_SYS_SEEK: + retval = semihosting_read_fields(target, 3, fields); + if (retval == ERROR_OK) { + uint64_t fd = semihosting_get_field(target, 0, fields); + uint32_t pos = semihosting_get_field(target, 1, fields); + size_t whence = semihosting_get_field(target, 2, fields); + retval = esp_semihosting_sys_seek(target, fd, pos, whence); + } + break; + + case ESP_SEMIHOSTING_SYS_APPTRACE_INIT: + case ESP_SEMIHOSTING_SYS_DEBUG_STUBS_INIT: + case ESP_SEMIHOSTING_SYS_BREAKPOINT_SET: + case ESP_SEMIHOSTING_SYS_WATCHPOINT_SET: + /* For the time being only riscv chips support these commands + * TODO: invoke riscv custom command handler */ + break; + } + + return retval; +} + +int esp_semihosting_basedir_command(struct command_invocation *cmd) +{ + struct target *target = get_current_target(CMD_CTX); + + if (!target) { + LOG_ERROR("No target selected"); + return ERROR_FAIL; + } + + struct semihosting *semihosting = target->semihosting; + if (!semihosting) { + command_print(CMD, "semihosting not supported for current target"); + return ERROR_FAIL; + } + + if (!semihosting->is_active) { + if (semihosting->setup(target, true) != ERROR_OK) { + LOG_ERROR("Failed to Configure semihosting"); + return ERROR_FAIL; + } + semihosting->is_active = true; + } + + if (CMD_ARGC > 0) { + free(semihosting->basedir); + semihosting->basedir = strdup(CMD_ARGV[0]); + if (!semihosting->basedir) { + command_print(CMD, "semihosting failed to allocate memory for basedir!"); + return ERROR_FAIL; + } + } + + command_print(CMD, "DEPRECATED! semihosting base dir: %s", + semihosting->basedir ? semihosting->basedir : ""); + + return ERROR_OK; +} diff --git a/src/target/espressif/esp_semihosting.h b/src/target/espressif/esp_semihosting.h new file mode 100644 index 0000000000..bd2c0799ed --- /dev/null +++ b/src/target/espressif/esp_semihosting.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Semihosting API for Espressif chips * + * Copyright (C) 2022 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESP_SEMIHOSTING_H +#define OPENOCD_TARGET_ESP_SEMIHOSTING_H + +/* Legacy syscalls */ +#define ESP_SYS_DRV_INFO_LEGACY 0xE0 + +/* syscalls compatible to ARM standard */ +#define ESP_SEMIHOSTING_SYS_DRV_INFO 0x100 +#define ESP_SEMIHOSTING_SYS_APPTRACE_INIT 0x101 +#define ESP_SEMIHOSTING_SYS_DEBUG_STUBS_INIT 0x102 +#define ESP_SEMIHOSTING_SYS_BREAKPOINT_SET 0x103 +#define ESP_SEMIHOSTING_SYS_WATCHPOINT_SET 0x104 +#define ESP_SEMIHOSTING_SYS_SEEK 0x105 /* custom lseek with whence */ +/* not implemented yet */ +#define ESP_SEMIHOSTING_SYS_MKDIR 0x106 +#define ESP_SEMIHOSTING_SYS_OPENDIR 0x107 +#define ESP_SEMIHOSTING_SYS_READDIR 0x108 +#define ESP_SEMIHOSTING_SYS_READDIR_R 0x109 +#define ESP_SEMIHOSTING_SYS_SEEKDIR 0x10A +#define ESP_SEMIHOSTING_SYS_TELLDIR 0x10B +#define ESP_SEMIHOSTING_SYS_CLOSEDIR 0x10C +#define ESP_SEMIHOSTING_SYS_RMDIR 0x10D +#define ESP_SEMIHOSTING_SYS_ACCESS 0x10E +#define ESP_SEMIHOSTING_SYS_TRUNCATE 0x10F +#define ESP_SEMIHOSTING_SYS_UTIME 0x110 +#define ESP_SEMIHOSTING_SYS_FSTAT 0x111 +#define ESP_SEMIHOSTING_SYS_STAT 0x112 +#define ESP_SEMIHOSTING_SYS_FSYNC 0x113 +#define ESP_SEMIHOSTING_SYS_LINK 0x114 +#define ESP_SEMIHOSTING_SYS_UNLINK 0x115 + +/** + * Semihost calls handling operations. + */ +struct esp_semihost_ops { + /** Callback called before handling semihost call */ + int (*prepare)(struct target *target); +}; + +struct esp_semihost_data { + bool need_resume; + struct esp_semihost_ops *ops; +}; + +int esp_semihosting_common(struct target *target); +int esp_semihosting_basedir_command(struct command_invocation *cmd); + +#endif /* OPENOCD_TARGET_ESP_SEMIHOSTING_H */ diff --git a/src/target/espressif/esp_xtensa.c b/src/target/espressif/esp_xtensa.c new file mode 100644 index 0000000000..11895d23bb --- /dev/null +++ b/src/target/espressif/esp_xtensa.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Espressif Xtensa target API for OpenOCD * + * Copyright (C) 2019 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdbool.h> +#include <stdint.h> +#include <target/smp.h> +#include <target/register.h> +#include "esp.h" +#include "esp_xtensa.h" +#include "esp_xtensa_apptrace.h" +#include "esp_semihosting.h" +#include "esp_xtensa_algorithm.h" + +#define ESP_XTENSA_DBGSTUBS_UPDATE_DATA_ENTRY(_e_) \ + do { \ + uint32_t __internal_val = (_e_); \ + if (!xtensa_data_addr_valid(target, __internal_val)) { \ + LOG_ERROR("No valid stub data entry found (0x%" PRIx32 ")!", __internal_val); \ + return; \ + } \ + } while (0) + +#define ESP_XTENSA_DBGSTUBS_UPDATE_CODE_ENTRY(_e_) \ + do { \ + uint32_t __internal_val = (_e_); \ + if (__internal_val == 0) { \ + LOG_ERROR("No valid stub code entry found (0x%" PRIx32 ")!", __internal_val); \ + return; \ + } \ + } while (0) + +static void esp_xtensa_dbgstubs_info_update(struct target *target); +static void esp_xtensa_dbgstubs_addr_check(struct target *target); + +static int esp_xtensa_dbgstubs_restore(struct target *target) +{ + struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); + + if (esp_xtensa->esp.dbg_stubs.base == 0) + return ERROR_OK; + + LOG_TARGET_INFO(target, "Restore debug stubs address %" PRIx32, esp_xtensa->esp.dbg_stubs.base); + int res = esp_xtensa_apptrace_status_reg_write(target, esp_xtensa->esp.dbg_stubs.base); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write trace status (%d)!", res); + return res; + } + return ERROR_OK; +} +int esp_xtensa_on_halt(struct target *target) +{ + /* debug stubs can be used in HALTED state only, so it is OK to get info about them here */ + esp_xtensa_dbgstubs_info_update(target); + return ERROR_OK; +} + +int esp_xtensa_init_arch_info(struct target *target, + struct esp_xtensa_common *esp_xtensa, + struct xtensa_debug_module_config *dm_cfg, + const struct esp_semihost_ops *semihost_ops) +{ + int ret = xtensa_init_arch_info(target, &esp_xtensa->xtensa, dm_cfg); + if (ret != ERROR_OK) + return ret; + ret = esp_common_init(&esp_xtensa->esp, &xtensa_algo_hw); + if (ret != ERROR_OK) + return ret; + + esp_xtensa->semihost.ops = (struct esp_semihost_ops *)semihost_ops; + esp_xtensa->apptrace.hw = &esp_xtensa_apptrace_hw; + return ERROR_OK; +} + +int esp_xtensa_target_init(struct command_context *cmd_ctx, struct target *target) +{ + return xtensa_target_init(cmd_ctx, target); +} + +void esp_xtensa_target_deinit(struct target *target) +{ + LOG_DEBUG("start"); + + if (target_was_examined(target)) { + int ret = esp_xtensa_dbgstubs_restore(target); + if (ret != ERROR_OK) + return; + } + xtensa_target_deinit(target); + free(target_to_esp_xtensa(target)); /* same as free(xtensa) */ +} + +int esp_xtensa_arch_state(struct target *target) +{ + return ERROR_OK; +} + +int esp_xtensa_poll(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + struct esp_xtensa_common *esp_xtensa_common = target_to_esp_xtensa(target); + + int ret = xtensa_poll(target); + + if (xtensa_dm_power_status_get(&xtensa->dbg_mod) & PWRSTAT_COREWASRESET(xtensa)) { + LOG_TARGET_DEBUG(target, "Clear debug stubs info"); + memset(&esp_xtensa_common->esp.dbg_stubs, 0, sizeof(esp_xtensa_common->esp.dbg_stubs)); + } + if (target->state != TARGET_DEBUG_RUNNING) + esp_xtensa_dbgstubs_addr_check(target); + return ret; +} + +static void esp_xtensa_dbgstubs_addr_check(struct target *target) +{ + struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); + uint32_t vec_addr = 0; + + if (esp_xtensa->esp.dbg_stubs.base != 0) + return; + + int res = esp_xtensa_apptrace_status_reg_read(target, &vec_addr); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read debug stubs address location (%d)!", res); + return; + } + if (xtensa_data_addr_valid(target, vec_addr)) { + LOG_TARGET_INFO(target, "Detected debug stubs @ %" PRIx32, vec_addr); + res = esp_xtensa_apptrace_status_reg_write(target, 0); + if (res != ERROR_OK) + LOG_ERROR("Failed to clear debug stubs address location (%d)!", res); + esp_xtensa->esp.dbg_stubs.base = vec_addr; + } +} + +static void esp_xtensa_dbgstubs_info_update(struct target *target) +{ + struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); + + if (esp_xtensa->esp.dbg_stubs.base == 0 || esp_xtensa->esp.dbg_stubs.entries_count != 0) + return; + + int res = esp_dbgstubs_table_read(target, &esp_xtensa->esp.dbg_stubs); + if (res != ERROR_OK) + return; + if (esp_xtensa->esp.dbg_stubs.entries_count == 0) + return; + + /* read debug stubs descriptor */ + ESP_XTENSA_DBGSTUBS_UPDATE_DATA_ENTRY(esp_xtensa->esp.dbg_stubs.entries[ESP_DBG_STUB_DESC]); + res = target_read_buffer(target, esp_xtensa->esp.dbg_stubs.entries[ESP_DBG_STUB_DESC], + sizeof(struct esp_dbg_stubs_desc), + (uint8_t *)&esp_xtensa->esp.dbg_stubs.desc); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read debug stubs descriptor (%d)!", res); + return; + } + ESP_XTENSA_DBGSTUBS_UPDATE_CODE_ENTRY(esp_xtensa->esp.dbg_stubs.desc.tramp_addr); + ESP_XTENSA_DBGSTUBS_UPDATE_DATA_ENTRY(esp_xtensa->esp.dbg_stubs.desc.min_stack_addr); + ESP_XTENSA_DBGSTUBS_UPDATE_CODE_ENTRY(esp_xtensa->esp.dbg_stubs.desc.data_alloc); + ESP_XTENSA_DBGSTUBS_UPDATE_CODE_ENTRY(esp_xtensa->esp.dbg_stubs.desc.data_free); +} + +int esp_xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint) +{ + return xtensa_breakpoint_add(target, breakpoint); + /* flash breakpoints will be handled in another patch */ +} + +int esp_xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint) +{ + return xtensa_breakpoint_remove(target, breakpoint); + /* flash breakpoints will be handled in another patch */ +} diff --git a/src/target/espressif/esp_xtensa.h b/src/target/espressif/esp_xtensa.h new file mode 100644 index 0000000000..00f67a3706 --- /dev/null +++ b/src/target/espressif/esp_xtensa.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Generic ESP xtensa target implementation for OpenOCD * + * Copyright (C) 2019 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESP_XTENSA_H +#define OPENOCD_TARGET_ESP_XTENSA_H + +#include <target/target.h> +#include <target/xtensa/xtensa.h> +#include "esp_semihosting.h" +#include "esp.h" +#include "esp_xtensa_apptrace.h" + +struct esp_xtensa_common { + struct xtensa xtensa; /* must be the first element */ + struct esp_common esp; + struct esp_semihost_data semihost; + struct esp_xtensa_apptrace_info apptrace; +}; + +static inline struct esp_xtensa_common *target_to_esp_xtensa(struct target *target) +{ + return container_of(target->arch_info, struct esp_xtensa_common, xtensa); +} + +int esp_xtensa_init_arch_info(struct target *target, + struct esp_xtensa_common *esp_xtensa, + struct xtensa_debug_module_config *dm_cfg, + const struct esp_semihost_ops *semihost_ops); +int esp_xtensa_target_init(struct command_context *cmd_ctx, struct target *target); +void esp_xtensa_target_deinit(struct target *target); +int esp_xtensa_arch_state(struct target *target); +void esp_xtensa_queue_tdi_idle(struct target *target); +int esp_xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint); +int esp_xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint); +int esp_xtensa_poll(struct target *target); +int esp_xtensa_on_halt(struct target *target); + +#endif /* OPENOCD_TARGET_ESP_XTENSA_H */ diff --git a/src/target/espressif/esp_xtensa_algorithm.c b/src/target/espressif/esp_xtensa_algorithm.c new file mode 100644 index 0000000000..68005cbf2c --- /dev/null +++ b/src/target/espressif/esp_xtensa_algorithm.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Module to run arbitrary code on Xtensa using OpenOCD * + * Copyright (C) 2019 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <target/xtensa/xtensa.h> +#include "esp_xtensa_algorithm.h" + +static int esp_xtensa_algo_init(struct target *target, struct esp_algorithm_run_data *run, + uint32_t num_args, va_list ap); +static int esp_xtensa_algo_cleanup(struct target *target, struct esp_algorithm_run_data *run); +static const uint8_t *esp_xtensa_stub_tramp_get(struct target *target, size_t *size); + +const struct esp_algorithm_hw xtensa_algo_hw = { + .algo_init = esp_xtensa_algo_init, + .algo_cleanup = esp_xtensa_algo_cleanup, + .stub_tramp_get = esp_xtensa_stub_tramp_get, +}; + +/* Generated from contrib/loaders/trampoline/espressif/xtensa/esp_xtensa_stub_tramp_win.S */ +static const uint8_t esp_xtensa_stub_tramp_win[] = { +#include "../../../contrib/loaders/trampoline/espressif/xtensa/esp_xtensa_stub_tramp_win.inc" +}; + +static const uint8_t *esp_xtensa_stub_tramp_get(struct target *target, size_t *size) +{ + struct xtensa *xtensa = target_to_xtensa(target); + + if (!xtensa->core_config->windowed) { + LOG_ERROR("Running stubs is not supported for cores without windowed registers option!"); + return NULL; + } + *size = sizeof(esp_xtensa_stub_tramp_win); + return esp_xtensa_stub_tramp_win; +} + +static int esp_xtensa_algo_regs_init_start(struct target *target, struct esp_algorithm_run_data *run) +{ + uint32_t stack_addr = run->stub.stack_addr; + + LOG_TARGET_DEBUG(target, "Check stack addr 0x%x", stack_addr); + if (stack_addr & 0xFUL) { + stack_addr &= ~0xFUL; + LOG_TARGET_DEBUG(target, "Adjust stack addr to 0x%x", stack_addr); + } + stack_addr -= 16; + struct reg_param *params = run->reg_args.params; + init_reg_param(¶ms[0], "a0", 32, PARAM_OUT); /*TODO: move to tramp */ + init_reg_param(¶ms[1], "a1", 32, PARAM_OUT); + init_reg_param(¶ms[2], "a8", 32, PARAM_OUT); + init_reg_param(¶ms[3], "windowbase", 32, PARAM_OUT); /*TODO: move to tramp */ + init_reg_param(¶ms[4], "windowstart", 32, PARAM_OUT); /*TODO: move to tramp */ + init_reg_param(¶ms[5], "ps", 32, PARAM_OUT); + buf_set_u32(params[0].value, 0, 32, 0); /* a0 TODO: move to tramp */ + buf_set_u32(params[1].value, 0, 32, stack_addr); /* a1 */ + buf_set_u32(params[2].value, 0, 32, run->stub.entry); /* a8 */ + buf_set_u32(params[3].value, 0, 32, 0x0); /* initial window base TODO: move to tramp */ + buf_set_u32(params[4].value, 0, 32, 0x1); /* initial window start TODO: move to tramp */ + buf_set_u32(params[5].value, 0, 32, 0x60025); /* enable WOE, UM and debug interrupts level (6) */ + return ERROR_OK; +} + +static int esp_xtensa_algo_init(struct target *target, struct esp_algorithm_run_data *run, + uint32_t num_args, va_list ap) +{ + enum xtensa_mode core_mode = XT_MODE_ANY; + static const char *const arg_regs[] = { "a2", "a3", "a4", "a5", "a6" }; + + if (!run) + return ERROR_FAIL; + + if (num_args > ARRAY_SIZE(arg_regs)) { + LOG_ERROR("Too many algo user args %u! Max %zu args are supported.", num_args, ARRAY_SIZE(arg_regs)); + return ERROR_FAIL; + } + + struct xtensa_algorithm *ainfo = calloc(1, sizeof(struct xtensa_algorithm)); + if (!ainfo) { + LOG_ERROR("Unable to allocate memory"); + return ERROR_FAIL; + } + + if (run->arch_info) { + struct xtensa_algorithm *xtensa_algo = run->arch_info; + core_mode = xtensa_algo->core_mode; + } + + run->reg_args.first_user_param = ESP_XTENSA_STUB_ARGS_FUNC_START; + run->reg_args.count = run->reg_args.first_user_param + num_args; + if (num_args == 0) + run->reg_args.count++; /* a2 reg is used as the 1st arg and return code */ + LOG_DEBUG("reg params count %d (%d/%d).", + run->reg_args.count, + run->reg_args.first_user_param, + num_args); + run->reg_args.params = calloc(run->reg_args.count, sizeof(struct reg_param)); + if (!run->reg_args.params) { + free(ainfo); + LOG_ERROR("Unable to allocate memory"); + return ERROR_FAIL; + } + + esp_xtensa_algo_regs_init_start(target, run); + + init_reg_param(&run->reg_args.params[run->reg_args.first_user_param + 0], "a2", 32, PARAM_IN_OUT); + + if (num_args > 0) { + uint32_t arg = va_arg(ap, uint32_t); + esp_algorithm_user_arg_set_uint(run, 0, arg); + LOG_DEBUG("Set arg[0] = %d (%s)", arg, run->reg_args.params[run->reg_args.first_user_param + 0].reg_name); + } else { + esp_algorithm_user_arg_set_uint(run, 0, 0); + } + + for (unsigned int i = 1; i < num_args; i++) { + uint32_t arg = va_arg(ap, uint32_t); + init_reg_param(&run->reg_args.params[run->reg_args.first_user_param + i], (char *)arg_regs[i], 32, PARAM_OUT); + esp_algorithm_user_arg_set_uint(run, i, arg); + LOG_DEBUG("Set arg[%d] = %d (%s)", i, arg, run->reg_args.params[run->reg_args.first_user_param + i].reg_name); + } + + ainfo->core_mode = core_mode; + run->stub.ainfo = ainfo; + return ERROR_OK; +} + +static int esp_xtensa_algo_cleanup(struct target *target, struct esp_algorithm_run_data *run) +{ + free(run->stub.ainfo); + for (uint32_t i = 0; i < run->reg_args.count; i++) + destroy_reg_param(&run->reg_args.params[i]); + free(run->reg_args.params); + return ERROR_OK; +} diff --git a/src/target/espressif/esp_xtensa_algorithm.h b/src/target/espressif/esp_xtensa_algorithm.h new file mode 100644 index 0000000000..36fa1a331b --- /dev/null +++ b/src/target/espressif/esp_xtensa_algorithm.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Module to run arbitrary code on Xtensa using OpenOCD * + * Copyright (C) 2019 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESP_XTENSA_ALGO_H +#define OPENOCD_TARGET_ESP_XTENSA_ALGO_H + +#include <target/xtensa/xtensa.h> +#include <target/espressif/esp_algorithm.h> + +/** Index of the first user-defined algo arg. @see algorithm_stub */ +#define ESP_XTENSA_STUB_ARGS_FUNC_START 6 + +extern const struct esp_algorithm_hw xtensa_algo_hw; + +#endif /* OPENOCD_TARGET_XTENSA_ALGO_H */ diff --git a/src/target/espressif/esp_xtensa_apptrace.c b/src/target/espressif/esp_xtensa_apptrace.c new file mode 100644 index 0000000000..5741ab0308 --- /dev/null +++ b/src/target/espressif/esp_xtensa_apptrace.c @@ -0,0 +1,499 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Xtensa application tracing module for OpenOCD * + * Copyright (C) 2017 Espressif Systems Ltd. * + ***************************************************************************/ + +/* + How it works? + https://github.com/espressif/esp-idf/blob/master/components/app_trace/port/xtensa/port.c#L8 +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/align.h> +#include <target/xtensa/xtensa.h> +#include <target/xtensa/xtensa_debug_module.h> +#include "esp_xtensa_apptrace.h" + +/* TRAX is disabled, so we use its registers for our own purposes + * | 31..XXXXXX..24 | 23 .(host_connect). 23 | 22 .(host_data). 22| 21..(block_id)..15 | 14..(block_len)..0 | + */ +#define XTENSA_APPTRACE_CTRL_REG XDMREG_DELAYCNT +#define XTENSA_APPTRACE_BLOCK_ID_MSK 0x7FUL +#define XTENSA_APPTRACE_BLOCK_ID_MAX XTENSA_APPTRACE_BLOCK_ID_MSK +/* if non-zero then apptrace code entered the critical section and the value is an address of the + * critical section's exit point */ +#define XTENSA_APPTRACE_STAT_REG XDMREG_TRIGGERPC + +#define XTENSA_APPTRACE_BLOCK_LEN_MSK 0x7FFFUL +#define XTENSA_APPTRACE_BLOCK_LEN(_l_) ((_l_) & XTENSA_APPTRACE_BLOCK_LEN_MSK) +#define XTENSA_APPTRACE_BLOCK_LEN_GET(_v_) ((_v_) & XTENSA_APPTRACE_BLOCK_LEN_MSK) +#define XTENSA_APPTRACE_BLOCK_ID(_id_) (((_id_) & XTENSA_APPTRACE_BLOCK_ID_MSK) << 15) +#define XTENSA_APPTRACE_BLOCK_ID_GET(_v_) (((_v_) >> 15) & XTENSA_APPTRACE_BLOCK_ID_MSK) +#define XTENSA_APPTRACE_HOST_DATA BIT(22) +#define XTENSA_APPTRACE_HOST_CONNECT BIT(23) + +static int esp_xtensa_apptrace_leave_crit_section_start(struct target *target); +static int esp_xtensa_apptrace_leave_crit_section_stop(struct target *target); +static int esp_xtensa_apptrace_buffs_write(struct target *target, + uint32_t bufs_num, + uint32_t buf_sz[], + const uint8_t *bufs[], + uint32_t block_id, + bool ack, + bool data); + +struct esp32_apptrace_hw esp_xtensa_apptrace_hw = { + .max_block_id = XTENSA_APPTRACE_BLOCK_ID_MAX, + .max_block_size_get = esp_xtensa_apptrace_block_max_size_get, + .status_reg_read = esp_xtensa_apptrace_status_reg_read, + .ctrl_reg_write = esp_xtensa_apptrace_ctrl_reg_write, + .ctrl_reg_read = esp_xtensa_apptrace_ctrl_reg_read, + .data_len_read = esp_xtensa_apptrace_data_len_read, + .data_read = esp_xtensa_apptrace_data_read, + .usr_block_max_size_get = esp_xtensa_apptrace_usr_block_max_size_get, + .buffs_write = esp_xtensa_apptrace_buffs_write, + .leave_trace_crit_section_start = esp_xtensa_apptrace_leave_crit_section_start, + .leave_trace_crit_section_stop = esp_xtensa_apptrace_leave_crit_section_stop, +}; + +uint32_t esp_xtensa_apptrace_block_max_size_get(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + struct xtensa_trace_status trace_status; + struct xtensa_trace_config trace_config; + uint32_t max_trace_block_sz; + + int res = xtensa_dm_trace_status_read(&xtensa->dbg_mod, &trace_status); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read TRAX status (%d)!", res); + return 0; + } + + max_trace_block_sz = BIT(((trace_status.stat >> 8) & 0x1f) - 2) * 4; + res = xtensa_dm_trace_config_read(&xtensa->dbg_mod, &trace_config); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read TRAX config (%d)!", res); + return 0; + } + LOG_DEBUG("ctrl=0x%" PRIx32 " memadrstart=0x%" PRIx32 " memadrend=0x%" PRIx32 " traxadr=0x%" PRIx32, + trace_config.ctrl, + trace_config.memaddr_start, + trace_config.memaddr_end, + trace_config.addr); + + return max_trace_block_sz; +} + +uint32_t esp_xtensa_apptrace_usr_block_max_size_get(struct target *target) +{ + return esp_xtensa_apptrace_block_max_size_get(target) - sizeof(struct esp_apptrace_host2target_hdr); +} + +int esp_xtensa_apptrace_data_len_read(struct target *target, + uint32_t *block_id, + uint32_t *len) +{ + return esp_xtensa_apptrace_ctrl_reg_read(target, block_id, len, NULL); +} + +int esp_xtensa_apptrace_usr_block_write(struct target *target, + uint32_t block_id, + const uint8_t *data, + uint32_t size) +{ + return esp_apptrace_usr_block_write(&esp_xtensa_apptrace_hw, target, block_id, data, size); +} + +static int esp_xtensa_apptrace_data_reverse_read(struct xtensa *xtensa, + uint32_t size, + uint8_t *buffer, + uint8_t *unal_bytes) +{ + int res = 0; + uint32_t rd_sz = ALIGN_UP(size, 4); + + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, (xtensa->core_config->trace.mem_sz - rd_sz) / 4); + if (res != ERROR_OK) + return res; + if (!IS_ALIGNED(size, 4)) { + res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, unal_bytes); + if (res != ERROR_OK) + return res; + } + for (unsigned int i = size / 4; i != 0; i--) { + res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, &buffer[(i - 1) * 4]); + if (res != ERROR_OK) + return res; + } + return ERROR_OK; +} + +static int esp_xtensa_apptrace_data_normal_read(struct xtensa *xtensa, + uint32_t size, + uint8_t *buffer, + uint8_t *unal_bytes) +{ + int res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, 0); + if (res != ERROR_OK) + return res; + for (unsigned int i = 0; i < size / 4; i++) { + res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, &buffer[i * 4]); + if (res != ERROR_OK) + return res; + } + if (!IS_ALIGNED(size, 4)) { + res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, unal_bytes); + if (res != ERROR_OK) + return res; + } + return ERROR_OK; +} + +int esp_xtensa_apptrace_data_read(struct target *target, + uint32_t size, + uint8_t *buffer, + uint32_t block_id, + bool ack) +{ + struct xtensa *xtensa = target_to_xtensa(target); + int res; + uint32_t tmp = XTENSA_APPTRACE_HOST_CONNECT | XTENSA_APPTRACE_BLOCK_ID(block_id) | + XTENSA_APPTRACE_BLOCK_LEN(0); + uint8_t unal_bytes[4]; + + LOG_DEBUG("Read data on target (%s)", target_name(target)); + if (xtensa->core_config->trace.reversed_mem_access) + res = esp_xtensa_apptrace_data_reverse_read(xtensa, size, buffer, unal_bytes); + else + res = esp_xtensa_apptrace_data_normal_read(xtensa, size, buffer, unal_bytes); + if (res != ERROR_OK) + return res; + if (ack) { + LOG_DEBUG("Ack block %" PRIu32 " target (%s)!", block_id, target_name(target)); + res = xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp); + if (res != ERROR_OK) + return res; + } + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_ERROR("Failed to exec JTAG queue!"); + return res; + } + if (!IS_ALIGNED(size, 4)) { + /* copy the last unaligned bytes */ + memcpy(buffer + ALIGN_DOWN(size, 4), unal_bytes, size & 0x3UL); + } + return ERROR_OK; +} + +int esp_xtensa_apptrace_ctrl_reg_write(struct target *target, + uint32_t block_id, + uint32_t len, + bool conn, + bool data) +{ + struct xtensa *xtensa = target_to_xtensa(target); + uint32_t tmp = (conn ? XTENSA_APPTRACE_HOST_CONNECT : 0) | + (data ? XTENSA_APPTRACE_HOST_DATA : 0) | XTENSA_APPTRACE_BLOCK_ID(block_id) | + XTENSA_APPTRACE_BLOCK_LEN(len); + + xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_ERROR("Failed to exec JTAG queue!"); + return res; + } + + return ERROR_OK; +} + +int esp_xtensa_apptrace_ctrl_reg_read(struct target *target, + uint32_t *block_id, + uint32_t *len, + bool *conn) +{ + struct xtensa *xtensa = target_to_xtensa(target); + uint8_t tmp[4]; + + xtensa_queue_dbg_reg_read(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) + return res; + uint32_t val = target_buffer_get_u32(target, tmp); + if (block_id) + *block_id = XTENSA_APPTRACE_BLOCK_ID_GET(val); + if (len) + *len = XTENSA_APPTRACE_BLOCK_LEN_GET(val); + if (conn) + *conn = val & XTENSA_APPTRACE_HOST_CONNECT; + return ERROR_OK; +} + +int esp_xtensa_apptrace_status_reg_read(struct target *target, uint32_t *stat) +{ + struct xtensa *xtensa = target_to_xtensa(target); + uint8_t tmp[4]; + + int res = xtensa_queue_dbg_reg_read(xtensa, XTENSA_APPTRACE_STAT_REG, tmp); + if (res != ERROR_OK) + return res; + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_ERROR("Failed to exec JTAG queue!"); + return res; + } + *stat = buf_get_u32(tmp, 0, 32); + return ERROR_OK; +} + +int esp_xtensa_apptrace_status_reg_write(struct target *target, uint32_t stat) +{ + struct xtensa *xtensa = target_to_xtensa(target); + + xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_STAT_REG, stat); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_ERROR("Failed to exec JTAG queue!"); + return res; + } + return ERROR_OK; +} + +static int esp_xtensa_swdbg_activate(struct target *target, int enab) +{ + struct xtensa *xtensa = target_to_xtensa(target); + + xtensa_queue_dbg_reg_write(xtensa, enab ? XDMREG_DCRSET : XDMREG_DCRCLR, OCDDCR_DEBUGSWACTIVE); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_ERROR("%s: writing DCR failed!", target->cmd_name); + return res; + } + + return ERROR_OK; +} + +static int esp_xtensa_apptrace_leave_crit_section_start(struct target *target) +{ + /* TODO: not sure that we need this, but it seems that we fail to leave tracing critical + *section w/o this */ + int res = esp_xtensa_swdbg_activate(target, 1 /*enable*/); + if (res != ERROR_OK) { + LOG_ERROR("Failed to activate SW debug (%d)!", res); + return res; + } + return ERROR_OK; +} + +static int esp_xtensa_apptrace_leave_crit_section_stop(struct target *target) +{ + int res = esp_xtensa_swdbg_activate(target, 0 /*disable*/); + if (res != ERROR_OK) { + LOG_ERROR("Failed to activate SW debug (%d)!", res); + return res; + } + return ERROR_OK; +} + +static int esp_xtensa_apptrace_queue_reverse_write(struct target *target, uint32_t bufs_num, + uint32_t buf_sz[], const uint8_t *bufs[]) +{ + int res = ERROR_OK; + uint32_t cached_bytes = 0, total_sz = 0; + uint8_t cached_data8[sizeof(uint32_t)] = { 0 }; + uint32_t cached_data32 = 0; + + struct xtensa *xtensa = target_to_xtensa(target); + + for (uint32_t i = 0; i < bufs_num; i++) + total_sz += buf_sz[i]; + if (!IS_ALIGNED(total_sz, 4)) { + cached_bytes = sizeof(uint32_t) - (total_sz & 0x3UL); + total_sz = ALIGN_UP(total_sz, 4); + } + xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, (xtensa->core_config->trace.mem_sz - total_sz) / 4); + for (uint32_t i = bufs_num; i > 0; i--) { + uint32_t bsz = buf_sz[i - 1]; + const uint8_t *cur_buf = &bufs[i - 1][bsz]; + uint32_t bytes_to_cache; + /* if there are cached bytes from the previous buffer, combine them with the last + * from the current buffer */ + if (cached_bytes) { + if ((cached_bytes + bsz) < sizeof(uint32_t)) + bytes_to_cache = bsz; + else + bytes_to_cache = sizeof(uint32_t) - cached_bytes; + memcpy(&cached_data8[sizeof(uint32_t) - cached_bytes - bytes_to_cache], + cur_buf - bytes_to_cache, + bytes_to_cache); + cached_data32 = target_buffer_get_u32(target, cached_data8); + cached_bytes += bytes_to_cache; + if (cached_bytes < sizeof(uint32_t)) + continue; + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32); + if (res != ERROR_OK) + return res; + bsz -= bytes_to_cache; + cur_buf -= bytes_to_cache; + memset(cached_data8, 0x00, sizeof(cached_data8)); + cached_bytes = 0; + } + /* write full dwords */ + for (unsigned int k = bsz; k >= sizeof(uint32_t); k -= sizeof(uint32_t)) { + uint32_t temp = target_buffer_get_u32(target, cur_buf - sizeof(uint32_t)); + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, temp); + if (res != ERROR_OK) + return res; + cur_buf -= sizeof(uint32_t); + } + /* if there are bytes to be cached (1..3) */ + bytes_to_cache = bsz & 0x3UL; + if (bytes_to_cache > 0) { + if (bytes_to_cache + cached_bytes >= sizeof(uint32_t)) { + /* filling the cache buffer from the end to beginning */ + uint32_t to_copy = sizeof(uint32_t) - cached_bytes; + memcpy(&cached_data8[0], cur_buf - to_copy, to_copy); + cached_data32 = target_buffer_get_u32(target, cached_data8); + /* write full word of cached bytes */ + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32); + if (res != ERROR_OK) + return res; + /* cache remaining bytes */ + memset(cached_data8, 0x00, sizeof(cached_data8)); + cur_buf -= to_copy; + to_copy = bytes_to_cache + cached_bytes - sizeof(uint32_t); + memcpy(&cached_data8[sizeof(uint32_t) - to_copy], cur_buf - to_copy, to_copy); + cached_bytes = to_copy; + } else { + /* filling the cache buffer from the end to beginning */ + memcpy(&cached_data8[sizeof(uint32_t) - cached_bytes - bytes_to_cache], + cur_buf - bytes_to_cache, + bytes_to_cache); + cached_bytes += bytes_to_cache; + } + } + } + return ERROR_OK; +} + +static int esp_xtensa_apptrace_queue_normal_write(struct target *target, uint32_t bufs_num, + uint32_t buf_sz[], const uint8_t *bufs[]) +{ + int res = ERROR_OK; + uint32_t cached_bytes = 0; + uint8_t cached_data8[4] = { 0 }; + uint32_t cached_data32 = 0; + + struct xtensa *xtensa = target_to_xtensa(target); + + /* | 1 | 2 | 1 | 2 | 4 |.......| + * | 4 | 4 | 4 | */ + xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, 0); + for (unsigned int i = 0; i < bufs_num; i++) { + uint32_t bsz = buf_sz[i]; + const uint8_t *cur_buf = bufs[i]; + uint32_t bytes_to_cache; + /* if there are cached bytes from the previous buffer, combine them with the last + * from the current buffer */ + if (cached_bytes) { + if ((cached_bytes + bsz) < sizeof(uint32_t)) + bytes_to_cache = bsz; + else + bytes_to_cache = sizeof(uint32_t) - cached_bytes; + memcpy(&cached_data8[cached_bytes], cur_buf, bytes_to_cache); + cached_bytes += bytes_to_cache; + if (cached_bytes < sizeof(uint32_t)) + continue; + cached_data32 = target_buffer_get_u32(target, cached_data8); + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32); + if (res != ERROR_OK) + return res; + bsz -= bytes_to_cache; + cur_buf += bytes_to_cache; + memset(cached_data8, 0x00, sizeof(cached_data8)); + cached_bytes = 0; + } + /* write full dwords */ + for (unsigned int k = 0; (k + sizeof(uint32_t)) <= bsz; k += sizeof(uint32_t)) { + uint32_t temp = target_buffer_get_u32(target, cur_buf); + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, temp); + if (res != ERROR_OK) + return res; + cur_buf += sizeof(uint32_t); + } + /* if there are bytes to be cached (1..3) */ + bytes_to_cache = bsz & 0x3UL; + if (bytes_to_cache > 0) { + if (bytes_to_cache + cached_bytes >= sizeof(uint32_t)) { + memcpy(&cached_data8[0], cur_buf, sizeof(uint32_t) - cached_bytes); + cached_data32 = target_buffer_get_u32(target, cached_data8); + /* write full word of cached bytes */ + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32); + if (res != ERROR_OK) + return res; + /* cache remaining bytes */ + memset(cached_data8, 0x00, sizeof(cached_data8)); + cur_buf += sizeof(uint32_t) - cached_bytes; + cached_bytes = bytes_to_cache + cached_bytes - sizeof(uint32_t); + memcpy(&cached_data8[0], cur_buf, cached_bytes); + } else { + memcpy(&cached_data8[cached_bytes], cur_buf, bytes_to_cache); + cached_bytes += bytes_to_cache; + } + } + } + if (cached_bytes) { + /* write remaining cached bytes */ + cached_data32 = target_buffer_get_u32(target, cached_data8); + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32); + if (res != ERROR_OK) + return res; + } + return ERROR_OK; +} + +static int esp_xtensa_apptrace_buffs_write(struct target *target, + uint32_t bufs_num, + uint32_t buf_sz[], + const uint8_t *bufs[], + uint32_t block_id, + bool ack, + bool data) +{ + struct xtensa *xtensa = target_to_xtensa(target); + int res = ERROR_OK; + uint32_t tmp = XTENSA_APPTRACE_HOST_CONNECT | + (data ? XTENSA_APPTRACE_HOST_DATA : 0) | XTENSA_APPTRACE_BLOCK_ID(block_id) | + XTENSA_APPTRACE_BLOCK_LEN(0); + + if (xtensa->core_config->trace.reversed_mem_access) + res = esp_xtensa_apptrace_queue_reverse_write(target, bufs_num, buf_sz, bufs); + else + res = esp_xtensa_apptrace_queue_normal_write(target, bufs_num, buf_sz, bufs); + if (res != ERROR_OK) + return res; + if (ack) { + LOG_DEBUG("Ack block %" PRId32 " on target (%s)!", block_id, target_name(target)); + res = xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp); + if (res != ERROR_OK) + return res; + } + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_ERROR("Failed to exec JTAG queue!"); + return res; + } + return ERROR_OK; +} diff --git a/src/target/espressif/esp_xtensa_apptrace.h b/src/target/espressif/esp_xtensa_apptrace.h new file mode 100644 index 0000000000..0a9be731fe --- /dev/null +++ b/src/target/espressif/esp_xtensa_apptrace.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Xtensa application tracing module for OpenOCD * + * Copyright (C) 2017 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESP_XTENSA_APPTRACE_H +#define OPENOCD_TARGET_ESP_XTENSA_APPTRACE_H + +#include "esp32_apptrace.h" + +struct esp_xtensa_apptrace_info { + const struct esp32_apptrace_hw *hw; +}; + +extern struct esp32_apptrace_hw esp_xtensa_apptrace_hw; + +int esp_xtensa_apptrace_data_len_read(struct target *target, uint32_t *block_id, uint32_t *len); +int esp_xtensa_apptrace_data_read(struct target *target, + uint32_t size, + uint8_t *buffer, + uint32_t block_id, + bool ack); +int esp_xtensa_apptrace_ctrl_reg_read(struct target *target, uint32_t *block_id, uint32_t *len, bool *conn); +int esp_xtensa_apptrace_ctrl_reg_write(struct target *target, + uint32_t block_id, + uint32_t len, + bool conn, + bool data); +int esp_xtensa_apptrace_status_reg_write(struct target *target, uint32_t stat); +int esp_xtensa_apptrace_status_reg_read(struct target *target, uint32_t *stat); +uint32_t esp_xtensa_apptrace_block_max_size_get(struct target *target); +uint32_t esp_xtensa_apptrace_usr_block_max_size_get(struct target *target); +int esp_xtensa_apptrace_usr_block_write(struct target *target, uint32_t block_id, const uint8_t *data, uint32_t size); + +#endif /* OPENOCD_TARGET_ESP_XTENSA_APPTRACE_H */ diff --git a/src/target/espressif/esp_xtensa_semihosting.c b/src/target/espressif/esp_xtensa_semihosting.c new file mode 100644 index 0000000000..54e9c4b8df --- /dev/null +++ b/src/target/espressif/esp_xtensa_semihosting.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (c) 2020 Espressif Systems (Shanghai) Co. Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <target/semihosting_common.h> +#include <target/xtensa/xtensa_regs.h> +#include <target/xtensa/xtensa.h> +#include "esp_xtensa.h" +#include "esp_xtensa_semihosting.h" + +#define ESP_XTENSA_SYSCALL 0x41E0 /* XT_INS_BREAK(1, 14) */ +#define ESP_XTENSA_SYSCALL_SZ 3 + +#define XTENSA_SYSCALL_OP_REG XT_REG_IDX_A2 +#define XTENSA_SYSCALL_RETVAL_REG XT_REG_IDX_A2 +#define XTENSA_SYSCALL_ERRNO_REG XT_REG_IDX_A3 + +static int esp_xtensa_semihosting_setup(struct target *target, int enable) +{ + LOG_TARGET_DEBUG(target, "semihosting enable=%d", enable); + + return ERROR_OK; +} + +static int esp_xtensa_semihosting_post_result(struct target *target) +{ + /* Even with the v2 and later, errno will not retrieved from A3 reg, it is safe to set */ + xtensa_reg_set(target, XTENSA_SYSCALL_RETVAL_REG, target->semihosting->result); + xtensa_reg_set(target, XTENSA_SYSCALL_ERRNO_REG, target->semihosting->sys_errno); + return ERROR_OK; +} + +/** + * Checks and processes an ESP Xtensa semihosting request. This is meant + * to be called when the target is stopped due to a debug mode entry. + * If the value 0 is returned then there was nothing to process. A non-zero + * return value signifies that a request was processed and the target resumed, + * or an error was encountered, in which case the caller must return immediately. + * + * @param target Pointer to the ESP Xtensa target to process. + * @param retval Pointer to a location where the return code will be stored + * @return SEMIHOSTING_HANDLED if a request was processed or SEMIHOSTING_NONE with the proper retval + */ +int esp_xtensa_semihosting(struct target *target, int *retval) +{ + struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); + + xtensa_reg_val_t dbg_cause = xtensa_reg_get(target, XT_REG_IDX_DEBUGCAUSE); + if ((dbg_cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN)) == 0) + return SEMIHOSTING_NONE; + + uint8_t brk_insn_buf[sizeof(uint32_t)] = { 0 }; + xtensa_reg_val_t pc = xtensa_reg_get(target, XT_REG_IDX_PC); + *retval = target_read_memory(target, pc, ESP_XTENSA_SYSCALL_SZ, 1, brk_insn_buf); + if (*retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read break instruction!"); + return SEMIHOSTING_NONE; + } + + uint32_t syscall_ins = buf_get_u32(brk_insn_buf, 0, 32); + if (syscall_ins != ESP_XTENSA_SYSCALL) { + *retval = ERROR_OK; + return SEMIHOSTING_NONE; + } + + if (esp_xtensa->semihost.ops && esp_xtensa->semihost.ops->prepare) + esp_xtensa->semihost.ops->prepare(target); + + xtensa_reg_val_t a2 = xtensa_reg_get(target, XT_REG_IDX_A2); + xtensa_reg_val_t a3 = xtensa_reg_get(target, XT_REG_IDX_A3); + LOG_TARGET_DEBUG(target, "Semihosting call 0x%" PRIx32 " 0x%" PRIx32 " Base dir '%s'", + a2, + a3, + target->semihosting->basedir ? target->semihosting->basedir : ""); + + target->semihosting->op = a2; + target->semihosting->param = a3; + + *retval = semihosting_common(target); + + /* Most operations are resumable, except the two exit calls. */ + if (*retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "Semihosting operation (op: 0x%x) error! Code: %d", + target->semihosting->op, + *retval); + } + + /* Resume if target it is resumable and we are not waiting on a fileio operation to complete. */ + if (target->semihosting->is_resumable && !target->semihosting->hit_fileio) + target_to_esp_xtensa(target)->semihost.need_resume = true; + + return SEMIHOSTING_HANDLED; +} + +static int xtensa_semihosting_init(struct target *target) +{ + return semihosting_common_init(target, esp_xtensa_semihosting_setup, esp_xtensa_semihosting_post_result); +} + +int esp_xtensa_semihosting_init(struct target *target) +{ + int retval = xtensa_semihosting_init(target); + if (retval != ERROR_OK) + return retval; + target->semihosting->word_size_bytes = 4; /* 32 bits */ + target->semihosting->user_command_extension = esp_semihosting_common; + return ERROR_OK; +} diff --git a/src/target/espressif/esp_xtensa_semihosting.h b/src/target/espressif/esp_xtensa_semihosting.h new file mode 100644 index 0000000000..1da3115796 --- /dev/null +++ b/src/target/espressif/esp_xtensa_semihosting.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (c) 2020 Espressif Systems (Shanghai) Co. Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESP_XTENSA_SEMIHOSTING_H +#define OPENOCD_TARGET_ESP_XTENSA_SEMIHOSTING_H + +#include <target/target.h> + +int esp_xtensa_semihosting_init(struct target *target); +int esp_xtensa_semihosting(struct target *target, int *retval); + +#endif /* OPENOCD_TARGET_ESP_XTENSA_SEMIHOSTING_H */ diff --git a/src/target/espressif/esp_xtensa_smp.c b/src/target/espressif/esp_xtensa_smp.c new file mode 100644 index 0000000000..f883b1ce76 --- /dev/null +++ b/src/target/espressif/esp_xtensa_smp.c @@ -0,0 +1,1035 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * ESP Xtensa SMP target API for OpenOCD * + * Copyright (C) 2020 Espressif Systems Ltd. Co * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "assert.h" +#include <target/target.h> +#include <target/target_type.h> +#include <target/smp.h> +#include <target/semihosting_common.h> +#include "esp_xtensa_smp.h" +#include "esp_xtensa_semihosting.h" +#include "esp_algorithm.h" + +/* +Multiprocessor stuff common: + +The ESP Xtensa chip can have several cores in it, which can run in SMP-mode if an +SMP-capable OS is running. The hardware has a few features which makes +SMP debugging much easier. + +First of all, there's something called a 'break network', consisting of a +BreakIn input and a BreakOut output on each CPU. The idea is that as soon +as a CPU goes into debug mode for whatever reason, it'll signal that using +its DebugOut pin. This signal is connected to the other CPU's DebugIn +input, causing this CPU also to go into debugging mode. To resume execution +when using only this break network, we will need to manually resume both +CPUs. + +An alternative to this is the XOCDMode output and the RunStall (or DebugStall) +input. When these are cross-connected, a CPU that goes into debug mode will +halt execution entirely on the other CPU. Execution on the other CPU can be +resumed by either the first CPU going out of debug mode, or the second CPU +going into debug mode: the stall is temporarily lifted as long as the stalled +CPU is in debug mode. + +A third, separate, signal is CrossTrigger. This is connected in the same way +as the breakIn/breakOut network, but is for the TRAX (trace memory) feature; +it does not affect OCD in any way. +*/ + +/* +Multiprocessor stuff: + +The ESP Xtensa chip has several Xtensa cores inside, but represent themself to the OCD +as one chip that works in multithreading mode under FreeRTOS OS. +The core that initiate the stop condition will be defined as an active cpu. +When one core stops, then other core will be stopped automatically by smpbreak. +The core that initiates stop condition will be defined as an active core, and +registers of this core will be transferred. +*/ + +#define ESP_XTENSA_SMP_EXAMINE_OTHER_CORES 5 + +static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resume); + +static inline struct esp_xtensa_smp_common *target_to_esp_xtensa_smp(struct target *target) +{ + return container_of(target->arch_info, struct esp_xtensa_smp_common, esp_xtensa); +} + +int esp_xtensa_smp_assert_reset(struct target *target) +{ + return ERROR_OK; +} + +int esp_xtensa_smp_deassert_reset(struct target *target) +{ + LOG_TARGET_DEBUG(target, "begin"); + + int ret = xtensa_deassert_reset(target); + if (ret != ERROR_OK) + return ret; + /* in SMP mode when chip was running single-core app the other core can be left un-examined, + because examination is done before SOC reset. But after SOC reset it is functional and should be handled. + So try to examine un-examined core just after SOC reset */ + if (target->smp && !target_was_examined(target)) + ret = xtensa_examine(target); + return ret; +} + +int esp_xtensa_smp_soft_reset_halt(struct target *target) +{ + int res; + struct target_list *head; + struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target); + + LOG_TARGET_DEBUG(target, "begin"); + /* in SMP mode we need to ensure that at first we reset SOC on PRO-CPU + and then call xtensa_assert_reset() for all cores */ + if (target->smp && target->coreid != 0) + return ERROR_OK; + /* Reset the SoC first */ + if (esp_xtensa_smp->chip_ops->reset) { + res = esp_xtensa_smp->chip_ops->reset(target); + if (res != ERROR_OK) + return res; + } + if (!target->smp) + return xtensa_assert_reset(target); + + foreach_smp_target(head, target->smp_targets) { + res = xtensa_assert_reset(head->target); + if (res != ERROR_OK) + return res; + } + return ERROR_OK; +} + +int esp_xtensa_smp_on_halt(struct target *target) +{ + struct target_list *head; + + if (!target->smp) + return esp_xtensa_on_halt(target); + + foreach_smp_target(head, target->smp_targets) { + int res = esp_xtensa_on_halt(head->target); + if (res != ERROR_OK) + return res; + } + return ERROR_OK; +} + +static struct target *get_halted_esp_xtensa_smp(struct target *target, int32_t coreid) +{ + struct target_list *head; + struct target *curr; + + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED)) + return curr; + } + + return target; +} + +int esp_xtensa_smp_poll(struct target *target) +{ + enum target_state old_state = target->state; + struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target); + struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target); + uint32_t old_dbg_stubs_base = esp_xtensa->esp.dbg_stubs.base; + struct target_list *head; + struct target *curr; + bool other_core_resume_req = false; + + if (target->state == TARGET_HALTED && target->smp && target->gdb_service && !target->gdb_service->target) { + target->gdb_service->target = get_halted_esp_xtensa_smp(target, target->gdb_service->core[1]); + LOG_INFO("Switch GDB target to '%s'", target_name(target->gdb_service->target)); + if (esp_xtensa_smp->chip_ops->on_halt) + esp_xtensa_smp->chip_ops->on_halt(target); + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + return ERROR_OK; + } + + int ret = esp_xtensa_poll(target); + if (ret != ERROR_OK) + return ret; + + if (esp_xtensa->esp.dbg_stubs.base && old_dbg_stubs_base != esp_xtensa->esp.dbg_stubs.base) { + /* debug stubs base is set only in PRO-CPU TRAX register, so sync this info */ + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + if (curr == target) + continue; + target_to_esp_xtensa(curr)->esp.dbg_stubs.base = esp_xtensa->esp.dbg_stubs.base; + } + } + + if (target->smp) { + if (target->state == TARGET_RESET) { + esp_xtensa_smp->examine_other_cores = ESP_XTENSA_SMP_EXAMINE_OTHER_CORES; + } else if (esp_xtensa_smp->examine_other_cores > 0 && + (target->state == TARGET_RUNNING || target->state == TARGET_HALTED)) { + LOG_TARGET_DEBUG(target, "Check for unexamined cores after reset"); + bool all_examined = true; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + if (curr == target) + continue; + if (!target_was_examined(curr)) { + if (target_examine_one(curr) != ERROR_OK) { + LOG_DEBUG("Failed to examine!"); + all_examined = false; + } + } + } + if (all_examined) + esp_xtensa_smp->examine_other_cores = 0; + else + esp_xtensa_smp->examine_other_cores--; + } + } + + if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) { + if (target->smp) { + ret = esp_xtensa_smp_update_halt_gdb(target, &other_core_resume_req); + if (ret != ERROR_OK) + return ret; + } + /* Call any event callbacks that are applicable */ + if (old_state == TARGET_DEBUG_RUNNING) { + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); + } else { + if (esp_xtensa_semihosting(target, &ret) == SEMIHOSTING_HANDLED) { + if (ret == ERROR_OK && esp_xtensa->semihost.need_resume && + !esp_xtensa_smp->other_core_does_resume) { + esp_xtensa->semihost.need_resume = false; + /* Resume xtensa_resume will handle BREAK instruction. */ + ret = target_resume(target, 1, 0, 1, 0); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to resume target"); + return ret; + } + } + return ret; + } + /* check whether any core polled by esp_xtensa_smp_update_halt_gdb() requested resume */ + if (target->smp && other_core_resume_req) { + /* Resume xtensa_resume will handle BREAK instruction. */ + ret = target_resume(target, 1, 0, 1, 0); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to resume target"); + return ret; + } + return ERROR_OK; + } + if (esp_xtensa_smp->chip_ops->on_halt) + esp_xtensa_smp->chip_ops->on_halt(target); + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + } + + return ERROR_OK; +} + +static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resume) +{ + struct esp_xtensa_smp_common *esp_xtensa_smp; + struct target *gdb_target = NULL; + struct target_list *head; + struct target *curr; + int ret = ERROR_OK; + + *need_resume = false; + + if (target->gdb_service && target->gdb_service->target) + LOG_DEBUG("GDB target '%s'", target_name(target->gdb_service->target)); + + if (target->gdb_service && target->gdb_service->core[0] == -1) { + target->gdb_service->target = target; + target->gdb_service->core[0] = target->coreid; + LOG_INFO("Set GDB target to '%s'", target_name(target)); + } + + if (target->gdb_service) + gdb_target = target->gdb_service->target; + + /* due to smpbreak config other cores can also go to HALTED state */ + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + LOG_DEBUG("Check target '%s'", target_name(curr)); + /* skip calling context */ + if (curr == target) + continue; + if (!target_was_examined(curr)) { + curr->state = TARGET_HALTED; + continue; + } + /* skip targets that were already halted */ + if (curr->state == TARGET_HALTED) + continue; + /* Skip gdb_target; it alerts GDB so has to be polled as last one */ + if (curr == gdb_target) + continue; + LOG_DEBUG("Poll target '%s'", target_name(curr)); + + esp_xtensa_smp = target_to_esp_xtensa_smp(curr); + /* avoid auto-resume after syscall, it will be done later */ + esp_xtensa_smp->other_core_does_resume = true; + /* avoid recursion in esp_xtensa_smp_poll() */ + curr->smp = 0; + if (esp_xtensa_smp->chip_ops->poll) + ret = esp_xtensa_smp->chip_ops->poll(curr); + else + ret = esp_xtensa_smp_poll(curr); + curr->smp = 1; + if (ret != ERROR_OK) + return ret; + esp_xtensa_smp->other_core_does_resume = false; + struct esp_xtensa_common *curr_esp_xtensa = target_to_esp_xtensa(curr); + if (curr_esp_xtensa->semihost.need_resume) { + curr_esp_xtensa->semihost.need_resume = false; + *need_resume = true; + } + } + + /* after all targets were updated, poll the gdb serving target */ + if (gdb_target && gdb_target != target) { + esp_xtensa_smp = target_to_esp_xtensa_smp(gdb_target); + if (esp_xtensa_smp->chip_ops->poll) + ret = esp_xtensa_smp->chip_ops->poll(gdb_target); + else + ret = esp_xtensa_smp_poll(gdb_target); + } + + LOG_DEBUG("exit"); + + return ret; +} + +static inline int esp_xtensa_smp_smpbreak_disable(struct target *target, uint32_t *smp_break) +{ + int res = xtensa_smpbreak_get(target, smp_break); + if (res != ERROR_OK) + return res; + return xtensa_smpbreak_set(target, 0); +} + +static inline int esp_xtensa_smp_smpbreak_restore(struct target *target, uint32_t smp_break) +{ + return xtensa_smpbreak_set(target, smp_break); +} + +static int esp_xtensa_smp_resume_cores(struct target *target, + int handle_breakpoints, + int debug_execution) +{ + struct target_list *head; + struct target *curr; + + LOG_TARGET_DEBUG(target, "begin"); + + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + /* in single-core mode disabled core cannot be examined, but need to be resumed too*/ + if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) { + /* resume current address, not in SMP mode */ + curr->smp = 0; + int res = esp_xtensa_smp_resume(curr, 1, 0, handle_breakpoints, debug_execution); + curr->smp = 1; + if (res != ERROR_OK) + return res; + } + } + return ERROR_OK; +} + +int esp_xtensa_smp_resume(struct target *target, + int current, + target_addr_t address, + int handle_breakpoints, + int debug_execution) +{ + int res; + uint32_t smp_break; + + xtensa_smpbreak_get(target, &smp_break); + LOG_TARGET_DEBUG(target, "smp_break=0x%" PRIx32, smp_break); + + /* dummy resume for smp toggle in order to reduce gdb impact */ + if ((target->smp) && (target->gdb_service) && (target->gdb_service->core[1] != -1)) { + /* simulate a start and halt of target */ + target->gdb_service->target = NULL; + target->gdb_service->core[0] = target->gdb_service->core[1]; + /* fake resume at next poll we play the target core[1], see poll*/ + LOG_TARGET_DEBUG(target, "Fake resume"); + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + return ERROR_OK; + } + + /* xtensa_prepare_resume() can step over breakpoint/watchpoint and generate signals on BreakInOut circuit for + * other cores. So disconnect this core from BreakInOut circuit and do xtensa_prepare_resume(). */ + res = esp_xtensa_smp_smpbreak_disable(target, &smp_break); + if (res != ERROR_OK) + return res; + res = xtensa_prepare_resume(target, current, address, handle_breakpoints, debug_execution); + /* restore configured BreakInOut signals config */ + int ret = esp_xtensa_smp_smpbreak_restore(target, smp_break); + if (ret != ERROR_OK) + return ret; + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to prepare for resume!"); + return res; + } + + if (target->smp) { + if (target->gdb_service) + target->gdb_service->core[0] = -1; + res = esp_xtensa_smp_resume_cores(target, handle_breakpoints, debug_execution); + if (res != ERROR_OK) + return res; + } + + res = xtensa_do_resume(target); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to resume!"); + return res; + } + + target->debug_reason = DBG_REASON_NOTHALTED; + if (!debug_execution) + target->state = TARGET_RUNNING; + else + target->state = TARGET_DEBUG_RUNNING; + + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + return ERROR_OK; +} + +int esp_xtensa_smp_step(struct target *target, + int current, + target_addr_t address, + int handle_breakpoints) +{ + int res; + uint32_t smp_break = 0; + struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target); + + if (target->smp) { + res = esp_xtensa_smp_smpbreak_disable(target, &smp_break); + if (res != ERROR_OK) + return res; + } + res = xtensa_step(target, current, address, handle_breakpoints); + + if (res == ERROR_OK) { + if (esp_xtensa_smp->chip_ops->on_halt) + esp_xtensa_smp->chip_ops->on_halt(target); + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + + if (target->smp) { + int ret = esp_xtensa_smp_smpbreak_restore(target, smp_break); + if (ret != ERROR_OK) + return ret; + } + + return res; +} + +int esp_xtensa_smp_watchpoint_add(struct target *target, struct watchpoint *watchpoint) +{ + int res = xtensa_watchpoint_add(target, watchpoint); + if (res != ERROR_OK) + return res; + + if (!target->smp) + return ERROR_OK; + + struct target_list *head; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + if (curr == target || !target_was_examined(curr)) + continue; + /* Need to use high level API here because every target for core contains list of watchpoints. + * GDB works with active core only, so we need to duplicate every watchpoint on other cores, + * otherwise watchpoint_free() on active core can fail if WP has been initially added on another core. */ + curr->smp = 0; + res = watchpoint_add(curr, watchpoint->address, watchpoint->length, + watchpoint->rw, watchpoint->value, watchpoint->mask); + curr->smp = 1; + if (res != ERROR_OK) + return res; + } + return ERROR_OK; +} + +int esp_xtensa_smp_watchpoint_remove(struct target *target, struct watchpoint *watchpoint) +{ + int res = xtensa_watchpoint_remove(target, watchpoint); + if (res != ERROR_OK) + return res; + + if (!target->smp) + return ERROR_OK; + + struct target_list *head; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + if (curr == target) + continue; + /* see big comment in esp_xtensa_smp_watchpoint_add() */ + curr->smp = 0; + watchpoint_remove(curr, watchpoint->address); + curr->smp = 1; + } + return ERROR_OK; +} + +int esp_xtensa_smp_run_func_image(struct target *target, struct esp_algorithm_run_data *run, uint32_t num_args, ...) +{ + struct target *run_target = target; + struct target_list *head; + va_list ap; + uint32_t smp_break = 0; + int res; + + if (target->smp) { + /* find first HALTED and examined core */ + foreach_smp_target(head, target->smp_targets) { + run_target = head->target; + if (target_was_examined(run_target) && run_target->state == TARGET_HALTED) + break; + } + if (!head) { + LOG_ERROR("Failed to find HALTED core!"); + return ERROR_FAIL; + } + + res = esp_xtensa_smp_smpbreak_disable(run_target, &smp_break); + if (res != ERROR_OK) + return res; + } + + va_start(ap, num_args); + int algo_res = esp_algorithm_run_func_image_va(run_target, run, num_args, ap); + va_end(ap); + + if (target->smp) { + res = esp_xtensa_smp_smpbreak_restore(run_target, smp_break); + if (res != ERROR_OK) + return res; + } + return algo_res; +} + +int esp_xtensa_smp_run_onboard_func(struct target *target, + struct esp_algorithm_run_data *run, + uint32_t func_addr, + uint32_t num_args, + ...) +{ + struct target *run_target = target; + struct target_list *head; + va_list ap; + uint32_t smp_break = 0; + int res; + + if (target->smp) { + /* find first HALTED and examined core */ + foreach_smp_target(head, target->smp_targets) { + run_target = head->target; + if (target_was_examined(run_target) && run_target->state == TARGET_HALTED) + break; + } + if (!head) { + LOG_ERROR("Failed to find HALTED core!"); + return ERROR_FAIL; + } + res = esp_xtensa_smp_smpbreak_disable(run_target, &smp_break); + if (res != ERROR_OK) + return res; + } + + va_start(ap, num_args); + int algo_res = esp_algorithm_run_onboard_func_va(run_target, run, func_addr, num_args, ap); + va_end(ap); + + if (target->smp) { + res = esp_xtensa_smp_smpbreak_restore(run_target, smp_break); + if (res != ERROR_OK) + return res; + } + return algo_res; +} + +int esp_xtensa_smp_init_arch_info(struct target *target, + struct esp_xtensa_smp_common *esp_xtensa_smp, + struct xtensa_debug_module_config *dm_cfg, + const struct esp_xtensa_smp_chip_ops *chip_ops, + const struct esp_semihost_ops *semihost_ops) +{ + int ret = esp_xtensa_init_arch_info(target, &esp_xtensa_smp->esp_xtensa, dm_cfg, semihost_ops); + if (ret != ERROR_OK) + return ret; + esp_xtensa_smp->chip_ops = chip_ops; + esp_xtensa_smp->examine_other_cores = ESP_XTENSA_SMP_EXAMINE_OTHER_CORES; + return ERROR_OK; +} + +int esp_xtensa_smp_target_init(struct command_context *cmd_ctx, struct target *target) +{ + int ret = esp_xtensa_target_init(cmd_ctx, target); + if (ret != ERROR_OK) + return ret; + + if (target->smp) { + struct target_list *head; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + ret = esp_xtensa_semihosting_init(curr); + if (ret != ERROR_OK) + return ret; + } + } else { + ret = esp_xtensa_semihosting_init(target); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; +} + +COMMAND_HANDLER(esp_xtensa_smp_cmd_xtdef) +{ + struct target *target = get_current_target(CMD_CTX); + if (target->smp && CMD_ARGC > 0) { + struct target_list *head; + struct target *curr; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do, + target_to_xtensa(curr)); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do, + target_to_xtensa(target)); +} + +COMMAND_HANDLER(esp_xtensa_smp_cmd_xtopt) +{ + struct target *target = get_current_target(CMD_CTX); + if (target->smp && CMD_ARGC > 0) { + struct target_list *head; + struct target *curr; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do, + target_to_xtensa(curr)); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do, + target_to_xtensa(target)); +} + +COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmem) +{ + struct target *target = get_current_target(CMD_CTX); + if (target->smp && CMD_ARGC > 0) { + struct target_list *head; + struct target *curr; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do, + target_to_xtensa(curr)); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do, + target_to_xtensa(target)); +} + +COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmpu) +{ + struct target *target = get_current_target(CMD_CTX); + if (target->smp && CMD_ARGC > 0) { + struct target_list *head; + struct target *curr; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do, + target_to_xtensa(curr)); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do, + target_to_xtensa(target)); +} + +COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmmu) +{ + struct target *target = get_current_target(CMD_CTX); + if (target->smp && CMD_ARGC > 0) { + struct target_list *head; + struct target *curr; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do, + target_to_xtensa(curr)); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do, + target_to_xtensa(target)); +} + +COMMAND_HANDLER(esp_xtensa_smp_cmd_xtreg) +{ + struct target *target = get_current_target(CMD_CTX); + if (target->smp && CMD_ARGC > 0) { + struct target_list *head; + struct target *curr; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do, + target_to_xtensa(curr)); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do, + target_to_xtensa(target)); +} + +COMMAND_HANDLER(esp_xtensa_smp_cmd_xtregfmt) +{ + struct target *target = get_current_target(CMD_CTX); + if (target->smp && CMD_ARGC > 0) { + struct target_list *head; + struct target *curr; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do, + target_to_xtensa(curr)); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do, + target_to_xtensa(target)); +} + +COMMAND_HANDLER(esp_xtensa_smp_cmd_permissive_mode) +{ + struct target *target = get_current_target(CMD_CTX); + if (target->smp && CMD_ARGC > 0) { + struct target_list *head; + struct target *curr; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + int ret = CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do, + target_to_xtensa(curr)); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do, + target_to_xtensa(target)); +} + +COMMAND_HANDLER(esp_xtensa_smp_cmd_smpbreak) +{ + struct target *target = get_current_target(CMD_CTX); + if (target->smp && CMD_ARGC > 0) { + struct target_list *head; + struct target *curr; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + int ret = CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, curr); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, target); +} + +COMMAND_HANDLER(esp_xtensa_smp_cmd_mask_interrupts) +{ + struct target *target = get_current_target(CMD_CTX); + if (target->smp && CMD_ARGC > 0) { + struct target_list *head; + struct target *curr; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + int ret = CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do, + target_to_xtensa(curr)); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do, + target_to_xtensa(target)); +} + +COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_enable) +{ + struct target *target = get_current_target(CMD_CTX); + if (target->smp && CMD_ARGC > 0) { + struct target_list *head; + struct target *curr; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + int ret = CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do, + target_to_xtensa(curr)); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do, + target_to_xtensa(target)); +} + +COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_dump) +{ + struct target *target = get_current_target(CMD_CTX); + if (target->smp) { + struct target_list *head; + struct target *curr; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + LOG_TARGET_INFO(curr, ":"); + int ret = CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do, + target_to_xtensa(curr)); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do, + target_to_xtensa(target)); +} + +COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestart) +{ + struct target *target = get_current_target(CMD_CTX); + if (target->smp) { + struct target_list *head; + struct target *curr; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do, + target_to_xtensa(curr)); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do, + target_to_xtensa(target)); +} + +COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestop) +{ + struct target *target = get_current_target(CMD_CTX); + if (target->smp) { + struct target_list *head; + struct target *curr; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do, + target_to_xtensa(curr)); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do, + target_to_xtensa(target)); +} + +COMMAND_HANDLER(esp_xtensa_smp_cmd_tracedump) +{ + struct target *target = get_current_target(CMD_CTX); + if (target->smp) { + struct target_list *head; + struct target *curr; + int32_t cores_max_id = 0; + /* assume that core IDs are assigned to SMP targets sequentially: 0,1,2... */ + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + if (cores_max_id < curr->coreid) + cores_max_id = curr->coreid; + } + if (CMD_ARGC < ((uint32_t)cores_max_id + 1)) { + command_print(CMD, + "Need %d filenames to dump to as output!", + cores_max_id + 1); + return ERROR_FAIL; + } + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do, + target_to_xtensa(curr), CMD_ARGV[curr->coreid]); + if (ret != ERROR_OK) + return ret; + } + return ERROR_OK; + } + return CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do, + target_to_xtensa(target), CMD_ARGV[0]); +} + +const struct command_registration esp_xtensa_smp_xtensa_command_handlers[] = { + { + .name = "xtdef", + .handler = esp_xtensa_smp_cmd_xtdef, + .mode = COMMAND_CONFIG, + .help = "Configure Xtensa core type", + .usage = "<type>", + }, + { + .name = "xtopt", + .handler = esp_xtensa_smp_cmd_xtopt, + .mode = COMMAND_CONFIG, + .help = "Configure Xtensa core option", + .usage = "<name> <value>", + }, + { + .name = "xtmem", + .handler = esp_xtensa_smp_cmd_xtmem, + .mode = COMMAND_CONFIG, + .help = "Configure Xtensa memory/cache option", + .usage = "<type> [parameters]", + }, + { + .name = "xtmmu", + .handler = esp_xtensa_smp_cmd_xtmmu, + .mode = COMMAND_CONFIG, + .help = "Configure Xtensa MMU option", + .usage = "<NIREFILLENTRIES> <NDREFILLENTRIES> <IVARWAY56> <DVARWAY56>", + }, + { + .name = "xtmpu", + .handler = esp_xtensa_smp_cmd_xtmpu, + .mode = COMMAND_CONFIG, + .help = "Configure Xtensa MPU option", + .usage = "<num FG seg> <min seg size> <lockable> <executeonly>", + }, + { + .name = "xtreg", + .handler = esp_xtensa_smp_cmd_xtreg, + .mode = COMMAND_CONFIG, + .help = "Configure Xtensa register", + .usage = "<regname> <regnum>", + }, + { + .name = "xtregs", + .handler = esp_xtensa_smp_cmd_xtreg, + .mode = COMMAND_CONFIG, + .help = "Configure number of Xtensa registers", + .usage = "<numregs>", + }, + { + .name = "xtregfmt", + .handler = esp_xtensa_smp_cmd_xtregfmt, + .mode = COMMAND_CONFIG, + .help = "Configure format of Xtensa register map", + .usage = "<numgregs>", + }, + { + .name = "set_permissive", + .handler = esp_xtensa_smp_cmd_permissive_mode, + .mode = COMMAND_ANY, + .help = "When set to 1, enable Xtensa permissive mode (less client-side checks)", + .usage = "[0|1]", + }, + { + .name = "maskisr", + .handler = esp_xtensa_smp_cmd_mask_interrupts, + .mode = COMMAND_ANY, + .help = "mask Xtensa interrupts at step", + .usage = "['on'|'off']", + }, + { + .name = "smpbreak", + .handler = esp_xtensa_smp_cmd_smpbreak, + .mode = COMMAND_ANY, + .help = "Set the way the CPU chains OCD breaks", + .usage = + "[none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]", + }, + { + .name = "perfmon_enable", + .handler = esp_xtensa_smp_cmd_perfmon_enable, + .mode = COMMAND_EXEC, + .help = "Enable and start performance counter", + .usage = "<counter_id> <select> [mask] [kernelcnt] [tracelevel]", + }, + { + .name = "perfmon_dump", + .handler = esp_xtensa_smp_cmd_perfmon_dump, + .mode = COMMAND_EXEC, + .help = + "Dump performance counter value. If no argument specified, dumps all counters.", + .usage = "[counter_id]", + }, + { + .name = "tracestart", + .handler = esp_xtensa_smp_cmd_tracestart, + .mode = COMMAND_EXEC, + .help = + "Tracing: Set up and start a trace. Optionally set stop trigger address and amount of data captured after.", + .usage = "[pc <pcval>/[maskbitcount]] [after <n> [ins|words]]", + }, + { + .name = "tracestop", + .handler = esp_xtensa_smp_cmd_tracestop, + .mode = COMMAND_EXEC, + .help = "Tracing: Stop current trace as started by the tracestart command", + .usage = "", + }, + { + .name = "tracedump", + .handler = esp_xtensa_smp_cmd_tracedump, + .mode = COMMAND_EXEC, + .help = "Tracing: Dump trace memory to a files. One file per core.", + .usage = "<outfile1> <outfile2>", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration esp_xtensa_smp_command_handlers[] = { + { + .name = "xtensa", + .usage = "", + .chain = esp_xtensa_smp_xtensa_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; diff --git a/src/target/espressif/esp_xtensa_smp.h b/src/target/espressif/esp_xtensa_smp.h new file mode 100644 index 0000000000..39afd8af10 --- /dev/null +++ b/src/target/espressif/esp_xtensa_smp.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * ESP Xtensa SMP target for OpenOCD * + * Copyright (C) 2020 Espressif Systems Ltd. Co * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_XTENSA_ESP_SMP_H +#define OPENOCD_TARGET_XTENSA_ESP_SMP_H + +#include "esp_xtensa.h" +#include "esp_algorithm.h" + +struct esp_xtensa_smp_chip_ops { + int (*poll)(struct target *target); + int (*reset)(struct target *target); + int (*on_halt)(struct target *target); +}; + +struct esp_xtensa_smp_common { + struct esp_xtensa_common esp_xtensa; + const struct esp_xtensa_smp_chip_ops *chip_ops; + bool other_core_does_resume; + /* number of attempts to examine other SMP cores, attempts are made after reset on target poll */ + int examine_other_cores; +}; + +int esp_xtensa_smp_poll(struct target *target); +int esp_xtensa_smp_resume(struct target *target, + int current, + target_addr_t address, + int handle_breakpoints, + int debug_execution); +int esp_xtensa_smp_step(struct target *target, + int current, + target_addr_t address, + int handle_breakpoints); +int esp_xtensa_smp_assert_reset(struct target *target); +int esp_xtensa_smp_deassert_reset(struct target *target); +int esp_xtensa_smp_soft_reset_halt(struct target *target); +int esp_xtensa_smp_on_halt(struct target *target); +int esp_xtensa_smp_watchpoint_add(struct target *target, struct watchpoint *watchpoint); +int esp_xtensa_smp_watchpoint_remove(struct target *target, struct watchpoint *watchpoint); +int esp_xtensa_smp_handle_target_event(struct target *target, enum target_event event, void *priv); +int esp_xtensa_smp_target_init(struct command_context *cmd_ctx, struct target *target); +int esp_xtensa_smp_init_arch_info(struct target *target, + struct esp_xtensa_smp_common *esp_xtensa_smp, + struct xtensa_debug_module_config *dm_cfg, + const struct esp_xtensa_smp_chip_ops *chip_ops, + const struct esp_semihost_ops *semihost_ops); +int esp_xtensa_smp_run_func_image(struct target *target, struct esp_algorithm_run_data *run, uint32_t num_args, ...); +int esp_xtensa_smp_run_onboard_func(struct target *target, + struct esp_algorithm_run_data *run, + uint32_t func_addr, + uint32_t num_args, + ...); +extern const struct command_registration esp_xtensa_smp_command_handlers[]; +extern const struct command_registration esp_xtensa_smp_xtensa_command_handlers[]; +extern const struct command_registration esp_xtensa_smp_esp_command_handlers[]; + +#endif /* OPENOCD_TARGET_XTENSA_ESP_SMP_H */ diff --git a/src/target/espressif/segger_sysview.h b/src/target/espressif/segger_sysview.h new file mode 100644 index 0000000000..d149cab665 --- /dev/null +++ b/src/target/espressif/segger_sysview.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: BSD-1-Clause */ +/* SPDX-FileCopyrightText: (c) 1995-2021 SEGGER Microcontroller GmbH. All rights reserved. */ +/* SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD */ + +/* +* The contend below is extracted from files SEGGER_SYSVIEW.h and SEGGER_SYSVIEW_Int.h in: +* https://www.segger.com/downloads/systemview/systemview_target_src +* SystemView version: 3.42 +*/ + +#ifndef OPENOCD_TARGET_SEGGER_SYSVIEW_H +#define OPENOCD_TARGET_SEGGER_SYSVIEW_H + +#define SYSVIEW_EVTID_NOP 0 /* Dummy packet. */ +#define SYSVIEW_EVTID_OVERFLOW 1 +#define SYSVIEW_EVTID_ISR_ENTER 2 +#define SYSVIEW_EVTID_ISR_EXIT 3 +#define SYSVIEW_EVTID_TASK_START_EXEC 4 +#define SYSVIEW_EVTID_TASK_STOP_EXEC 5 +#define SYSVIEW_EVTID_TASK_START_READY 6 +#define SYSVIEW_EVTID_TASK_STOP_READY 7 +#define SYSVIEW_EVTID_TASK_CREATE 8 +#define SYSVIEW_EVTID_TASK_INFO 9 +#define SYSVIEW_EVTID_TRACE_START 10 +#define SYSVIEW_EVTID_TRACE_STOP 11 +#define SYSVIEW_EVTID_SYSTIME_CYCLES 12 +#define SYSVIEW_EVTID_SYSTIME_US 13 +#define SYSVIEW_EVTID_SYSDESC 14 +#define SYSVIEW_EVTID_USER_START 15 +#define SYSVIEW_EVTID_USER_STOP 16 +#define SYSVIEW_EVTID_IDLE 17 +#define SYSVIEW_EVTID_ISR_TO_SCHEDULER 18 +#define SYSVIEW_EVTID_TIMER_ENTER 19 +#define SYSVIEW_EVTID_TIMER_EXIT 20 +#define SYSVIEW_EVTID_STACK_INFO 21 +#define SYSVIEW_EVTID_MODULEDESC 22 + +#define SYSVIEW_EVTID_INIT 24 +#define SYSVIEW_EVTID_NAME_RESOURCE 25 +#define SYSVIEW_EVTID_PRINT_FORMATTED 26 +#define SYSVIEW_EVTID_NUMMODULES 27 +#define SYSVIEW_EVTID_END_CALL 28 +#define SYSVIEW_EVTID_TASK_TERMINATE 29 + +#define SYSVIEW_EVTID_EX 31 +// +// SystemView extended events. Sent with ID 31. +// +#define SYSVIEW_EVTID_EX_MARK 0 +#define SYSVIEW_EVTID_EX_NAME_MARKER 1 +#define SYSVIEW_EVTID_EX_HEAP_DEFINE 2 +#define SYSVIEW_EVTID_EX_HEAP_ALLOC 3 +#define SYSVIEW_EVTID_EX_HEAP_ALLOC_EX 4 +#define SYSVIEW_EVTID_EX_HEAP_FREE 5 + +#define SYSVIEW_SYNC_LEN 10 + +#define SYSVIEW_EVENT_ID_MAX (200) + +// +// Commands that Host can send to target +// +enum { + SEGGER_SYSVIEW_COMMAND_ID_START = 1, + SEGGER_SYSVIEW_COMMAND_ID_STOP, + SEGGER_SYSVIEW_COMMAND_ID_GET_SYSTIME, + SEGGER_SYSVIEW_COMMAND_ID_GET_TASKLIST, + SEGGER_SYSVIEW_COMMAND_ID_GET_SYSDESC, + SEGGER_SYSVIEW_COMMAND_ID_GET_NUMMODULES, + SEGGER_SYSVIEW_COMMAND_ID_GET_MODULEDESC, + SEGGER_SYSVIEW_COMMAND_ID_HEARTBEAT = 127, + // Extended commands: Commands >= 128 have a second parameter + SEGGER_SYSVIEW_COMMAND_ID_GET_MODULE = 128 +}; + +/* Minimum compatible SEGGER SystemView tool version */ +#define SYSVIEW_MIN_VER_STRING "SEGGER SystemViewer V2.42" + +#endif diff --git a/src/target/etb.c b/src/target/etb.c index ce1bef968e..3b9004bb85 100644 --- a/src/target/etb.c +++ b/src/target/etb.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/etb.h b/src/target/etb.h index 680c8a1ab8..fa75600ad6 100644 --- a/src/target/etb.h +++ b/src/target/etb.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ETB_H diff --git a/src/target/etm.c b/src/target/etm.c index 119c0df5d8..d083017f71 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" @@ -563,8 +552,8 @@ static int etm_set_reg(struct reg *reg, uint32_t value) } buf_set_u32(reg->value, 0, reg->size, value); - reg->valid = 1; - reg->dirty = 0; + reg->valid = true; + reg->dirty = false; return ERROR_OK; } @@ -1717,7 +1706,7 @@ COMMAND_HANDLER(handle_etm_dump_command) return ERROR_FAIL; } - if (etm_ctx->capture_driver->status == TRACE_IDLE) { + if (etm_ctx->capture_driver->status(etm_ctx) == TRACE_IDLE) { command_print(CMD, "trace capture wasn't enabled, no trace data captured"); return ERROR_OK; } diff --git a/src/target/etm.h b/src/target/etm.h index debe197439..be5f2c7d07 100644 --- a/src/target/etm.h +++ b/src/target/etm.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007 by Vincent Palatin * * vincent.palatin_openocd@m4x.org * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ETM_H diff --git a/src/target/etm_dummy.c b/src/target/etm_dummy.c index ba53c7a828..8deccf5f9d 100644 --- a/src/target/etm_dummy.c +++ b/src/target/etm_dummy.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/etm_dummy.h b/src/target/etm_dummy.h index 5a1955f37e..8df20000cb 100644 --- a/src/target/etm_dummy.h +++ b/src/target/etm_dummy.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_ETM_DUMMY_H diff --git a/src/target/fa526.c b/src/target/fa526.c index aa9e450430..38b7ab2e9d 100644 --- a/src/target/fa526.c +++ b/src/target/fa526.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 by Paulius Zaleckas * * paulius.zaleckas@gmail.com * - * * - * 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/>. * ***************************************************************************/ /* diff --git a/src/target/feroceon.c b/src/target/feroceon.c index bbb793aaa7..1e7eb0961f 100644 --- a/src/target/feroceon.c +++ b/src/target/feroceon.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2008-2009 by Marvell Semiconductors, Inc. * * Written by Nicolas Pitre <nico@marvell.com> * * * * Copyright (C) 2008 by Hongtao Zheng * * hontor@126.com * - * * - * 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/>. * ***************************************************************************/ /* diff --git a/src/target/hla_target.c b/src/target/hla_target.c index 3e359b950e..c1bda996ce 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester <kesmtp@freenet.de> * @@ -6,19 +8,6 @@ * spen@spen-soft.co.uk * * * * revised: 4/25/13 by brent@mbari.org [DCC target request 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -203,7 +192,7 @@ static int adapter_target_create(struct target *target, { LOG_DEBUG("%s", __func__); struct adiv5_private_config *pc = target->private_config; - if (pc && pc->ap_num > 0) { + if (pc && pc->ap_num != DP_APSEL_INVALID && pc->ap_num != 0) { LOG_ERROR("hla_target: invalid parameter -ap-num (> 0)"); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -242,7 +231,7 @@ static int adapter_debug_entry(struct target *target) struct armv7m_common *armv7m = target_to_armv7m(target); struct arm *arm = &armv7m->arm; struct reg *r; - uint32_t xPSR; + uint32_t xpsr; int retval; /* preserve the DCRDR across halts */ @@ -260,11 +249,11 @@ static int adapter_debug_entry(struct target *target) adapter->layout->api->write_debug_reg(adapter->handle, DCB_DEMCR, TRCENA); r = arm->cpsr; - xPSR = buf_get_u32(r->value, 0, 32); + xpsr = buf_get_u32(r->value, 0, 32); /* Are we in an exception handler */ - if (xPSR & 0x1FF) { - armv7m->exception_number = (xPSR & 0x1FF); + if (xpsr & 0x1FF) { + armv7m->exception_number = (xpsr & 0x1FF); arm->core_mode = ARM_MODE_HANDLER; arm->map = armv7m_msp_reg_map; @@ -358,6 +347,13 @@ static int hl_assert_reset(struct target *target) adapter->layout->api->write_debug_reg(adapter->handle, DCB_DHCSR, DBGKEY|C_DEBUGEN); + if (!target_was_examined(target) && !target->defer_examine + && srst_asserted && res == ERROR_OK) { + /* If the target is not examined, now under reset it is good time to retry examination */ + LOG_TARGET_DEBUG(target, "Trying to re-examine under reset"); + target_examine_one(target); + } + /* only set vector catch if halt is requested */ if (target->reset_halt) adapter->layout->api->write_debug_reg(adapter->handle, DCB_DEMCR, TRCENA|VC_CORERESET); @@ -453,7 +449,7 @@ static int adapter_resume(struct target *target, int current, address, handle_breakpoints, debug_execution); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -542,7 +538,7 @@ static int adapter_step(struct target *target, int current, LOG_DEBUG("%s", __func__); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/image.c b/src/target/image.c index 130ea6c1f9..9175c200af 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -13,19 +15,6 @@ * * * Copyright (C) 2018 by Advantest * * florian.meister@advantest.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -61,12 +50,15 @@ static int autodetect_image_type(struct image *image, const char *url) if (retval != ERROR_OK) return retval; retval = fileio_read(fileio, 9, buffer, &read_bytes); + fileio_close(fileio); - if (retval == ERROR_OK) { - if (read_bytes != 9) - retval = ERROR_FILEIO_OPERATION_FAILED; + /* If the file is smaller than 9 bytes, it can only be bin */ + if (retval == ERROR_OK && read_bytes != 9) { + LOG_DEBUG("Less than 9 bytes in the image file found."); + LOG_DEBUG("BIN image detected."); + image->type = IMAGE_BINARY; + return ERROR_OK; } - fileio_close(fileio); if (retval != ERROR_OK) return retval; @@ -93,8 +85,10 @@ static int autodetect_image_type(struct image *image, const char *url) && (buffer[1] >= '0') && (buffer[1] < '9')) { LOG_DEBUG("S19 image detected."); image->type = IMAGE_SRECORD; - } else + } else { + LOG_DEBUG("BIN image detected."); image->type = IMAGE_BINARY; + } return ERROR_OK; } @@ -102,20 +96,22 @@ static int autodetect_image_type(struct image *image, const char *url) static int identify_image_type(struct image *image, const char *type_string, const char *url) { if (type_string) { - if (!strcmp(type_string, "bin")) + if (!strcmp(type_string, "bin")) { image->type = IMAGE_BINARY; - else if (!strcmp(type_string, "ihex")) + } else if (!strcmp(type_string, "ihex")) { image->type = IMAGE_IHEX; - else if (!strcmp(type_string, "elf")) + } else if (!strcmp(type_string, "elf")) { image->type = IMAGE_ELF; - else if (!strcmp(type_string, "mem")) + } else if (!strcmp(type_string, "mem")) { image->type = IMAGE_MEMORY; - else if (!strcmp(type_string, "s19")) + } else if (!strcmp(type_string, "s19")) { image->type = IMAGE_SRECORD; - else if (!strcmp(type_string, "build")) + } else if (!strcmp(type_string, "build")) { image->type = IMAGE_BUILDER; - else + } else { + LOG_ERROR("Unknown image type: %s, use one of: bin, ihex, elf, mem, s19, build", type_string); return ERROR_IMAGE_TYPE_UNKNOWN; + } } else return autodetect_image_type(image, url); @@ -972,12 +968,13 @@ int image_open(struct image *image, const char *url, const char *type_string) retval = fileio_open(&image_binary->fileio, url, FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) - return retval; + goto free_mem_on_error; + size_t filesize; retval = fileio_size(image_binary->fileio, &filesize); if (retval != ERROR_OK) { fileio_close(image_binary->fileio); - return retval; + goto free_mem_on_error; } image->num_sections = 1; @@ -992,14 +989,14 @@ int image_open(struct image *image, const char *url, const char *type_string) retval = fileio_open(&image_ihex->fileio, url, FILEIO_READ, FILEIO_TEXT); if (retval != ERROR_OK) - return retval; + goto free_mem_on_error; retval = image_ihex_buffer_complete(image); if (retval != ERROR_OK) { LOG_ERROR( "failed buffering IHEX image, check server output for additional information"); fileio_close(image_ihex->fileio); - return retval; + goto free_mem_on_error; } } else if (image->type == IMAGE_ELF) { struct image_elf *image_elf; @@ -1008,12 +1005,12 @@ int image_open(struct image *image, const char *url, const char *type_string) retval = fileio_open(&image_elf->fileio, url, FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) - return retval; + goto free_mem_on_error; retval = image_elf_read_headers(image); if (retval != ERROR_OK) { fileio_close(image_elf->fileio); - return retval; + goto free_mem_on_error; } } else if (image->type == IMAGE_MEMORY) { struct target *target = get_target(url); @@ -1043,14 +1040,14 @@ int image_open(struct image *image, const char *url, const char *type_string) retval = fileio_open(&image_mot->fileio, url, FILEIO_READ, FILEIO_TEXT); if (retval != ERROR_OK) - return retval; + goto free_mem_on_error; retval = image_mot_buffer_complete(image); if (retval != ERROR_OK) { LOG_ERROR( "failed buffering S19 image, check server output for additional information"); fileio_close(image_mot->fileio); - return retval; + goto free_mem_on_error; } } else if (image->type == IMAGE_BUILDER) { image->num_sections = 0; @@ -1071,6 +1068,11 @@ int image_open(struct image *image, const char *url, const char *type_string) } return retval; + +free_mem_on_error: + free(image->type_private); + image->type_private = NULL; + return retval; }; int image_read_section(struct image *image, diff --git a/src/target/image.h b/src/target/image.h index bf06064ac9..03bc068d62 100644 --- a/src/target/image.h +++ b/src/target/image.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -10,19 +12,6 @@ * * * Copyright (C) 2018 by Advantest * * florian.meister@advantest.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_IMAGE_H diff --git a/src/target/lakemont.c b/src/target/lakemont.c index 230f53fe03..6c0964bfaa 100644 --- a/src/target/lakemont.c +++ b/src/target/lakemont.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright(c) 2013-2016 Intel Corporation. * @@ -8,19 +10,6 @@ * Jeffrey Maxwell (jeffrey.r.maxwell@intel.com) * Jessica Gomez (jessica.gomez.hernandez@intel.com) * - * 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/>. - * * Contact Information: * Intel Corporation */ @@ -84,26 +73,26 @@ static const struct { const char *feature; } regs[] = { /* general purpose registers */ - { EAX, "eax", 0x000000D01D660000, 0, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { ECX, "ecx", 0x000000501D660000, 1, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { EDX, "edx", 0x000000901D660000, 2, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { EBX, "ebx", 0x000000101D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { ESP, "esp", 0x000000E01D660000, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" }, - { EBP, "ebp", 0x000000601D660000, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" }, - { ESI, "esi", 0x000000A01D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { EDI, "edi", 0x000000201D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { EAX, "eax", 0x000000D01D660000ULL, 0, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { ECX, "ecx", 0x000000501D660000ULL, 1, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { EDX, "edx", 0x000000901D660000ULL, 2, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { EBX, "ebx", 0x000000101D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { ESP, "esp", 0x000000E01D660000ULL, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" }, + { EBP, "ebp", 0x000000601D660000ULL, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" }, + { ESI, "esi", 0x000000A01D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { EDI, "edi", 0x000000201D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, /* instruction pointer & flags */ - { EIP, "eip", 0x000000C01D660000, 3, 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.i386.core" }, - { EFLAGS, "eflags", 0x000000401D660000, 4, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { EIP, "eip", 0x000000C01D660000ULL, 3, 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.i386.core" }, + { EFLAGS, "eflags", 0x000000401D660000ULL, 4, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, /* segment registers */ - { CS, "cs", 0x000000281D660000, 5, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { SS, "ss", 0x000000C81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { DS, "ds", 0x000000481D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { ES, "es", 0x000000A81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { FS, "fs", 0x000000881D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { GS, "gs", 0x000000081D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { CS, "cs", 0x000000281D660000ULL, 5, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { SS, "ss", 0x000000C81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { DS, "ds", 0x000000481D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { ES, "es", 0x000000A81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { FS, "fs", 0x000000881D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { GS, "gs", 0x000000081D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, /* floating point unit registers - not accessible via JTAG - here to satisfy GDB */ { ST0, "st0", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, @@ -124,56 +113,56 @@ static const struct { { FOP, "fop", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, /* control registers */ - { CR0, "cr0", 0x000000001D660000, 6, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { CR2, "cr2", 0x000000BC1D660000, 7, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { CR3, "cr3", 0x000000801D660000, 8, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { CR4, "cr4", 0x0000002C1D660000, 9, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { CR0, "cr0", 0x000000001D660000ULL, 6, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { CR2, "cr2", 0x000000BC1D660000ULL, 7, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { CR3, "cr3", 0x000000801D660000ULL, 8, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { CR4, "cr4", 0x0000002C1D660000ULL, 9, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, /* debug registers */ - { DR0, "dr0", 0x0000007C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DR1, "dr1", 0x000000FC1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DR2, "dr2", 0x000000021D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DR3, "dr3", 0x000000821D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DR6, "dr6", 0x000000301D660000, 10, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DR7, "dr7", 0x000000B01D660000, 11, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DR0, "dr0", 0x0000007C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DR1, "dr1", 0x000000FC1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DR2, "dr2", 0x000000021D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DR3, "dr3", 0x000000821D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DR6, "dr6", 0x000000301D660000ULL, 10, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DR7, "dr7", 0x000000B01D660000ULL, 11, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, /* descriptor tables */ - { IDTB, "idtbase", 0x000000581D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { IDTL, "idtlimit", 0x000000D81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { IDTAR, "idtar", 0x000000981D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { GDTB, "gdtbase", 0x000000B81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { GDTL, "gdtlimit", 0x000000781D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { GDTAR, "gdtar", 0x000000381D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { TR, "tr", 0x000000701D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { LDTR, "ldtr", 0x000000F01D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { LDTB, "ldbase", 0x000000041D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { LDTL, "ldlimit", 0x000000841D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { LDTAR, "ldtar", 0x000000F81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { IDTB, "idtbase", 0x000000581D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { IDTL, "idtlimit", 0x000000D81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { IDTAR, "idtar", 0x000000981D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { GDTB, "gdtbase", 0x000000B81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { GDTL, "gdtlimit", 0x000000781D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { GDTAR, "gdtar", 0x000000381D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { TR, "tr", 0x000000701D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { LDTR, "ldtr", 0x000000F01D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { LDTB, "ldbase", 0x000000041D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { LDTL, "ldlimit", 0x000000841D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { LDTAR, "ldtar", 0x000000F81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, /* segment registers */ - { CSB, "csbase", 0x000000F41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { CSL, "cslimit", 0x0000000C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { CSAR, "csar", 0x000000741D660000, 12, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DSB, "dsbase", 0x000000941D660000, 13, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DSL, "dslimit", 0x000000541D660000, 14, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DSAR, "dsar", 0x000000141D660000, 15, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { ESB, "esbase", 0x0000004C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { ESL, "eslimit", 0x000000CC1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { ESAR, "esar", 0x0000008C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { FSB, "fsbase", 0x000000641D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { FSL, "fslimit", 0x000000E41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { FSAR, "fsar", 0x000000A41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { GSB, "gsbase", 0x000000C41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { GSL, "gslimit", 0x000000241D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { GSAR, "gsar", 0x000000441D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { SSB, "ssbase", 0x000000341D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { SSL, "sslimit", 0x000000B41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { SSAR, "ssar", 0x000000D41D660000, 16, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { TSSB, "tssbase", 0x000000E81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { TSSL, "tsslimit", 0x000000181D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { TSSAR, "tssar", 0x000000681D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { CSB, "csbase", 0x000000F41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { CSL, "cslimit", 0x0000000C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { CSAR, "csar", 0x000000741D660000ULL, 12, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DSB, "dsbase", 0x000000941D660000ULL, 13, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DSL, "dslimit", 0x000000541D660000ULL, 14, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DSAR, "dsar", 0x000000141D660000ULL, 15, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { ESB, "esbase", 0x0000004C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { ESL, "eslimit", 0x000000CC1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { ESAR, "esar", 0x0000008C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { FSB, "fsbase", 0x000000641D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { FSL, "fslimit", 0x000000E41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { FSAR, "fsar", 0x000000A41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { GSB, "gsbase", 0x000000C41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { GSL, "gslimit", 0x000000241D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { GSAR, "gsar", 0x000000441D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { SSB, "ssbase", 0x000000341D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { SSL, "sslimit", 0x000000B41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { SSAR, "ssar", 0x000000D41D660000ULL, 16, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { TSSB, "tssbase", 0x000000E81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { TSSL, "tsslimit", 0x000000181D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { TSSAR, "tssar", 0x000000681D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, /* probemode control register */ - { PMCR, "pmcr", 0x000000421D660000, 17, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { PMCR, "pmcr", 0x000000421D660000ULL, 17, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, }; static const struct { @@ -182,36 +171,36 @@ static const struct { uint64_t op; } instructions[] = { /* memory read/write */ - { MEMRDB32, "MEMRDB32", 0x0909090909090851 }, - { MEMRDB16, "MEMRDB16", 0x09090909090851E6 }, - { MEMRDH32, "MEMRDH32", 0x090909090908D166 }, - { MEMRDH16, "MEMRDH16", 0x090909090908D1E6 }, - { MEMRDW32, "MEMRDW32", 0x09090909090908D1 }, - { MEMRDW16, "MEMRDW16", 0x0909090908D1E666 }, - { MEMWRB32, "MEMWRB32", 0x0909090909090811 }, - { MEMWRB16, "MEMWRB16", 0x09090909090811E6 }, - { MEMWRH32, "MEMWRH32", 0x0909090909089166 }, - { MEMWRH16, "MEMWRH16", 0x09090909090891E6 }, - { MEMWRW32, "MEMWRW32", 0x0909090909090891 }, - { MEMWRW16, "MEMWRW16", 0x090909090891E666 }, + { MEMRDB32, "MEMRDB32", 0x0909090909090851ULL }, + { MEMRDB16, "MEMRDB16", 0x09090909090851E6ULL }, + { MEMRDH32, "MEMRDH32", 0x090909090908D166ULL }, + { MEMRDH16, "MEMRDH16", 0x090909090908D1E6ULL }, + { MEMRDW32, "MEMRDW32", 0x09090909090908D1ULL }, + { MEMRDW16, "MEMRDW16", 0x0909090908D1E666ULL }, + { MEMWRB32, "MEMWRB32", 0x0909090909090811ULL }, + { MEMWRB16, "MEMWRB16", 0x09090909090811E6ULL }, + { MEMWRH32, "MEMWRH32", 0x0909090909089166ULL }, + { MEMWRH16, "MEMWRH16", 0x09090909090891E6ULL }, + { MEMWRW32, "MEMWRW32", 0x0909090909090891ULL }, + { MEMWRW16, "MEMWRW16", 0x090909090891E666ULL }, /* IO read/write */ - { IORDB32, "IORDB32", 0x0909090909090937 }, - { IORDB16, "IORDB16", 0x09090909090937E6 }, - { IORDH32, "IORDH32", 0x090909090909B766 }, - { IORDH16, "IORDH16", 0x090909090909B7E6 }, - { IORDW32, "IORDW32", 0x09090909090909B7 }, - { IORDW16, "IORDW16", 0x0909090909B7E666 }, - { IOWRB32, "IOWRB32", 0x0909090909090977 }, - { IOWRB16, "IOWRB16", 0x09090909090977E6 }, - { IOWRH32, "IOWRH32", 0x090909090909F766 }, - { IOWRH16, "IOWRH16", 0x090909090909F7E6 }, - { IOWRW32, "IOWRW32", 0x09090909090909F7 }, - { IOWRW16, "IOWRW16", 0x0909090909F7E666 }, + { IORDB32, "IORDB32", 0x0909090909090937ULL }, + { IORDB16, "IORDB16", 0x09090909090937E6ULL }, + { IORDH32, "IORDH32", 0x090909090909B766ULL }, + { IORDH16, "IORDH16", 0x090909090909B7E6ULL }, + { IORDW32, "IORDW32", 0x09090909090909B7ULL }, + { IORDW16, "IORDW16", 0x0909090909B7E666ULL }, + { IOWRB32, "IOWRB32", 0x0909090909090977ULL }, + { IOWRB16, "IOWRB16", 0x09090909090977E6ULL }, + { IOWRH32, "IOWRH32", 0x090909090909F766ULL }, + { IOWRH16, "IOWRH16", 0x090909090909F7E6ULL }, + { IOWRW32, "IOWRW32", 0x09090909090909F7ULL }, + { IOWRW16, "IOWRW16", 0x0909090909F7E666ULL }, /* lakemont1 core shadow ram access opcodes */ - { SRAMACCESS, "SRAMACCESS", 0x0000000E9D660000 }, - { SRAM2PDR, "SRAM2PDR", 0x4CF0000000000000 }, - { PDR2SRAM, "PDR2SRAM", 0x0CF0000000000000 }, - { WBINVD, "WBINVD", 0x09090909090990F0 }, + { SRAMACCESS, "SRAMACCESS", 0x0000000E9D660000ULL }, + { SRAM2PDR, "SRAM2PDR", 0x4CF0000000000000ULL }, + { PDR2SRAM, "PDR2SRAM", 0x0CF0000000000000ULL }, + { WBINVD, "WBINVD", 0x09090909090990F0ULL }, }; bool check_not_halted(const struct target *t) diff --git a/src/target/lakemont.h b/src/target/lakemont.h index 98efd44a99..ca6557fcde 100644 --- a/src/target/lakemont.h +++ b/src/target/lakemont.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Copyright(c) 2013-2016 Intel Corporation. * @@ -7,19 +9,6 @@ * Julien Carreno (julien.carreno@intel.com) * Jeffrey Maxwell (jeffrey.r.maxwell@intel.com) * - * 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/>. - * * Contact Information: * Intel Corporation */ diff --git a/src/target/ls1_sap.c b/src/target/ls1_sap.c index c167224d28..9bd00c0e5f 100644 --- a/src/target/ls1_sap.c +++ b/src/target/ls1_sap.c @@ -1,17 +1,8 @@ -/*************************************************************************** - * Copyright (C) 2015 by Esben Haabendal * - * eha@deif.com * - * * - * 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. * - ***************************************************************************/ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2015 by Esben Haabendal <eha@deif.com> + */ #ifdef HAVE_CONFIG_H #include "config.h" diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c index eef05b44bb..5c81e3a75f 100644 --- a/src/target/mem_ap.c +++ b/src/target/mem_ap.c @@ -1,16 +1,8 @@ -/***************************************************************************** - * Copyright (C) 2016 by Matthias Welwarsky <matthias.welwarsky@sysgo.com> * - * * - * 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. * - ****************************************************************************/ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2016 by Matthias Welwarsky <matthias.welwarsky@sysgo.com> + */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -29,7 +21,7 @@ struct mem_ap { int common_magic; struct adiv5_dap *dap; struct adiv5_ap *ap; - int ap_num; + uint64_t ap_num; }; static int mem_ap_target_create(struct target *target, Jim_Interp *interp) @@ -74,8 +66,13 @@ static int mem_ap_init_target(struct command_context *cmd_ctx, struct target *ta static void mem_ap_deinit_target(struct target *target) { + struct mem_ap *mem_ap = target->arch_info; + LOG_DEBUG("%s", __func__); + if (mem_ap->ap) + dap_put_ap(mem_ap->ap); + free(target->private_config); free(target->arch_info); return; @@ -139,7 +136,13 @@ static int mem_ap_examine(struct target *target) struct mem_ap *mem_ap = target->arch_info; if (!target_was_examined(target)) { - mem_ap->ap = dap_ap(mem_ap->dap, mem_ap->ap_num); + if (!mem_ap->ap) { + mem_ap->ap = dap_get_ap(mem_ap->dap, mem_ap->ap_num); + if (!mem_ap->ap) { + LOG_ERROR("Cannot get AP"); + return ERROR_FAIL; + } + } target_set_examined(target); target->state = TARGET_UNKNOWN; target->debug_reason = DBG_REASON_UNDEFINED; @@ -179,7 +182,7 @@ static struct reg_arch_type mem_ap_reg_arch_type = { .set = mem_ap_reg_set, }; -const char *mem_ap_get_gdb_arch(struct target *target) +static const char *mem_ap_get_gdb_arch(const struct target *target) { return "arm"; } diff --git a/src/target/mips32.c b/src/target/mips32.c index c82536931e..5b94e6c894 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * @@ -9,19 +11,6 @@ * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -29,6 +18,7 @@ #endif #include "mips32.h" +#include "mips_cpu.h" #include "breakpoints.h" #include "algorithm.h" #include "register.h" @@ -37,7 +27,7 @@ static const char *mips_isa_strings[] = { "MIPS32", "MIPS16", "", "MICRO MIPS32", }; -#define MIPS32_GDB_DUMMY_FP_REG 1 +#define MIPS32_GDB_FP_REG 1 /* * GDB registers @@ -49,7 +39,7 @@ static const struct { enum reg_type type; const char *group; const char *feature; - int flag; + int size; } mips32_regs[] = { { 0, "r0", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 1, "r1", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, @@ -83,87 +73,93 @@ static const struct { { 29, "r29", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 30, "r30", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 31, "r31", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, - { 32, "status", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 }, - { 33, "lo", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, - { 34, "hi", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, - { 35, "badvaddr", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 }, - { 36, "cause", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 }, - { 37, "pc", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, - - { 38, "f0", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 39, "f1", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 40, "f2", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 41, "f3", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 42, "f4", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 43, "f5", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 44, "f6", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 45, "f7", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 46, "f8", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 47, "f9", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 48, "f10", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 49, "f11", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 50, "f12", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 51, "f13", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 52, "f14", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 53, "f15", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 54, "f16", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 55, "f17", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 56, "f18", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 57, "f19", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 58, "f20", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 59, "f21", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 60, "f22", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 61, "f23", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 62, "f24", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 63, "f25", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 64, "f26", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 65, "f27", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 66, "f28", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 67, "f29", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 68, "f30", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 69, "f31", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 70, "fcsr", REG_TYPE_INT, "float", - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 71, "fir", REG_TYPE_INT, "float", - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, + { 32, "lo", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 33, "hi", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, + + { MIPS32_REGLIST_FP_INDEX + 0, "f0", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 1, "f1", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 2, "f2", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 3, "f3", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 4, "f4", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 5, "f5", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 6, "f6", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 7, "f7", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 8, "f8", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 9, "f9", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 10, "f10", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 11, "f11", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 12, "f12", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 13, "f13", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 14, "f14", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 15, "f15", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 16, "f16", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 17, "f17", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 18, "f18", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 19, "f19", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 20, "f20", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 21, "f21", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 22, "f22", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 23, "f23", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 24, "f24", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 25, "f25", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 26, "f26", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 27, "f27", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 28, "f28", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 29, "f29", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 30, "f30", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 31, "f31", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + + { MIPS32_REGLIST_FPC_INDEX + 0, "fcsr", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS32_REGLIST_FPC_INDEX + 1, "fir", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + + { MIPS32_REGLIST_C0_STATUS_INDEX, "status", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS32_REGLIST_C0_BADVADDR_INDEX, "badvaddr", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS32_REGLIST_C0_CAUSE_INDEX, "cause", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS32_REGLIST_C0_PC_INDEX, "pc", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.cpu", 0 }, + { MIPS32_REGLIST_C0_GUESTCTL1_INDEX, "guestCtl1", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.cp0", 0 }, }; - #define MIPS32_NUM_REGS ARRAY_SIZE(mips32_regs) -static uint8_t mips32_gdb_dummy_fp_value[] = {0, 0, 0, 0}; static int mips32_get_core_reg(struct reg *reg) { @@ -184,12 +180,21 @@ static int mips32_set_core_reg(struct reg *reg, uint8_t *buf) { struct mips32_core_reg *mips32_reg = reg->arch_info; struct target *target = mips32_reg->target; - uint32_t value = buf_get_u32(buf, 0, 32); + uint64_t value; + + if (reg->size == 64) + value = buf_get_u64(buf, 0, 64); + else + value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; - buf_set_u32(reg->value, 0, 32, value); + if (reg->size == 64) + buf_set_u64(reg->value, 0, 64, value); + else + buf_set_u32(reg->value, 0, 32, value); + reg->dirty = true; reg->valid = true; @@ -198,7 +203,8 @@ static int mips32_set_core_reg(struct reg *reg, uint8_t *buf) static int mips32_read_core_reg(struct target *target, unsigned int num) { - uint32_t reg_value; + unsigned int cnum; + uint64_t reg_value = 0; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); @@ -206,17 +212,40 @@ static int mips32_read_core_reg(struct target *target, unsigned int num) if (num >= MIPS32_NUM_REGS) return ERROR_COMMAND_SYNTAX_ERROR; - reg_value = mips32->core_regs[num]; - buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); + if (num >= MIPS32_REGLIST_C0_INDEX) { + /* CP0 */ + cnum = num - MIPS32_REGLIST_C0_INDEX; + reg_value = mips32->core_regs.cp0[cnum]; + buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); + } else if (num >= MIPS32_REGLIST_FPC_INDEX) { + /* FPCR */ + cnum = num - MIPS32_REGLIST_FPC_INDEX; + reg_value = mips32->core_regs.fpcr[cnum]; + buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); + } else if (num >= MIPS32_REGLIST_FP_INDEX) { + /* FPR */ + cnum = num - MIPS32_REGLIST_FP_INDEX; + reg_value = mips32->core_regs.fpr[cnum]; + buf_set_u64(mips32->core_cache->reg_list[num].value, 0, 64, reg_value); + } else { + /* GPR */ + cnum = num - MIPS32_REGLIST_GP_INDEX; + reg_value = mips32->core_regs.gpr[cnum]; + buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); + } + mips32->core_cache->reg_list[num].valid = true; mips32->core_cache->reg_list[num].dirty = false; + LOG_DEBUG("read core reg %i value 0x%" PRIx64 "", num, reg_value); + return ERROR_OK; } static int mips32_write_core_reg(struct target *target, unsigned int num) { - uint32_t reg_value; + unsigned int cnum; + uint64_t reg_value; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); @@ -224,9 +253,29 @@ static int mips32_write_core_reg(struct target *target, unsigned int num) if (num >= MIPS32_NUM_REGS) return ERROR_COMMAND_SYNTAX_ERROR; - reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); - mips32->core_regs[num] = reg_value; - LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value); + if (num >= MIPS32_REGLIST_C0_INDEX) { + /* CP0 */ + cnum = num - MIPS32_REGLIST_C0_INDEX; + reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); + mips32->core_regs.cp0[cnum] = (uint32_t)reg_value; + } else if (num >= MIPS32_REGLIST_FPC_INDEX) { + /* FPCR */ + cnum = num - MIPS32_REGLIST_FPC_INDEX; + reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); + mips32->core_regs.fpcr[cnum] = (uint32_t)reg_value; + } else if (num >= MIPS32_REGLIST_FP_INDEX) { + /* FPR */ + cnum = num - MIPS32_REGLIST_FP_INDEX; + reg_value = buf_get_u64(mips32->core_cache->reg_list[num].value, 0, 64); + mips32->core_regs.fpr[cnum] = reg_value; + } else { + /* GPR */ + cnum = num - MIPS32_REGLIST_GP_INDEX; + reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); + mips32->core_regs.gpr[cnum] = (uint32_t)reg_value; + } + + LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num, reg_value); mips32->core_cache->reg_list[num].valid = true; mips32->core_cache->reg_list[num].dirty = false; @@ -256,10 +305,13 @@ int mips32_save_context(struct target *target) /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); - struct mips_ejtag *ejtag_info = &mips32->ejtag_info; /* read core registers */ - mips32_pracc_read_regs(ejtag_info, mips32->core_regs); + int retval = mips32_pracc_read_regs(mips32); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read core registers from target"); + return retval; + } for (i = 0; i < MIPS32_NUM_REGS; i++) { if (!mips32->core_cache->reg_list[i].valid) @@ -275,7 +327,6 @@ int mips32_restore_context(struct target *target) /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); - struct mips_ejtag *ejtag_info = &mips32->ejtag_info; for (i = 0; i < MIPS32_NUM_REGS; i++) { if (mips32->core_cache->reg_list[i].dirty) @@ -283,9 +334,7 @@ int mips32_restore_context(struct target *target) } /* write core regs */ - mips32_pracc_write_regs(ejtag_info, mips32->core_regs); - - return ERROR_OK; + return mips32_pracc_write_regs(mips32); } int mips32_arch_state(struct target *target) @@ -295,7 +344,7 @@ int mips32_arch_state(struct target *target) LOG_USER("target halted in %s mode due to %s, pc: 0x%8.8" PRIx32 "", mips_isa_strings[mips32->isa_mode], debug_reason_name(target), - buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32)); + buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32)); return ERROR_OK; } @@ -332,25 +381,19 @@ struct reg_cache *mips32_build_reg_cache(struct target *target) arch_info[i].mips32_common = mips32; reg_list[i].name = mips32_regs[i].name; - reg_list[i].size = 32; - - if (mips32_regs[i].flag == MIPS32_GDB_DUMMY_FP_REG) { - reg_list[i].value = mips32_gdb_dummy_fp_value; - reg_list[i].valid = true; - reg_list[i].arch_info = NULL; - register_init_dummy(®_list[i]); - } else { - reg_list[i].value = calloc(1, 4); - reg_list[i].valid = false; - reg_list[i].type = &mips32_reg_type; - reg_list[i].arch_info = &arch_info[i]; - - reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); - if (reg_list[i].reg_data_type) - reg_list[i].reg_data_type->type = mips32_regs[i].type; - else - LOG_ERROR("unable to allocate reg type list"); - } + reg_list[i].size = mips32_regs[i].size ? 64 : 32; + + reg_list[i].value = mips32_regs[i].size ? calloc(1, 8) : calloc(1, 4); + reg_list[i].valid = false; + reg_list[i].type = &mips32_reg_type; + reg_list[i].arch_info = &arch_info[i]; + + reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); + if (reg_list[i].reg_data_type) + reg_list[i].reg_data_type->type = mips32_regs[i].type; + else + LOG_ERROR("unable to allocate reg type list"); + reg_list[i].dirty = false; @@ -395,7 +438,7 @@ int mips32_init_arch_info(struct target *target, struct mips32_common *mips32, s /* run to exit point. return error if exit point was not reached. */ static int mips32_run_and_wait(struct target *target, target_addr_t entry_point, - int timeout_ms, target_addr_t exit_point, struct mips32_common *mips32) + unsigned int timeout_ms, target_addr_t exit_point, struct mips32_common *mips32) { uint32_t pc; int retval; @@ -417,7 +460,7 @@ static int mips32_run_and_wait(struct target *target, target_addr_t entry_point, return ERROR_TARGET_TIMEOUT; } - pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32); + pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32); if (exit_point && (pc != exit_point)) { LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 " ", pc); return ERROR_TARGET_TIMEOUT; @@ -429,7 +472,7 @@ static int mips32_run_and_wait(struct target *target, target_addr_t entry_point, int mips32_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, - target_addr_t exit_point, int timeout_ms, void *arch_info) + target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { struct mips32_common *mips32 = target_to_mips32(target); struct mips32_algorithm *mips32_algorithm_info = arch_info; @@ -449,7 +492,7 @@ int mips32_run_algorithm(struct target *target, int num_mem_params, } if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted (run target algo)"); return ERROR_TARGET_NOT_HALTED; } @@ -704,15 +747,253 @@ int mips32_enable_interrupts(struct target *target, int enable) return ERROR_OK; } +/* read processor identification cp0 register */ +static int mips32_read_c0_prid(struct target *target) +{ + struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + int retval; + + retval = mips32_cp0_read(ejtag_info, &mips32->prid, 15, 0); + if (retval != ERROR_OK) { + LOG_ERROR("processor id not available, failed to read cp0 PRId register"); + mips32->prid = 0; + } + + return retval; +} + +/** + * mips32_find_cpu_by_prid - Find CPU information by processor ID. + * @param[in] prid: Processor ID of the CPU. + * + * @brief This function looks up the CPU entry in the mips32_cpu_entry array based on the provided + * processor ID. It also handles special cases like AMD/Alchemy CPUs that use Company Options + * instead of Processor IDs. + * + * @return Pointer to the corresponding cpu_entry struct, or the 'unknown' entry if not found. + */ +static const struct cpu_entry *mips32_find_cpu_by_prid(uint32_t prid) +{ + /* AMD/Alchemy CPU uses Company Options instead of Processor ID. + * Therefore an extra transform step for prid to map it to an assigned ID, + */ + if ((prid & PRID_COMP_MASK) == PRID_COMP_ALCHEMY) { + /* Clears Processor ID field, then put Company Option field to its place */ + prid = (prid & 0xFFFF00FF) | ((prid & 0xFF000000) >> 16); + } + + /* Mask out Company Option */ + prid &= 0x00FFFFFF; + + for (unsigned int i = 0; i < MIPS32_NUM_CPU_ENTRIES; i++) { + const struct cpu_entry *entry = &mips32_cpu_entry[i]; + if ((entry->prid & MIPS32_CORE_MASK) <= prid && prid <= entry->prid) + return entry; + } + + /* If nothing matched, then return unknown entry */ + return &mips32_cpu_entry[MIPS32_NUM_CPU_ENTRIES - 1]; +} + +static bool mips32_cpu_is_lexra(struct mips_ejtag *ejtag_info) +{ + return (ejtag_info->prid & PRID_COMP_MASK) == PRID_COMP_LEXRA; +} + +static int mips32_cpu_get_release(struct mips_ejtag *ejtag_info) +{ + return (ejtag_info->config[0] & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT; +} + +/** + * mips32_cpu_support_sync - Checks CPU supports ordering + * @param[in] ejtag_info: MIPS EJTAG information structure. + * + * @brief MIPS ISA implemented on Lexra CPUs is MIPS-I, similar to R3000, + * which does not have the SYNC instruction alone with unaligned + * load/store instructions. + * + * @returns true if current CPU supports sync instruction(CPU is not Lexra) +*/ +bool mips32_cpu_support_sync(struct mips_ejtag *ejtag_info) +{ + return !mips32_cpu_is_lexra(ejtag_info); +} + +/** + * mips32_cpu_support_hazard_barrier - Checks CPU supports hazard barrier + * @param[in] ejtag_info: MIPS EJTAG information structure. + * + * @brief hazard barrier instructions EHB and *.HB was introduced to MIPS from release 2. + * + * @returns true if current CPU supports hazard barrier(release > 1) +*/ +bool mips32_cpu_support_hazard_barrier(struct mips_ejtag *ejtag_info) +{ + return mips32_cpu_get_release(ejtag_info) > MIPS32_RELEASE_1; +} + +/** + * mips32_cpu_probe - Detects processor type and applies necessary quirks. + * @param[in] target: The target CPU to probe. + * + * @brief This function probes the CPU, reads its PRID (Processor ID), and determines the CPU type. + * It applies any quirks necessary for specific processor types. + * + * NOTE: The proper detection of certain CPUs can become quite complicated. + * Please consult the following Linux kernel code when adding new CPUs: + * arch/mips/include/asm/cpu.h + * arch/mips/kernel/cpu-probe.c + * + * @return ERROR_OK on success; error code on failure. + */ +int mips32_cpu_probe(struct target *target) +{ + struct mips32_common *mips32 = target_to_mips32(target); + int retval; + + if (mips32->prid) + return ERROR_OK; /* Already probed once, return early. */ + + retval = mips32_read_c0_prid(target); + if (retval != ERROR_OK) + return retval; + + const struct cpu_entry *entry = mips32_find_cpu_by_prid(mips32->prid); + + switch (mips32->prid & PRID_COMP_MASK) { + case PRID_COMP_INGENIC_E1: + switch (mips32->prid & PRID_IMP_MASK) { + case PRID_IMP_XBURST_REV1: + mips32->cpu_quirks |= EJTAG_QUIRK_PAD_DRET; + break; + default: + break; + } + break; + + /* Determine which CP0 registers are available in the current processor core */ + case PRID_COMP_MTI: + switch (entry->prid & PRID_IMP_MASK) { + case PRID_IMP_MAPTIV_UC: + mips32->cp0_mask = MIPS_CP0_MAPTIV_UC; + break; + case PRID_IMP_MAPTIV_UP: + case PRID_IMP_M5150: + mips32->cp0_mask = MIPS_CP0_MAPTIV_UP; + break; + case PRID_IMP_IAPTIV: + case PRID_IMP_IAPTIV_CM: + mips32->cp0_mask = MIPS_CP0_IAPTIV; + break; + default: + /* CP0 mask should be the same as MK4 by default */ + mips32->cp0_mask = MIPS_CP0_MK4; + break; + } + + default: + break; + } + + mips32->cpu_info = entry; + LOG_DEBUG("CPU: %s (PRId %08x)", entry->cpu_name, mips32->prid); + + return ERROR_OK; +} + +/* reads dsp implementation info from CP0 Config3 register {DSPP, DSPREV}*/ +static void mips32_read_config_dsp(struct mips32_common *mips32, struct mips_ejtag *ejtag_info) +{ + uint32_t dsp_present = ((ejtag_info->config[3] & MIPS32_CONFIG3_DSPP_MASK) >> MIPS32_CONFIG3_DSPP_SHIFT); + if (dsp_present) { + mips32->dsp_imp = ((ejtag_info->config[3] & MIPS32_CONFIG3_DSPREV_MASK) >> MIPS32_CONFIG3_DSPREV_SHIFT) + 1; + LOG_USER("DSP implemented: %s, rev %d", "yes", mips32->dsp_imp); + } else { + LOG_USER("DSP implemented: %s", "no"); + } +} + +/* read fpu implementation info from CP0 Config1 register {CU1, FP}*/ +static int mips32_read_config_fpu(struct mips32_common *mips32, struct mips_ejtag *ejtag_info) +{ + int retval; + uint32_t fp_imp = (ejtag_info->config[1] & MIPS32_CONFIG1_FP_MASK) >> MIPS32_CONFIG1_FP_SHIFT; + char buf[60] = {0}; + if (!fp_imp) { + LOG_USER("FPU implemented: %s", "no"); + mips32->fp_imp = MIPS32_FP_IMP_NONE; + return ERROR_OK; + } + uint32_t status_value; + bool status_fr, status_cu1; + + retval = mips32_cp0_read(ejtag_info, &status_value, MIPS32_C0_STATUS, 0); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read cp0 status register"); + return retval; + } + + status_fr = (status_value >> MIPS32_CP0_STATUS_FR_SHIFT) & 0x1; + status_cu1 = (status_value >> MIPS32_CP0_STATUS_CU1_SHIFT) & 0x1; + if (status_cu1) { + /* TODO: read fpu(cp1) config register for current operating mode. + * Now its set to 32 bits by default. */ + snprintf(buf, sizeof(buf), "yes"); + fp_imp = MIPS32_FP_IMP_32; + } else { + snprintf(buf, sizeof(buf), "yes, disabled"); + fp_imp = MIPS32_FP_IMP_UNKNOWN; + } + + mips32->fpu_in_64bit = status_fr; + mips32->fpu_enabled = status_cu1; + + LOG_USER("FPU implemented: %s", buf); + mips32->fp_imp = fp_imp; + + return ERROR_OK; +} + +/** + * mips32_read_config_fdc - Read Fast Debug Channel configuration + * @param[in,out] mips32: MIPS32 common structure + * @param[in] ejtag_info: EJTAG information structure + * @param[in] dcr: Device Configuration Register value + * + * @brief Checks if the current target implements the Common Device Memory Map (CDMM) and Fast Debug Channel (FDC). + * + * This function examines the configuration registers and the Device Configuration Register (DCR) to determine + * if the current MIPS32 target supports the Common Device Memory Map (CDMM) and the Fast Debug Channel (FDC). + * If supported, it sets the corresponding flags in the MIPS32 common structure. \n + * + * NOTE:These are defined on MD00090, page 67 and MD00047F, page 82, respectively. + * MIPS Documents are pretty much all available online, + * it should pop up first when you search "MDxxxxx" + */ +static void mips32_read_config_fdc(struct mips32_common *mips32, struct mips_ejtag *ejtag_info, uint32_t dcr) +{ + if (((ejtag_info->config[3] & MIPS32_CONFIG3_CDMM_MASK) != 0) && ((dcr & EJTAG_DCR_FDC) != 0)) { + mips32->fdc = 1; + mips32->semihosting = 1; + } else { + mips32->fdc = 0; + mips32->semihosting = 0; + } +} + /* read config to config3 cp0 registers and log isa implementation */ int mips32_read_config_regs(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + char buf[60] = {0}; + int retval; if (ejtag_info->config_regs == 0) for (int i = 0; i != 4; i++) { - int retval = mips32_cp0_read(ejtag_info, &ejtag_info->config[i], 16, i); + retval = mips32_cp0_read(ejtag_info, &ejtag_info->config[i], 16, i); if (retval != ERROR_OK) { LOG_ERROR("isa info not available, failed to read cp0 config register: %" PRId32, i); ejtag_info->config_regs = 0; @@ -727,27 +1008,56 @@ int mips32_read_config_regs(struct target *target) LOG_DEBUG("read %"PRIu32" config registers", ejtag_info->config_regs); + mips32->isa_rel = (ejtag_info->config[0] & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT; + snprintf(buf, sizeof(buf), ", release %s(AR=%d)", + mips32->isa_rel == MIPS32_RELEASE_1 ? "1" + : mips32->isa_rel == MIPS32_RELEASE_2 ? "2" + : mips32->isa_rel == MIPS32_RELEASE_6 ? "6" + : "unknown", mips32->isa_rel); + if (ejtag_info->impcode & EJTAG_IMP_MIPS16) { mips32->isa_imp = MIPS32_MIPS16; - LOG_USER("MIPS32 with MIPS16 support implemented"); - + LOG_USER("ISA implemented: %s%s", "MIPS32, MIPS16", buf); } else if (ejtag_info->config_regs >= 4) { /* config3 implemented */ unsigned isa_imp = (ejtag_info->config[3] & MIPS32_CONFIG3_ISA_MASK) >> MIPS32_CONFIG3_ISA_SHIFT; if (isa_imp == 1) { mips32->isa_imp = MMIPS32_ONLY; - LOG_USER("MICRO MIPS32 only implemented"); + LOG_USER("ISA implemented: %s%s", "microMIPS32", buf); } else if (isa_imp != 0) { mips32->isa_imp = MIPS32_MMIPS32; - LOG_USER("MIPS32 and MICRO MIPS32 implemented"); + LOG_USER("ISA implemented: %s%s", "MIPS32, microMIPS32", buf); } + } else if (mips32->isa_imp == MIPS32_ONLY) { + /* initial default value */ + LOG_USER("ISA implemented: %s%s", "MIPS32", buf); } - if (mips32->isa_imp == MIPS32_ONLY) /* initial default value */ - LOG_USER("MIPS32 only implemented"); + /* Retrieve DSP info */ + mips32_read_config_dsp(mips32, ejtag_info); + + /* Retrieve if Float Point CoProcessor Implemented */ + retval = mips32_read_config_fpu(mips32, ejtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("fpu info is not available, error while reading cp0 status"); + mips32->fp_imp = MIPS32_FP_IMP_NONE; + return retval; + } + + uint32_t dcr; + + retval = target_read_u32(target, EJTAG_DCR, &dcr); + if (retval != ERROR_OK) { + LOG_ERROR("failed to read EJTAG_DCR register"); + return retval; + } + + /* Determine if FDC and CDMM are implemented for this core */ + mips32_read_config_fdc(mips32, ejtag_info, dcr); return ERROR_OK; } + int mips32_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) { @@ -814,7 +1124,7 @@ int mips32_checksum_memory(struct target *target, target_addr_t address, init_reg_param(®_params[1], "r5", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); - int timeout = 20000 * (1 + (count / (1024 * 1024))); + unsigned int timeout = 20000 * (1 + (count / (1024 * 1024))); retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, crc_algorithm->address + (sizeof(mips_crc_code) - 4), timeout, &mips32_info); @@ -916,12 +1226,284 @@ static int mips32_verify_pointer(struct command_invocation *cmd, } /** - * MIPS32 targets expose command interface - * to manipulate CP0 registers + * mips32_read_config_mmu - Reads MMU configuration and logs relevant information. + * @param[in] ejtag_info: EJTAG interface information. + * + * @brief Reads the MMU configuration from the CP0 register and calculates the number of TLB entries, + * ways, and sets. Handles different MMU types like VTLB only, root RPU/Fixed, and VTLB and FTLB. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_read_config_mmu(struct mips_ejtag *ejtag_info) +{ + uint32_t config4, tlb_entries = 0, ways = 0, sets = 0; + uint32_t config0 = ejtag_info->config[0]; + uint32_t config1 = ejtag_info->config[1]; + uint32_t config3 = ejtag_info->config[3]; + uint32_t mmu_type = (config0 >> 7) & 7; + uint32_t vz_present = (config3 & BIT(23)); + + int retval = mips32_cp0_read(ejtag_info, &config4, 16, 4); + if (retval != ERROR_OK) + return retval; + + /* mmu type = 1: VTLB only (Note: Does not account for Config4.ExtVTLB) + * mmu type = 3: root RPU/Fixed (Note: Only valid with VZ ASE) + * mmu type = 4: VTLB and FTLB + */ + if ((mmu_type == 1 || mmu_type == 4) || (mmu_type == 3 && vz_present)) { + tlb_entries = (uint32_t)(((config1 >> 25) & 0x3f) + 1); + if (mmu_type == 4) { + /* Release 6 definition for Config4[0:15] (MD01251, page 243) */ + /* The FTLB ways field is defined as [2, 3, 4, 5, 6, 7, 8, ...0 (reserved)] */ + int index = ((config4 >> 4) & 0xf); + ways = index > 6 ? 0 : index + 2; + + /* The FTLB sets field is defined as [1, 2, 4, 8, ..., 16384, 32768] (powers of 2) */ + index = (config4 & 0xf); + sets = 1 << index; + tlb_entries = tlb_entries + (ways * sets); + } + } + LOG_USER("TLB Entries: %d (%d ways, %d sets per way)", tlb_entries, ways, sets); + + return ERROR_OK; +} + +/** + * mips32_cp0_find_register_by_name - Find CP0 register by its name. + * @param[in] cp0_mask: Mask to filter out irrelevant registers. + * @param[in] reg_name: Name of the register to find. + * + * @brief This function iterates through mips32_cp0_regs to find a register + * matching reg_name, considering cp0_mask to filter out registers + * not relevant for the current core. + * + * @return Pointer to the found register, or NULL if not found. + */ +static const struct mips32_cp0 *mips32_cp0_find_register_by_name(uint32_t cp0_mask, const char *reg_name) +{ + if (reg_name) + for (unsigned int i = 0; i < MIPS32NUMCP0REGS; i++) { + if ((mips32_cp0_regs[i].core & cp0_mask) == 0) + continue; + + if (strcmp(mips32_cp0_regs[i].name, reg_name) == 0) + return &mips32_cp0_regs[i]; + } + return NULL; +} + +/** + * mips32_cp0_get_all_regs - Print all CP0 registers and their values. + * @param[in] cmd: Command invocation context. + * @param[in] ejtag_info: EJTAG interface information. + * @param[in] cp0_mask: Mask to identify relevant registers. + * + * @brief Iterates over all CP0 registers, reads their values, and prints them. + * Only considers registers relevant to the current core, as defined by cp0_mask. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_cp0_get_all_regs(struct command_invocation *cmd, struct mips_ejtag *ejtag_info, uint32_t cp0_mask) +{ + uint32_t value; + + for (unsigned int i = 0; i < MIPS32NUMCP0REGS; i++) { + /* Register name not valid for this core */ + if ((mips32_cp0_regs[i].core & cp0_mask) == 0) + continue; + + int retval = mips32_cp0_read(ejtag_info, &value, mips32_cp0_regs[i].reg, mips32_cp0_regs[i].sel); + if (retval != ERROR_OK) { + command_print(CMD, "Error: couldn't access reg %s", mips32_cp0_regs[i].name); + return retval; + } + + command_print(CMD, "%*s: 0x%8.8" PRIx32, 14, mips32_cp0_regs[i].name, value); + } + return ERROR_OK; +} + +/** + * mips32_cp0_get_reg_by_name - Read and print a CP0 register's value by name. + * @param[in] cmd: Command invocation context. + * @param[in] ejtag_info: EJTAG interface information. + * @param[in] cp0_mask: Mask to identify relevant registers. + * + * @brief Finds a CP0 register by name, reads its value, and prints it. + * Handles error scenarios like register not found or read failure. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_cp0_get_reg_by_name(struct command_invocation *cmd, struct mips_ejtag *ejtag_info, uint32_t cp0_mask) +{ + const struct mips32_cp0 *cp0_regs = mips32_cp0_find_register_by_name(cp0_mask, CMD_ARGV[0]); + if (!cp0_regs) { + command_print(CMD, "Error: Register '%s' not found", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + uint32_t value; + int retval = mips32_cp0_read(ejtag_info, &value, cp0_regs->reg, cp0_regs->sel); + if (retval != ERROR_OK) { + command_print(CMD, "Error: Encounter an Error while reading cp0 reg %d sel %d", + cp0_regs->reg, cp0_regs->sel); + return retval; + } + + command_print(CMD, "0x%8.8" PRIx32, value); + return ERROR_OK; +} + +/** + * mips32_cp0_get_reg_by_number - Read and print a CP0 register's value by number. + * @param[in] cmd: Command invocation context. + * @param[in] ejtag_info: EJTAG interface information. + * + * @brief Reads a specific CP0 register (identified by number and selection) and prints its value. + * The register number and selection are parsed from the command arguments. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_cp0_get_reg_by_number(struct command_invocation *cmd, struct mips_ejtag *ejtag_info) +{ + uint32_t cp0_reg, cp0_sel, value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel); + + int retval = mips32_cp0_read(ejtag_info, &value, cp0_reg, cp0_sel); + if (retval != ERROR_OK) { + command_print(CMD, + "Error: couldn't access reg %" PRIu32, + cp0_reg); + return retval; + } + + command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32, + cp0_reg, cp0_sel, value); + return ERROR_OK; +} + +/** + * mips32_cp0_set_reg_by_name - Write to a CP0 register identified by name. + * @param[in] cmd: Command invocation context. + * @param[in] mips32: Common MIPS32 data structure. + * @param[in] ejtag_info: EJTAG interface information. + * + * @brief Writes a value to a CP0 register specified by name. Updates internal + * cache if specific registers (STATUS, CAUSE, DEPC, GUESTCTL1) are modified. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_cp0_set_reg_by_name(struct command_invocation *cmd, + struct mips32_common *mips32, struct mips_ejtag *ejtag_info) +{ + const struct mips32_cp0 *cp0_regs = mips32_cp0_find_register_by_name(mips32->cp0_mask, CMD_ARGV[0]); + if (!cp0_regs) { + command_print(CMD, "Error: Register '%s' not found", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + + uint32_t value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + + if (cp0_regs->reg == MIPS32_C0_STATUS && cp0_regs->sel == 0) { + /* Update cached Status register if user is writing to Status */ + mips32->core_regs.cp0[MIPS32_REG_C0_STATUS_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_STATUS_INDEX].dirty = 1; + } else if (cp0_regs->reg == MIPS32_C0_CAUSE && cp0_regs->sel == 0) { + /* Update register cache with new value if its Cause */ + mips32->core_regs.cp0[MIPS32_REG_C0_CAUSE_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_CAUSE_INDEX].dirty = 1; + } else if (cp0_regs->reg == MIPS32_C0_DEPC && cp0_regs->sel == 0) { + /* Update cached PC if its DEPC */ + mips32->core_regs.cp0[MIPS32_REG_C0_PC_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].dirty = 1; + } else if (cp0_regs->reg == MIPS32_C0_GUESTCTL1 && cp0_regs->sel == 4) { + /* Update cached guestCtl1 */ + mips32->core_regs.cp0[MIPS32_REG_C0_GUESTCTL1_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_GUESTCTL1_INDEX].dirty = 1; + } + + int retval = mips32_cp0_write(ejtag_info, value, + cp0_regs->reg, + cp0_regs->sel); + if (retval != ERROR_OK) { + command_print(CMD, "Error: Encounter an Error while writing to cp0 reg %d, sel %d", + cp0_regs->reg, cp0_regs->sel); + return retval; + } + + command_print(CMD, "cp0 reg %s (%u, select %u: %8.8" PRIx32 ")", + CMD_ARGV[0], cp0_regs->reg, cp0_regs->sel, value); + return ERROR_OK; +} + +/** + * mips32_cp0_set_reg_by_number - Write to a CP0 register identified by number. + * @param[in] cmd: Command invocation context. + * @param[in] mips32: Common MIPS32 data structure. + * @param[in] ejtag_info: EJTAG interface information. + * + * @brief Writes a value to a CP0 register specified by number and selection. + * Handles special cases like updating the internal cache for certain registers. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_cp0_set_reg_by_number(struct command_invocation *cmd, + struct mips32_common *mips32, struct mips_ejtag *ejtag_info) +{ + uint32_t cp0_reg, cp0_sel, value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); + + if (cp0_reg == MIPS32_C0_STATUS && cp0_sel == 0) { + /* Update cached status register if user is writing to Status register */ + mips32->core_regs.cp0[MIPS32_REG_C0_STATUS_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_STATUS_INDEX].dirty = 1; + } else if (cp0_reg == MIPS32_C0_CAUSE && cp0_sel == 0) { + /* Update register cache with new value if its Cause register */ + mips32->core_regs.cp0[MIPS32_REG_C0_CAUSE_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_CAUSE_INDEX].dirty = 1; + } else if (cp0_reg == MIPS32_C0_DEPC && cp0_sel == 0) { + /* Update cached PC if its DEPC */ + mips32->core_regs.cp0[MIPS32_REG_C0_PC_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].dirty = 1; + } else if (cp0_reg == MIPS32_C0_GUESTCTL1 && cp0_sel == 4) { + /* Update cached guestCtl1, too */ + mips32->core_regs.cp0[MIPS32_REG_C0_GUESTCTL1_INDEX] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_GUESTCTL1_INDEX].dirty = 1; + } + + int retval = mips32_cp0_write(ejtag_info, value, cp0_reg, cp0_sel); + if (retval != ERROR_OK) { + command_print(CMD, + "Error: couldn't access cp0 reg %" PRIu32 ", select %" PRIu32, + cp0_reg, cp0_sel); + return retval; + } + + command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32, + cp0_reg, cp0_sel, value); + return ERROR_OK; +} + +/** + * mips32_handle_cp0_command - Handle commands related to CP0 registers. + * @cmd: Command invocation context. + * + * Orchestrates different operations on CP0 registers based on the command arguments. + * Supports operations like reading all registers, reading/writing a specific register + * by name or number. + * + * Return: ERROR_OK on success; error code on failure. */ COMMAND_HANDLER(mips32_handle_cp0_command) { - int retval; + int retval, tmp; struct target *target = get_current_target(CMD_CTX); struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; @@ -932,49 +1514,301 @@ COMMAND_HANDLER(mips32_handle_cp0_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } - /* two or more argument, access a single register/select (write if third argument is given) */ - if (CMD_ARGC < 2) + switch (CMD_ARGC) { + case 0: /* No arg => print out all cp0 regs */ + retval = mips32_cp0_get_all_regs(CMD, ejtag_info, mips32->cp0_mask); + break; + case 1: /* 1 arg => get cp0 #reg/#sel value by name */ + retval = mips32_cp0_get_reg_by_name(CMD, ejtag_info, mips32->cp0_mask); + break; + case 2: /* 2 args => get cp0 reg/sel value or set value by name */ + tmp = *CMD_ARGV[0]; + if (isdigit(tmp)) /* starts from number then args are #reg and #sel */ + retval = mips32_cp0_get_reg_by_number(CMD, ejtag_info); + else /* or set value by register name */ + retval = mips32_cp0_set_reg_by_name(CMD, mips32, ejtag_info); + + break; + case 3: /* 3 args => set cp0 reg/sel value*/ + retval = mips32_cp0_set_reg_by_number(CMD, mips32, ejtag_info); + break; + default: /* Other argc => err */ + retval = ERROR_COMMAND_SYNTAX_ERROR; + break; + } + + return retval; +} + +/** + * mips32_handle_cpuinfo_command - Handles the 'cpuinfo' command. + * @param[in] cmd: Command invocation context. + * + * @brief Executes the 'cpuinfo' command which displays detailed information about the current CPU core. + * This includes core type, vendor, instruction set, cache size, and other relevant details. + * + * @return ERROR_OK on success; error code on failure. + */ +COMMAND_HANDLER(mips32_handle_cpuinfo_command) +{ + int retval; + struct target *target = get_current_target(CMD_CTX); + struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + + uint32_t prid = mips32->prid; /* cp0 PRID - 15, 0 */ + uint32_t config0 = ejtag_info->config[0]; /* cp0 config - 16, 0 */ + uint32_t config1 = ejtag_info->config[1]; /* cp0 config - 16, 1 */ + uint32_t config3 = ejtag_info->config[3]; /* cp0 config - 16, 3 */ + + /* Following configs are not read during probe */ + uint32_t config5; /* cp0 config - 16, 5 */ + + /* No args for now */ + if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; - else { - uint32_t cp0_reg, cp0_sel; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel); - if (CMD_ARGC == 2) { - uint32_t value; + if (target->state != TARGET_HALTED) { + command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; + } - retval = mips32_cp0_read(ejtag_info, &value, cp0_reg, cp0_sel); - if (retval != ERROR_OK) { - command_print(CMD, - "couldn't access reg %" PRIu32, - cp0_reg); - return ERROR_OK; - } - command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32, - cp0_reg, cp0_sel, value); + retval = mips32_cp0_read(ejtag_info, &config5, 16, 5); + if (retval != ERROR_OK) + return retval; - } else if (CMD_ARGC == 3) { - uint32_t value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); - retval = mips32_cp0_write(ejtag_info, value, cp0_reg, cp0_sel); - if (retval != ERROR_OK) { - command_print(CMD, - "couldn't access cp0 reg %" PRIu32 ", select %" PRIu32, - cp0_reg, cp0_sel); - return ERROR_OK; - } - command_print(CMD, "cp0 reg %" PRIu32 ", select %" PRIu32 ": %8.8" PRIx32, - cp0_reg, cp0_sel, value); - } + /* Determine Core info */ + const struct cpu_entry *entry = mips32->cpu_info; + /* Display Core Type info */ + command_print(CMD, "CPU Core: %s", entry->cpu_name); + + /* Display Core Vendor ID if it's unknown */ + if (entry == &mips32_cpu_entry[MIPS32_NUM_CPU_ENTRIES - 1]) + command_print(CMD, "Vendor: Unknown CPU vendor code %x.", ((prid & 0x00ffff00) >> 16)); + else + command_print(CMD, "Vendor: %s", entry->vendor); + + /* If MIPS release 2 or above, then get exception base info */ + enum mips32_isa_rel ar = mips32->isa_rel; + if (ar > MIPS32_RELEASE_1) { /* release 2 and above */ + uint32_t ebase; + retval = mips32_cp0_read(ejtag_info, &ebase, 15, 1); + if (retval != ERROR_OK) + return retval; + + command_print(CMD, "Current CPU ID: %d", (ebase & 0x1ff)); + } else { + command_print(CMD, "Current CPU ID: 0"); + } + + char *instr; + switch ((config3 & MIPS32_CONFIG3_ISA_MASK) >> MIPS32_CONFIG3_ISA_SHIFT) { + case 0: + instr = "MIPS32"; + break; + case 1: + instr = "microMIPS"; + break; + case 2: + instr = "MIPS32 (at reset) and microMIPS"; + break; + case 3: + default: + instr = "microMIPS (at reset) and MIPS32"; + break; + } + + /* Display Instruction Set Info */ + command_print(CMD, "Instr set: %s", instr); + command_print(CMD, "Instr rel: %s", + ar == MIPS32_RELEASE_1 ? "1" + : ar == MIPS32_RELEASE_2 ? "2" + : ar == MIPS32_RELEASE_6 ? "6" + : "unknown"); + command_print(CMD, "PRId: %x", prid); + /* Some of MIPS CPU Revisions(for M74K) can be seen on MD00541, page 26 */ + uint32_t rev = prid & 0x000000ff; + command_print(CMD, "RTL Rev: %d.%d.%d", (rev & 0xE0), (rev & 0x1C), (rev & 0x3)); + + command_print(CMD, "Max Number of Instr Breakpoints: %d", mips32->num_inst_bpoints); + command_print(CMD, "Max Number of Data Breakpoints: %d", mips32->num_data_bpoints); + + /* MMU Support */ + uint32_t mmu_type = (config0 >> 7) & 7; /* MMU Type Info */ + char *mmu; + switch (mmu_type) { + case MIPS32_MMU_TLB: + mmu = "TLB"; + break; + case MIPS32_MMU_BAT: + mmu = "BAT"; + break; + case MIPS32_MMU_FIXED: + mmu = "FIXED"; + break; + case MIPS32_MMU_DUAL_VTLB_FTLB: + mmu = "DUAL VAR/FIXED"; + break; + default: + mmu = "Unknown"; } + command_print(CMD, "MMU Type: %s", mmu); + + retval = mips32_read_config_mmu(ejtag_info); + if (retval != ERROR_OK) + return retval; + + /* Definitions of I/D Cache Sizes are available on MD01251, page 224~226 */ + int index; + uint32_t ways, sets, bpl; + + /* Determine Instr Cache Size */ + /* Ways mapping = [1, 2, 3, 4, 5, 6, 7, 8] */ + ways = ((config1 >> MIPS32_CFG1_IASHIFT) & 7); + + /* Sets per way = [64, 128, 256, 512, 1024, 2048, 4096, 32] */ + index = ((config1 >> MIPS32_CFG1_ISSHIFT) & 7); + sets = index == 7 ? 32 : 32 << (index + 1); + + /* Bytes per line = [0, 4, 8, 16, 32, 64, 128, Reserved] */ + index = ((config1 >> MIPS32_CFG1_ILSHIFT) & 7); + bpl = index == 0 ? 0 : 4 << (index - 1); + command_print(CMD, "Instr Cache: %d (%d ways, %d lines, %d byte per line)", ways * sets * bpl, ways, sets, bpl); + + /* Determine data cache size, same as above */ + ways = ((config1 >> MIPS32_CFG1_DASHIFT) & 7); + + index = ((config1 >> MIPS32_CFG1_DSSHIFT) & 7); + sets = index == 7 ? 32 : 32 << (index + 1); + + index = ((config1 >> MIPS32_CFG1_DLSHIFT) & 7); + bpl = index == 0 ? 0 : 4 << (index - 1); + command_print(CMD, " Data Cache: %d (%d ways, %d lines, %d byte per line)", ways * sets * bpl, ways, sets, bpl); + + /* does the core hava FPU*/ + mips32_read_config_fpu(mips32, ejtag_info); + + /* does the core support a DSP */ + mips32_read_config_dsp(mips32, ejtag_info); + + /* VZ module */ + uint32_t vzase = (config3 & BIT(23)); + if (vzase) + command_print(CMD, "VZ implemented: yes"); + else + command_print(CMD, "VZ implemented: no"); + + /* multithreading */ + uint32_t mtase = (config3 & BIT(2)); + if (mtase) { + command_print(CMD, "MT implemented: yes"); + + /* Get VPE and Thread info */ + uint32_t tcbind; + uint32_t mvpconf0; + + /* Read tcbind register */ + retval = mips32_cp0_read(ejtag_info, &tcbind, 2, 2); + if (retval != ERROR_OK) + return retval; + + command_print(CMD, " | Current VPE: %d", (tcbind & 0xf)); + command_print(CMD, " | Current TC: %d", ((tcbind >> 21) & 0xff)); + + /* Read mvpconf0 register */ + retval = mips32_cp0_read(ejtag_info, &mvpconf0, 0, 2); + if (retval != ERROR_OK) + return retval; + + command_print(CMD, " | Total TC: %d", (mvpconf0 & 0xf) + 1); + command_print(CMD, " | Total VPE: %d", ((mvpconf0 >> 10) & 0xf) + 1); + } else { + command_print(CMD, "MT implemented: no"); + } + + /* MIPS SIMD Architecture (MSA) */ + uint32_t msa = (config3 & BIT(28)); + command_print(CMD, "MSA implemented: %s", msa ? "yes" : "no"); + + /* Move To/From High COP0 (MTHC0/MFHC0) instructions are implemented. + * Implicates current ISA release >= 5.*/ + uint32_t mvh = (config5 & BIT(5)); + command_print(CMD, "MVH implemented: %s", mvh ? "yes" : "no"); + + /* Common Device Memory Map implemented? */ + uint32_t cdmm = (config3 & BIT(3)); + command_print(CMD, "CDMM implemented: %s", cdmm ? "yes" : "no"); return ERROR_OK; } +/** + * mips32_handle_ejtag_reg_command - Handler commands related to EJTAG + * @param[in] cmd: Command invocation context + * + * @brief Prints all EJTAG Registers including DCR features. + * + * @return ERROR_OK on success; error code on failure. + */ +COMMAND_HANDLER(mips32_handle_ejtag_reg_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + + uint32_t ejtag_ctrl; + uint32_t dcr; + int retval; + + retval = mips_ejtag_get_idcode(ejtag_info); + if (retval != ERROR_OK) + command_print(CMD, "Error: Encounter an Error while getting idcode"); + else + command_print(CMD, " idcode: 0x%8.8" PRIx32, ejtag_info->idcode); + + retval = mips_ejtag_get_impcode(ejtag_info); + if (retval != ERROR_OK) + command_print(CMD, "Error: Encounter an Error while getting impcode"); + else + command_print(CMD, " impcode: 0x%8.8" PRIx32, ejtag_info->impcode); + + mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); + ejtag_ctrl = ejtag_info->ejtag_ctrl; + retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); + if (retval != ERROR_OK) + command_print(CMD, "Error: Encounter an Error while executing drscan reading EJTAG Control register"); + else + command_print(CMD, "ejtag control: 0x%8.8" PRIx32, ejtag_ctrl); + + ejtag_main_print_imp(ejtag_info); + + /* Display current DCR */ + retval = target_read_u32(target, EJTAG_DCR, &dcr); + if (retval != ERROR_OK) + command_print(CMD, "Error: Encounter an Error while reading Debug Control Register"); + else + command_print(CMD, " DCR: 0x%8.8" PRIx32, dcr); + + for (unsigned int i = 0; i < EJTAG_DCR_ENTRIES; i++) { + if (dcr & BIT(dcr_features[i].bit)) + command_print(CMD, "%s supported", dcr_features[i].name); + } + + return ERROR_OK; +} + +/** + * mips32_handle_scan_delay_command - Handler command for changing scan delay + * @param[in] cmd: Command invocation context + * + * @brief Changes current scan mode between legacy and fast queued mode. + * + * @return ERROR_OK on success; error code on failure. + */ COMMAND_HANDLER(mips32_handle_scan_delay_command) { struct target *target = get_current_target(CMD_CTX); @@ -1003,16 +1837,30 @@ static const struct command_registration mips32_exec_command_handlers[] = { .name = "cp0", .handler = mips32_handle_cp0_command, .mode = COMMAND_EXEC, - .usage = "regnum select [value]", + .usage = "[[reg_name|regnum select] [value]]", .help = "display/modify cp0 register", }, - { + { + .name = "cpuinfo", + .handler = mips32_handle_cpuinfo_command, + .mode = COMMAND_EXEC, + .help = "display CPU information", + .usage = "", + }, + { .name = "scan_delay", .handler = mips32_handle_scan_delay_command, .mode = COMMAND_ANY, .help = "display/set scan delay in nano seconds", .usage = "[value]", }, + { + .name = "ejtag_reg", + .handler = mips32_handle_ejtag_reg_command, + .mode = COMMAND_ANY, + .help = "read ejtag registers", + .usage = "", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/mips32.h b/src/target/mips32.h index 5ca3b7e05e..208c9da174 100644 --- a/src/target/mips32.h +++ b/src/target/mips32.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * @@ -6,28 +8,17 @@ * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_MIPS32_H #define OPENOCD_TARGET_MIPS32_H +#include <helper/bits.h> + #include "target.h" #include "mips32_pracc.h" -#define MIPS32_COMMON_MAGIC 0xB320B320 +#define MIPS32_COMMON_MAGIC 0xB320B320U /** * Memory segments (32bit kernel mode addresses) @@ -55,9 +46,21 @@ #define MIPS32_CONFIG0_AR_SHIFT 10 #define MIPS32_CONFIG0_AR_MASK (0x7 << MIPS32_CONFIG0_AR_SHIFT) +#define MIPS32_CONFIG1_FP_SHIFT 0 +#define MIPS32_CONFIG1_FP_MASK BIT(MIPS32_CONFIG1_FP_SHIFT) + #define MIPS32_CONFIG1_DL_SHIFT 10 #define MIPS32_CONFIG1_DL_MASK (0x7 << MIPS32_CONFIG1_DL_SHIFT) +#define MIPS32_CONFIG3_CDMM_SHIFT 3 +#define MIPS32_CONFIG3_CDMM_MASK BIT(MIPS32_CONFIG3_CDMM_SHIFT) + +#define MIPS32_CONFIG3_DSPP_SHIFT 10 +#define MIPS32_CONFIG3_DSPP_MASK BIT(MIPS32_CONFIG3_DSPP_SHIFT) + +#define MIPS32_CONFIG3_DSPREV_SHIFT 11 +#define MIPS32_CONFIG3_DSPREV_MASK BIT(MIPS32_CONFIG3_DSPREV_SHIFT) + #define MIPS32_CONFIG3_ISA_SHIFT 14 #define MIPS32_CONFIG3_ISA_MASK (3 << MIPS32_CONFIG3_ISA_SHIFT) @@ -66,6 +69,144 @@ #define MIPS32_SCAN_DELAY_LEGACY_MODE 2000000 +#define MIPS32_NUM_DSPREGS 9 + +/* Bit Mask indicating CP0 register supported by this core */ +#define MIPS_CP0_MK4 0x0001 +#define MIPS_CP0_MAPTIV_UC 0x0002 +#define MIPS_CP0_MAPTIV_UP 0x0004 +#define MIPS_CP0_IAPTIV 0x0008 + +/* CP0 Status register fields */ +#define MIPS32_CP0_STATUS_FR_SHIFT 26 +#define MIPS32_CP0_STATUS_CU1_SHIFT 29 + +/* CP1 FIR register fields */ +#define MIPS32_CP1_FIR_F64_SHIFT 22 + +static const struct mips32_cp0 { + unsigned int reg; + unsigned int sel; + const char *name; + const unsigned int core; +} mips32_cp0_regs[] = { + {0, 0, "index", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {0, 1, "mvpcontrol", MIPS_CP0_IAPTIV}, + {0, 2, "mvpconf0", MIPS_CP0_IAPTIV}, + {0, 3, "mvpconf1", MIPS_CP0_IAPTIV}, + {1, 0, "random", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {1, 1, "vpecontrol", MIPS_CP0_IAPTIV}, + {1, 2, "vpeconf0", MIPS_CP0_IAPTIV}, + {1, 3, "vpeconf1", MIPS_CP0_IAPTIV}, + {1, 4, "yqmask", MIPS_CP0_IAPTIV}, + {1, 5, "vpeschedule", MIPS_CP0_IAPTIV}, + {1, 6, "vpeschefback", MIPS_CP0_IAPTIV}, + {1, 7, "vpeopt", MIPS_CP0_IAPTIV}, + {2, 0, "entrylo0", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {2, 1, "tcstatus", MIPS_CP0_IAPTIV}, + {2, 2, "tcbind", MIPS_CP0_IAPTIV}, + {2, 3, "tcrestart", MIPS_CP0_IAPTIV}, + {2, 4, "tchalt", MIPS_CP0_IAPTIV}, + {2, 5, "tccontext", MIPS_CP0_IAPTIV}, + {2, 6, "tcschedule", MIPS_CP0_IAPTIV}, + {2, 7, "tcschefback", MIPS_CP0_IAPTIV}, + {3, 0, "entrylo1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {3, 7, "tcopt", MIPS_CP0_IAPTIV}, + {4, 0, "context", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {4, 2, "userlocal", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {5, 0, "pagemask", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {5, 1, "pagegrain", MIPS_CP0_MAPTIV_UP}, + {5, 2, "segctl0", MIPS_CP0_IAPTIV}, + {5, 3, "segctl1", MIPS_CP0_IAPTIV}, + {5, 4, "segctl2", MIPS_CP0_IAPTIV}, + {6, 0, "wired", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {6, 1, "srsconf0", MIPS_CP0_IAPTIV}, + {6, 2, "srsconf1", MIPS_CP0_IAPTIV}, + {6, 3, "srsconf2", MIPS_CP0_IAPTIV}, + {6, 4, "srsconf3", MIPS_CP0_IAPTIV}, + {6, 5, "srsconf4", MIPS_CP0_IAPTIV}, + {7, 0, "hwrena", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {8, 0, "badvaddr", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {8, 1, "badinstr", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, + {8, 2, "badinstrp", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, + {9, 0, "count", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {10, 0, "entryhi", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {10, 4, "guestctl1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {10, 5, "guestctl2", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {10, 6, "guestctl3", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {11, 0, "compare", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {11, 4, "guestctl0ext", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {12, 0, "status", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {12, 1, "intctl", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {12, 2, "srsctl", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {12, 3, "srsmap", MIPS_CP0_IAPTIV}, + {12, 3, "srsmap1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, + {12, 4, "view_ipl", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {12, 5, "srsmap2", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, + {12, 6, "guestctl0", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {12, 7, "gtoffset", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {13, 0, "cause", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {13, 5, "nestedexc", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {14, 0, "epc", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {14, 2, "nestedepc", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {15, 0, "prid", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {15, 1, "ebase", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {15, 2, "cdmmbase", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {15, 3, "cmgcrbase", MIPS_CP0_IAPTIV}, + {16, 0, "config", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 1, "config1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 2, "config2", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 3, "config3", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 4, "config4", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 5, "config5", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 7, "config7", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {17, 0, "lladdr", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {18, 0, "watchlo0", MIPS_CP0_IAPTIV}, + {18, 1, "watchlo1", MIPS_CP0_IAPTIV}, + {18, 2, "watchlo2", MIPS_CP0_IAPTIV}, + {18, 3, "watchlo3", MIPS_CP0_IAPTIV}, + {19, 0, "watchhi0", MIPS_CP0_IAPTIV}, + {19, 1, "watchhi1", MIPS_CP0_IAPTIV}, + {19, 2, "watchhi2", MIPS_CP0_IAPTIV}, + {19, 3, "watchhi3", MIPS_CP0_IAPTIV}, + {23, 0, "debug", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {23, 1, "tracecontrol", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {23, 2, "tracecontrol2", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {23, 3, "usertracedata1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {23, 4, "tracebpc", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {23, 4, "traceibpc", MIPS_CP0_IAPTIV}, + {23, 5, "tracedbpc", MIPS_CP0_IAPTIV}, + {24, 0, "depc", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {24, 2, "tracecontrol3", MIPS_CP0_IAPTIV}, + {24, 3, "usertracedata2", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {25, 0, "perfctl0", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {25, 1, "perfcnt0", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {25, 2, "perfctl1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {25, 3, "perfcnt1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {26, 0, "errctl", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {27, 0, "cacheerr", MIPS_CP0_IAPTIV}, + {28, 0, "itaglo", MIPS_CP0_IAPTIV}, + {28, 0, "taglo", MIPS_CP0_IAPTIV}, + {28, 1, "idatalo", MIPS_CP0_IAPTIV}, + {28, 1, "datalo", MIPS_CP0_IAPTIV}, + {28, 2, "dtaglo", MIPS_CP0_IAPTIV}, + {28, 3, "ddatalo", MIPS_CP0_IAPTIV}, + {28, 4, "l23taglo", MIPS_CP0_IAPTIV}, + {28, 5, "l23datalo", MIPS_CP0_IAPTIV}, + {29, 1, "idatahi", MIPS_CP0_IAPTIV}, + {29, 2, "dtaghi", MIPS_CP0_IAPTIV}, + {29, 5, "l23datahi", MIPS_CP0_IAPTIV}, + {30, 0, "errorepc", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {31, 0, "desave", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {31, 2, "kscratch1", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, + {31, 3, "kscratch2", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, +}; + +#define MIPS32NUMCP0REGS (ARRAY_SIZE(mips32_cp0_regs)) + +/* Insert extra NOPs after the DRET instruction on exit from debug. */ +#define EJTAG_QUIRK_PAD_DRET BIT(0) + /* offsets into mips32 core register cache */ enum { MIPS32_PC = 37, @@ -73,6 +214,30 @@ enum { MIPS32NUMCOREREGS }; +/* offsets into mips32 core register cache */ + +#define MIPS32_REG_GP_COUNT 34 +#define MIPS32_REG_FP_COUNT 32 +#define MIPS32_REG_FPC_COUNT 2 +#define MIPS32_REG_C0_COUNT 5 + +#define MIPS32_REGLIST_GP_INDEX 0 +#define MIPS32_REGLIST_FP_INDEX (MIPS32_REGLIST_GP_INDEX + MIPS32_REG_GP_COUNT) +#define MIPS32_REGLIST_FPC_INDEX (MIPS32_REGLIST_FP_INDEX + MIPS32_REG_FP_COUNT) +#define MIPS32_REGLIST_C0_INDEX (MIPS32_REGLIST_FPC_INDEX + MIPS32_REG_FPC_COUNT) + +#define MIPS32_REGLIST_C0_STATUS_INDEX (MIPS32_REGLIST_C0_INDEX + 0) +#define MIPS32_REGLIST_C0_BADVADDR_INDEX (MIPS32_REGLIST_C0_INDEX + 1) +#define MIPS32_REGLIST_C0_CAUSE_INDEX (MIPS32_REGLIST_C0_INDEX + 2) +#define MIPS32_REGLIST_C0_PC_INDEX (MIPS32_REGLIST_C0_INDEX + 3) +#define MIPS32_REGLIST_C0_GUESTCTL1_INDEX (MIPS32_REGLIST_C0_INDEX + 4) + +#define MIPS32_REG_C0_STATUS_INDEX 0 +#define MIPS32_REG_C0_BADVADDR_INDEX 1 +#define MIPS32_REG_C0_CAUSE_INDEX 2 +#define MIPS32_REG_C0_PC_INDEX 3 +#define MIPS32_REG_C0_GUESTCTL1_INDEX 4 + enum mips32_isa_mode { MIPS32_ISA_MIPS32 = 0, MIPS32_ISA_MIPS16E = 1, @@ -86,20 +251,169 @@ enum mips32_isa_imp { MIPS32_MMIPS32 = 3, }; +/* Release 2~5 does not have much change regarding to the ISA under User mode, +* therefore no new Architecture Revision(AR) level is assigned to them. +* Release 6 changed some instruction's encoding/mnemonic, removed instructions that +* has lost its purposes/none are using, and added some new instructions as well. +*/ +enum mips32_isa_rel { + MIPS32_RELEASE_1 = 0, + MIPS32_RELEASE_2 = 1, + MIPS32_RELEASE_6 = 2, + MIPS32_RELEASE_UNKNOWN, +}; + +enum mips32_isa_supported { + MIPS16, + MIPS32, + MIPS64, + MICROMIPS_ONLY, + MIPS32_AT_RESET_AND_MICROMIPS, + MICROMIPS_AT_RESET_AND_MIPS32, +}; +#define MIPS32_CORE_MASK 0xFFFFFF00 +#define MIPS32_VARIANT_MASK 0x00FF + +/* This struct contains mips cpu types with their name respectively. + * The PrID register format is as following: + * - Company Optionsp[31:24] + * - Company ID[23:16] + * - Processor ID[15:8] + * - Revision[7:0] + * Here the revision field represents the maximum value of revision. + */ +static const struct cpu_entry { + uint32_t prid; + enum mips32_isa_supported isa; + const char *vendor; + const char *cpu_name; +} mips32_cpu_entry[] = { + /* MIPS Technologies cores */ + {0x000180FF, MIPS32, "MIPS", "4Kc"}, + {0x000181FF, MIPS64, "MIPS", "5Kc"}, + {0x000182FF, MIPS64, "MIPS", "20Kc"}, + {0x000183FF, MIPS32, "MIPS", "4KM"}, + + {0x000184FF, MIPS32, "MIPS", "4KEc"}, + {0x000190FF, MIPS32, "MIPS", "4KEc"}, + + {0x000185FF, MIPS32, "MIPS", "4KEm"}, + {0x000191FF, MIPS32, "MIPS", "4KEm"}, + + {0x000186FF, MIPS32, "MIPS", "4KSc"}, + {0x000187FF, MIPS32, "MIPS", "M4K"}, + {0x000188FF, MIPS64, "MIPS", "25Kf"}, + {0x000189FF, MIPS64, "MIPS", "5KEc"}, + {0x000192FF, MIPS32, "MIPS", "4KSD"}, + {0x000193FF, MIPS32, "MIPS", "24Kc"}, + {0x000195FF, MIPS32, "MIPS", "34Kc"}, + {0x000196FF, MIPS32, "MIPS", "24KEc"}, + {0x000197FF, MIPS32, "MIPS", "74Kc"}, + {0x000199FF, MIPS32, "MIPS", "1004Kc"}, + {0x00019AFF, MIPS32, "MIPS", "1074Kc"}, + {0x00019BFF, MIPS32, "MIPS", "M14K"}, + {0x00019CFF, MIPS32, "MIPS", "M14Kc"}, + {0x00019DFF, MIPS32, "MIPS", "microAptiv_UC(M14KE)"}, + {0x00019EFF, MIPS32, "MIPS", "microAptiv_UP(M14KEc)"}, + {0x0001A0FF, MIPS32, "MIPS", "interAptiv"}, + {0x0001A1FF, MIPS32, "MIPS", "interAptiv_CM"}, + {0x0001A2FF, MIPS32, "MIPS", "proAptiv"}, + {0x0001A3FF, MIPS32, "MIPS", "proAptiv_CM"}, + {0x0001A6FF, MIPS32, "MIPS", "M5100"}, + {0x0001A7FF, MIPS32, "MIPS", "M5150"}, + {0x0001A8FF, MIPS32, "MIPS", "P5600"}, + {0x0001A9FF, MIPS32, "MIPS", "I5500"}, + + /* Broadcom */ + {0x000200FF, MIPS32, "Broadcom", "Broadcom"}, + + /* AMD Alchemy Series*/ + /* NOTE: AMD/Alchemy series uses Company Option instead of + * Processor ID, to match the find function, Processor ID field + * is the copy of Company Option field */ + {0x000300FF, MIPS32, "AMD Alchemy", "AU1000"}, + {0x010301FF, MIPS32, "AMD Alchemy", "AU1500"}, + {0x020302FF, MIPS32, "AMD Alchemy", "AU1100"}, + {0x030303FF, MIPS32, "AMD Alchemy", "AU1550"}, + {0x04030401, MIPS32, "AMD Alchemy", "AU1200"}, + {0x040304FF, MIPS32, "AMD Alchemy", "AU1250"}, + {0x050305FF, MIPS32, "AMD Alchemy", "AU1210"}, + + /* Altera */ + {0x001000FF, MIPS32, "Altera", "Altera"}, + + /* Lexra */ + {0x000B00FF, MIPS32, "Lexra", "Lexra"}, + + /* Ingenic */ + {0x00e102FF, MIPS32, "Ingenic", "Ingenic XBurst rev1"}, + + {0xFFFFFFFF, MIPS32, "Unknown", "Unknown"} +}; + +#define MIPS32_NUM_CPU_ENTRIES (ARRAY_SIZE(mips32_cpu_entry)) + +enum mips32_fp_imp { + MIPS32_FP_IMP_NONE = 0, + MIPS32_FP_IMP_32 = 1, + MIPS32_FP_IMP_64 = 2, + MIPS32_FP_IMP_UNKNOWN = 3, +}; + +enum mips32_dsp_imp { + MIPS32_DSP_IMP_NONE = 0, + MIPS32_DSP_IMP_REV1 = 1, + MIPS32_DSP_IMP_REV2 = 2, +}; + struct mips32_comparator { int used; uint32_t bp_value; uint32_t reg_address; }; +struct mips32_core_regs { + uint32_t gpr[MIPS32_REG_GP_COUNT]; + uint64_t fpr[MIPS32_REG_FP_COUNT]; + uint32_t fpcr[MIPS32_REG_FPC_COUNT]; + uint32_t cp0[MIPS32_REG_C0_COUNT]; +}; + struct mips32_common { - uint32_t common_magic; + unsigned int common_magic; + void *arch_info; struct reg_cache *core_cache; struct mips_ejtag ejtag_info; - uint32_t core_regs[MIPS32NUMCOREREGS]; + + struct mips32_core_regs core_regs; + enum mips32_isa_mode isa_mode; enum mips32_isa_imp isa_imp; + enum mips32_isa_rel isa_rel; + enum mips32_fp_imp fp_imp; + enum mips32_dsp_imp dsp_imp; + + int fdc; + int semihosting; + + /* The cp0 registers implemented on different processor cores could be different, too. + * Here you can see most of the registers are implemented on interAptiv, which is + * a 2c4t SMP processor, it has more features than M-class processors, like vpe + * and other config registers for multhreading. */ + uint32_t cp0_mask; + + /* FPU enabled (cp0.status.cu1) */ + bool fpu_enabled; + /* FPU mode (cp0.status.fr) */ + bool fpu_in_64bit; + + /* processor identification register */ + uint32_t prid; + /* detected CPU type */ + const struct cpu_entry *cpu_info; + /* CPU specific quirks */ + uint32_t cpu_quirks; /* working area for fastdata access */ struct working_area *fast_data_area; @@ -130,7 +444,7 @@ struct mips32_core_reg { }; struct mips32_algorithm { - int common_magic; + unsigned int common_magic; enum mips32_isa_mode isa_mode; }; @@ -140,6 +454,7 @@ struct mips32_algorithm { #define MIPS32_OP_BEQ 0x04u #define MIPS32_OP_BGTZ 0x07u #define MIPS32_OP_BNE 0x05u +#define MIPS32_OP_ADD 0x20u #define MIPS32_OP_ADDI 0x08u #define MIPS32_OP_AND 0x24u #define MIPS32_OP_CACHE 0x2Fu @@ -163,9 +478,11 @@ struct mips32_algorithm { #define MIPS32_OP_XORI 0x0Eu #define MIPS32_OP_XOR 0x26u #define MIPS32_OP_SLTU 0x2Bu -#define MIPS32_OP_SRL 0x03u +#define MIPS32_OP_SRL 0x02u +#define MIPS32_OP_SRA 0x03u #define MIPS32_OP_SYNCI 0x1Fu #define MIPS32_OP_SLL 0x00u +#define MIPS32_OP_SLLV 0x04u #define MIPS32_OP_SLTI 0x0Au #define MIPS32_OP_MOVN 0x0Bu @@ -175,8 +492,11 @@ struct mips32_algorithm { #define MIPS32_OP_SPECIAL2 0x07u #define MIPS32_OP_SPECIAL3 0x1Fu -#define MIPS32_COP0_MF 0x00u -#define MIPS32_COP0_MT 0x04u +#define MIPS32_COP_MF 0x00u +#define MIPS32_COP_CF 0x02u +#define MIPS32_COP_MFH 0x03u +#define MIPS32_COP_MT 0x04u +#define MIPS32_COP_MTH 0x07u #define MIPS32_R_INST(opcode, rs, rt, rd, shamt, funct) \ (((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | ((rd) << 11) | ((shamt) << 6) | (funct)) @@ -185,6 +505,7 @@ struct mips32_algorithm { #define MIPS32_J_INST(opcode, addr) (((opcode) << 26) | (addr)) #define MIPS32_ISA_NOP 0 +#define MIPS32_ISA_ADD(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_ADD) #define MIPS32_ISA_ADDI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ADDI, src, tar, val) #define MIPS32_ISA_ADDIU(tar, src, val) MIPS32_I_INST(MIPS32_OP_ADDIU, src, tar, val) #define MIPS32_ISA_ADDU(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_ADDU) @@ -198,6 +519,7 @@ struct mips32_algorithm { #define MIPS32_ISA_CACHE(op, off, base) MIPS32_I_INST(MIPS32_OP_CACHE, base, op, off) #define MIPS32_ISA_J(tar) MIPS32_J_INST(MIPS32_OP_J, (0x0FFFFFFFu & (tar)) >> 2) #define MIPS32_ISA_JR(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_JR) +#define MIPS32_ISA_JRHB(reg) MIPS32_R_INST(0, reg, 0, 0, 0x10, MIPS32_OP_JR) #define MIPS32_ISA_LB(reg, off, base) MIPS32_I_INST(MIPS32_OP_LB, base, reg, off) #define MIPS32_ISA_LBU(reg, off, base) MIPS32_I_INST(MIPS32_OP_LBU, base, reg, off) @@ -205,14 +527,16 @@ struct mips32_algorithm { #define MIPS32_ISA_LUI(reg, val) MIPS32_I_INST(MIPS32_OP_LUI, 0, reg, val) #define MIPS32_ISA_LW(reg, off, base) MIPS32_I_INST(MIPS32_OP_LW, base, reg, off) -#define MIPS32_ISA_MFC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MF, gpr, cpr, 0, sel) -#define MIPS32_ISA_MTC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MT, gpr, cpr, 0, sel) +#define MIPS32_ISA_MFC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP_MF, gpr, cpr, 0, sel) +#define MIPS32_ISA_MTC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP_MT, gpr, cpr, 0, sel) #define MIPS32_ISA_MFLO(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFLO) #define MIPS32_ISA_MFHI(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFHI) #define MIPS32_ISA_MTLO(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTLO) #define MIPS32_ISA_MTHI(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTHI) +#define MIPS32_ISA_MUL(dst, src, t) MIPS32_R_INST(28, src, t, dst, 0, MIPS32_OP_MUL) #define MIPS32_ISA_MOVN(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_MOVN) +#define MIPS32_ISA_OR(dst, src, val) MIPS32_R_INST(0, src, val, dst, 0, 37) #define MIPS32_ISA_ORI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ORI, src, tar, val) #define MIPS32_ISA_RDHWR(tar, dst) MIPS32_R_INST(MIPS32_OP_SPECIAL3, 0, tar, dst, 0, MIPS32_OP_RDHWR) #define MIPS32_ISA_SB(reg, off, base) MIPS32_I_INST(MIPS32_OP_SB, base, reg, off) @@ -220,9 +544,11 @@ struct mips32_algorithm { #define MIPS32_ISA_SW(reg, off, base) MIPS32_I_INST(MIPS32_OP_SW, base, reg, off) #define MIPS32_ISA_SLL(dst, src, sa) MIPS32_R_INST(MIPS32_OP_SPECIAL, 0, src, dst, sa, MIPS32_OP_SLL) +#define MIPS32_ISA_SLLV(dst, src, sa) MIPS32_R_INST(MIPS32_OP_SPECIAL, 0, src, dst, sa, MIPS32_OP_SLLV) #define MIPS32_ISA_SLTI(tar, src, val) MIPS32_I_INST(MIPS32_OP_SLTI, src, tar, val) #define MIPS32_ISA_SLTU(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_SLTU) -#define MIPS32_ISA_SRL(reg, src, off) MIPS32_R_INST(0, 0, src, reg, off, MIPS32_OP_SRL) +#define MIPS32_ISA_SRA(reg, src, off) MIPS32_R_INST(MIPS32_OP_SPECIAL, 0, src, reg, off, MIPS32_OP_SRA) +#define MIPS32_ISA_SRL(reg, src, off) MIPS32_R_INST(MIPS32_OP_SPECIAL, 0, src, reg, off, MIPS32_OP_SRL) #define MIPS32_ISA_SYNC 0xFu #define MIPS32_ISA_SYNCI(off, base) MIPS32_I_INST(MIPS32_OP_REGIMM, base, MIPS32_OP_SYNCI, off) @@ -247,10 +573,12 @@ struct mips32_algorithm { #define MIPS16_ISA_SDBBP 0xE801u /*MICRO MIPS INSTRUCTIONS, see doc MD00582 */ -#define POOL32A 0X00u -#define POOL32AXF 0x3Cu -#define POOL32B 0x08u -#define POOL32I 0x10u +#define MMIPS32_POOL32A 0x00u +#define MMIPS32_POOL32F 0x15u +#define MMIPS32_POOL32FXF 0x3Bu +#define MMIPS32_POOL32AXF 0x3Cu +#define MMIPS32_POOL32B 0x08u +#define MMIPS32_POOL32I 0x10u #define MMIPS32_OP_ADDI 0x04u #define MMIPS32_OP_ADDIU 0x0Cu #define MMIPS32_OP_ADDU 0x150u @@ -262,6 +590,7 @@ struct mips32_algorithm { #define MMIPS32_OP_CACHE 0x06u #define MMIPS32_OP_J 0x35u #define MMIPS32_OP_JALR 0x03Cu +#define MMIPS32_OP_JALRHB 0x07Cu #define MMIPS32_OP_LB 0x07u #define MMIPS32_OP_LBU 0x05u #define MMIPS32_OP_LHU 0x0Du @@ -289,55 +618,59 @@ struct mips32_algorithm { #define MMIPS32_ADDI(tar, src, val) MIPS32_I_INST(MMIPS32_OP_ADDI, tar, src, val) #define MMIPS32_ADDIU(tar, src, val) MIPS32_I_INST(MMIPS32_OP_ADDIU, tar, src, val) -#define MMIPS32_ADDU(dst, src, tar) MIPS32_R_INST(POOL32A, tar, src, dst, 0, MMIPS32_OP_ADDU) -#define MMIPS32_AND(dst, src, tar) MIPS32_R_INST(POOL32A, tar, src, dst, 0, MMIPS32_OP_AND) +#define MMIPS32_ADDU(dst, src, tar) MIPS32_R_INST(MMIPS32_POOL32A, tar, src, dst, 0, MMIPS32_OP_ADDU) +#define MMIPS32_AND(dst, src, tar) MIPS32_R_INST(MMIPS32_POOL32A, tar, src, dst, 0, MMIPS32_OP_AND) #define MMIPS32_ANDI(tar, src, val) MIPS32_I_INST(MMIPS32_OP_ANDI, tar, src, val) #define MMIPS32_B(off) MMIPS32_BEQ(0, 0, off) #define MMIPS32_BEQ(src, tar, off) MIPS32_I_INST(MMIPS32_OP_BEQ, tar, src, off) -#define MMIPS32_BGTZ(reg, off) MIPS32_I_INST(POOL32I, MMIPS32_OP_BGTZ, reg, off) +#define MMIPS32_BGTZ(reg, off) MIPS32_I_INST(MMIPS32_POOL32I, MMIPS32_OP_BGTZ, reg, off) #define MMIPS32_BNE(src, tar, off) MIPS32_I_INST(MMIPS32_OP_BNE, tar, src, off) -#define MMIPS32_CACHE(op, off, base) MIPS32_R_INST(POOL32B, op, base, MMIPS32_OP_CACHE << 1, 0, off) +#define MMIPS32_CACHE(op, off, base) MIPS32_R_INST(MMIPS32_POOL32B, op, base, MMIPS32_OP_CACHE << 1, 0, off) #define MMIPS32_J(tar) MIPS32_J_INST(MMIPS32_OP_J, ((0x07FFFFFFu & ((tar) >> 1)))) -#define MMIPS32_JR(reg) MIPS32_R_INST(POOL32A, 0, reg, 0, MMIPS32_OP_JALR, POOL32AXF) +#define MMIPS32_JR(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_JALR, MMIPS32_POOL32AXF) +#define MMIPS32_JRHB(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_JALRHB, MMIPS32_POOL32AXF) #define MMIPS32_LB(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LB, reg, base, off) #define MMIPS32_LBU(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LBU, reg, base, off) #define MMIPS32_LHU(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LHU, reg, base, off) -#define MMIPS32_LUI(reg, val) MIPS32_I_INST(POOL32I, MMIPS32_OP_LUI, reg, val) +#define MMIPS32_LUI(reg, val) MIPS32_I_INST(MMIPS32_POOL32I, MMIPS32_OP_LUI, reg, val) #define MMIPS32_LW(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LW, reg, base, off) -#define MMIPS32_MFC0(gpr, cpr, sel) MIPS32_R_INST(POOL32A, gpr, cpr, sel, MMIPS32_OP_MFC0, POOL32AXF) -#define MMIPS32_MFLO(reg) MIPS32_R_INST(POOL32A, 0, reg, 0, MMIPS32_OP_MFLO, POOL32AXF) -#define MMIPS32_MFHI(reg) MIPS32_R_INST(POOL32A, 0, reg, 0, MMIPS32_OP_MFHI, POOL32AXF) -#define MMIPS32_MTC0(gpr, cpr, sel) MIPS32_R_INST(POOL32A, gpr, cpr, sel, MMIPS32_OP_MTC0, POOL32AXF) -#define MMIPS32_MTLO(reg) MIPS32_R_INST(POOL32A, 0, reg, 0, MMIPS32_OP_MTLO, POOL32AXF) -#define MMIPS32_MTHI(reg) MIPS32_R_INST(POOL32A, 0, reg, 0, MMIPS32_OP_MTHI, POOL32AXF) +#define MMIPS32_MFC0(gpr, cpr, sel) MIPS32_R_INST(MMIPS32_POOL32A, gpr, cpr, sel,\ + MMIPS32_OP_MFC0, MMIPS32_POOL32AXF) +#define MMIPS32_MFLO(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_MFLO, MMIPS32_POOL32AXF) +#define MMIPS32_MFHI(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_MFHI, MMIPS32_POOL32AXF) +#define MMIPS32_MTC0(gpr, cpr, sel) MIPS32_R_INST(MMIPS32_POOL32A, gpr, cpr, sel,\ + MMIPS32_OP_MTC0, MMIPS32_POOL32AXF) +#define MMIPS32_MTLO(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_MTLO, MMIPS32_POOL32AXF) +#define MMIPS32_MTHI(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_MTHI, MMIPS32_POOL32AXF) -#define MMIPS32_MOVN(dst, src, tar) MIPS32_R_INST(POOL32A, tar, src, dst, 0, MMIPS32_OP_MOVN) +#define MMIPS32_MOVN(dst, src, tar) MIPS32_R_INST(MMIPS32_POOL32A, tar, src, dst, 0, MMIPS32_OP_MOVN) #define MMIPS32_NOP 0 #define MMIPS32_ORI(tar, src, val) MIPS32_I_INST(MMIPS32_OP_ORI, tar, src, val) -#define MMIPS32_RDHWR(tar, dst) MIPS32_R_INST(POOL32A, dst, tar, 0, MMIPS32_OP_RDHWR, POOL32AXF) +#define MMIPS32_RDHWR(tar, dst) MIPS32_R_INST(MMIPS32_POOL32A, dst, tar, 0, MMIPS32_OP_RDHWR, MMIPS32_POOL32AXF) #define MMIPS32_SB(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SB, reg, base, off) #define MMIPS32_SH(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SH, reg, base, off) #define MMIPS32_SW(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SW, reg, base, off) -#define MMIPS32_SRL(reg, src, off) MIPS32_R_INST(POOL32A, reg, src, off, 0, MMIPS32_OP_SRL) -#define MMIPS32_SLTU(dst, src, tar) MIPS32_R_INST(POOL32A, tar, src, dst, 0, MMIPS32_OP_SLTU) -#define MMIPS32_SYNCI(off, base) MIPS32_I_INST(POOL32I, MMIPS32_OP_SYNCI, base, off) -#define MMIPS32_SLL(dst, src, sa) MIPS32_R_INST(POOL32A, dst, src, sa, 0, MMIPS32_OP_SLL) +#define MMIPS32_SRL(reg, src, off) MIPS32_R_INST(MMIPS32_POOL32A, reg, src, off, 0, MMIPS32_OP_SRL) +#define MMIPS32_SLTU(dst, src, tar) MIPS32_R_INST(MMIPS32_POOL32A, tar, src, dst, 0, MMIPS32_OP_SLTU) +#define MMIPS32_SYNCI(off, base) MIPS32_I_INST(MMIPS32_POOL32I, MMIPS32_OP_SYNCI, base, off) +#define MMIPS32_SLL(dst, src, sa) MIPS32_R_INST(MMIPS32_POOL32A, dst, src, sa, 0, MMIPS32_OP_SLL) +#define MMIPS32_SLLV(dst, src, sa) MIPS32_R_INST(MMIPS32_POOL32A, dst, src, sa, 0, MMIPS32_OP_SLLV) #define MMIPS32_SLTI(tar, src, val) MIPS32_I_INST(MMIPS32_OP_SLTI, tar, src, val) -#define MMIPS32_SYNC 0x00001A7Cu /* MIPS32_R_INST(POOL32A, 0, 0, 0, 0x1ADu, POOL32AXF) */ +#define MMIPS32_SYNC 0x00001A7Cu /* MIPS32_R_INST(MMIPS32_POOL32A, 0, 0, 0, 0x1ADu, MMIPS32_POOL32AXF) */ -#define MMIPS32_XOR(reg, val1, val2) MIPS32_R_INST(POOL32A, val1, val2, reg, 0, MMIPS32_OP_XOR) +#define MMIPS32_XOR(reg, val1, val2) MIPS32_R_INST(MMIPS32_POOL32A, val1, val2, reg, 0, MMIPS32_OP_XOR) #define MMIPS32_XORI(tar, src, val) MIPS32_I_INST(MMIPS32_OP_XORI, tar, src, val) #define MMIPS32_SYNCI_STEP 0x1u /* reg num od address step size to be used with synci instruction */ /* ejtag specific instructions */ -#define MMIPS32_DRET 0x0000E37Cu /* MIPS32_R_INST(POOL32A, 0, 0, 0, 0x38D, POOL32AXF) */ -#define MMIPS32_SDBBP 0x0000DB7Cu /* MIPS32_R_INST(POOL32A, 0, 0, 0, 0x1BD, POOL32AXF) */ +#define MMIPS32_DRET 0x0000E37Cu /* MIPS32_R_INST(MMIPS32_POOL32A, 0, 0, 0, 0x38D, MMIPS32_POOL32AXF) */ +#define MMIPS32_SDBBP 0x0000DB7Cu /* MIPS32_R_INST(MMIPS32_POOL32A, 0, 0, 0, 0x1BD, MMIPS32_POOL32AXF) */ #define MMIPS16_SDBBP 0x46C0u /* POOL16C instr */ /* instruction code with isa selection */ @@ -356,6 +689,7 @@ struct mips32_algorithm { #define MIPS32_J(isa, tar) (isa ? MMIPS32_J(tar) : MIPS32_ISA_J(tar)) #define MIPS32_JR(isa, reg) (isa ? MMIPS32_JR(reg) : MIPS32_ISA_JR(reg)) +#define MIPS32_JRHB(isa, reg) (isa ? MMIPS32_JRHB(reg) : MIPS32_ISA_JRHB(reg)) #define MIPS32_LB(isa, reg, off, base) (isa ? MMIPS32_LB(reg, off, base) : MIPS32_ISA_LB(reg, off, base)) #define MIPS32_LBU(isa, reg, off, base) (isa ? MMIPS32_LBU(reg, off, base) : MIPS32_ISA_LBU(reg, off, base)) #define MIPS32_LHU(isa, reg, off, base) (isa ? MMIPS32_LHU(reg, off, base) : MIPS32_ISA_LHU(reg, off, base)) @@ -369,6 +703,7 @@ struct mips32_algorithm { #define MIPS32_MTLO(isa, reg) (isa ? MMIPS32_MTLO(reg) : MIPS32_ISA_MTLO(reg)) #define MIPS32_MTHI(isa, reg) (isa ? MMIPS32_MTHI(reg) : MIPS32_ISA_MTHI(reg)) +#define MIPS32_MUL(isa, dst, src, t) (MIPS32_ISA_MUL(dst, src, t)) #define MIPS32_MOVN(isa, dst, src, tar) (isa ? MMIPS32_MOVN(dst, src, tar) : MIPS32_ISA_MOVN(dst, src, tar)) #define MIPS32_ORI(isa, tar, src, val) (isa ? MMIPS32_ORI(tar, src, val) : MIPS32_ISA_ORI(tar, src, val)) #define MIPS32_RDHWR(isa, tar, dst) (isa ? MMIPS32_RDHWR(tar, dst) : MIPS32_ISA_RDHWR(tar, dst)) @@ -377,6 +712,8 @@ struct mips32_algorithm { #define MIPS32_SW(isa, reg, off, base) (isa ? MMIPS32_SW(reg, off, base) : MIPS32_ISA_SW(reg, off, base)) #define MIPS32_SLL(isa, dst, src, sa) (isa ? MMIPS32_SLL(dst, src, sa) : MIPS32_ISA_SLL(dst, src, sa)) +#define MIPS32_EHB(isa) (isa ? MMIPS32_SLL(0, 0, 3) : MIPS32_ISA_SLL(0, 0, 3)) +#define MIPS32_SLLV(isa, dst, src, sa) (MIPS32_ISA_SLLV(dst, src, sa)) #define MIPS32_SLTI(isa, tar, src, val) (isa ? MMIPS32_SLTI(tar, src, val) : MIPS32_ISA_SLTI(tar, src, val)) #define MIPS32_SLTU(isa, dst, src, tar) (isa ? MMIPS32_SLTU(dst, src, tar) : MIPS32_ISA_SLTU(dst, src, tar)) #define MIPS32_SRL(isa, reg, src, off) (isa ? MMIPS32_SRL(reg, src, off) : MIPS32_ISA_SRL(reg, src, off)) @@ -394,6 +731,104 @@ struct mips32_algorithm { #define MIPS16_SDBBP(isa) (isa ? MMIPS16_SDBBP : MIPS16_ISA_SDBBP) +/* ejtag specific instructions */ +#define MICRO_MIPS32_SDBBP 0x000046C0 +#define MICRO_MIPS_SDBBP 0x46C0 +/* + * MIPS32 Config1 Register (CP0 Register 16, Select 1) + */ +#define MIPS32_CFG1_M 0x80000000 /* Config2 implemented */ +#define MIPS32_CFG1_MMUSMASK 0x7e000000 /* mmu size - 1 */ +#define MIPS32_CFG1_MMUSSHIFT 25 +#define MIPS32_CFG1_ISMASK 0x01c00000 /* icache lines 64<<n */ +#define MIPS32_CFG1_ISSHIFT 22 +#define MIPS32_CFG1_ILMASK 0x00380000 /* icache line size 2<<n */ +#define MIPS32_CFG1_ILSHIFT 19 +#define MIPS32_CFG1_IAMASK 0x00070000 /* icache ways - 1 */ +#define MIPS32_CFG1_IASHIFT 16 +#define MIPS32_CFG1_DSMASK 0x0000e000 /* dcache lines 64<<n */ +#define MIPS32_CFG1_DSSHIFT 13 +#define MIPS32_CFG1_DLMASK 0x00001c00 /* dcache line size 2<<n */ +#define MIPS32_CFG1_DLSHIFT 10 +#define MIPS32_CFG1_DAMASK 0x00000380 /* dcache ways - 1 */ +#define MIPS32_CFG1_DASHIFT 7 +#define MIPS32_CFG1_C2 0x00000040 /* Coprocessor 2 present */ +#define MIPS32_CFG1_MD 0x00000020 /* MDMX implemented */ +#define MIPS32_CFG1_PC 0x00000010 /* performance counters implemented */ +#define MIPS32_CFG1_WR 0x00000008 /* watch registers implemented */ +#define MIPS32_CFG1_CA 0x00000004 /* compression (mips16) implemented */ +#define MIPS32_CFG1_EP 0x00000002 /* ejtag implemented */ +#define MIPS32_CFG1_FP 0x00000001 /* fpu implemented */ + +/* + * MIPS32 Coprocessor 0 register numbers + */ +#define MIPS32_C0_INDEX 0 +#define MIPS32_C0_INX 0 +#define MIPS32_C0_RANDOM 1 +#define MIPS32_C0_RAND 1 +#define MIPS32_C0_ENTRYLO0 2 +#define MIPS32_C0_TLBLO0 2 +#define MIPS32_C0_ENTRYLO1 3 +#define MIPS32_C0_TLBLO1 3 +#define MIPS32_C0_CONTEXT 4 +#define MIPS32_C0_CTXT 4 +#define MIPS32_C0_PAGEMASK 5 +#define MIPS32_C0_PAGEGRAIN (5, 1) +#define MIPS32_C0_WIRED 6 +#define MIPS32_C0_HWRENA 7 +#define MIPS32_C0_BADVADDR 8 +#define MIPS32_C0_VADDR 8 +#define MIPS32_C0_COUNT 9 +#define MIPS32_C0_ENTRYHI 10 +#define MIPS32_C0_TLBHI 10 +#define MIPS32_C0_GUESTCTL1 10 +#define MIPS32_C0_COMPARE 11 +#define MIPS32_C0_STATUS 12 +#define MIPS32_C0_SR 12 +#define MIPS32_C0_INTCTL (12, 1) +#define MIPS32_C0_SRSCTL (12, 2) +#define MIPS32_C0_SRSMAP (12, 3) +#define MIPS32_C0_CAUSE 13 +#define MIPS32_C0_CR 13 +#define MIPS32_C0_EPC 14 +#define MIPS32_C0_PRID 15 +#define MIPS32_C0_EBASE (15, 1) +#define MIPS32_C0_CONFIG 16 +#define MIPS32_C0_CONFIG0 (16, 0) +#define MIPS32_C0_CONFIG1 (16, 1) +#define MIPS32_C0_CONFIG2 (16, 2) +#define MIPS32_C0_CONFIG3 (16, 3) +#define MIPS32_C0_LLADDR 17 +#define MIPS32_C0_WATCHLO 18 +#define MIPS32_C0_WATCHHI 19 +#define MIPS32_C0_DEBUG 23 +#define MIPS32_C0_DEPC 24 +#define MIPS32_C0_PERFCNT 25 +#define MIPS32_C0_ERRCTL 26 +#define MIPS32_C0_CACHEERR 27 +#define MIPS32_C0_TAGLO 28 +#define MIPS32_C0_ITAGLO 28 +#define MIPS32_C0_DTAGLO (28, 2) +#define MIPS32_C0_TAGLO2 (28, 4) +#define MIPS32_C0_DATALO (28, 1) +#define MIPS32_C0_IDATALO (28, 1) +#define MIPS32_C0_DDATALO (28, 3) +#define MIPS32_C0_DATALO2 (28, 5) +#define MIPS32_C0_TAGHI 29 +#define MIPS32_C0_ITAGHI 29 +#define MIPS32_C0_DATAHI (29, 1) +#define MIPS32_C0_ERRPC 30 +#define MIPS32_C0_DESAVE 31 + +/* + * MIPS32 MMU types + */ +#define MIPS32_MMU_TLB 1 +#define MIPS32_MMU_BAT 2 +#define MIPS32_MMU_FIXED 3 +#define MIPS32_MMU_DUAL_VTLB_FTLB 4 + extern const struct command_registration mips32_command_handlers[]; int mips32_arch_state(struct target *target); @@ -410,7 +845,7 @@ int mips32_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, - int timeout_ms, void *arch_info); + unsigned int timeout_ms, void *arch_info); int mips32_configure_break_unit(struct target *target); @@ -418,6 +853,8 @@ int mips32_enable_interrupts(struct target *target, int enable); int mips32_examine(struct target *target); +int mips32_cpu_probe(struct target *target); + int mips32_read_config_regs(struct target *target); int mips32_register_commands(struct command_context *cmd_ctx); @@ -430,4 +867,7 @@ int mips32_checksum_memory(struct target *target, target_addr_t address, int mips32_blank_check_memory(struct target *target, struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value); +bool mips32_cpu_support_sync(struct mips_ejtag *ejtag_info); +bool mips32_cpu_support_hazard_barrier(struct mips_ejtag *ejtag_info); + #endif /* OPENOCD_TARGET_MIPS32_H */ diff --git a/src/target/mips32_dmaacc.c b/src/target/mips32_dmaacc.c index 220ea94f92..beffbf51ee 100644 --- a/src/target/mips32_dmaacc.c +++ b/src/target/mips32_dmaacc.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2008 by John McCarthy * * jgmcc@magma.ca * @@ -6,19 +8,6 @@ * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/mips32_dmaacc.h b/src/target/mips32_dmaacc.h index 70fe2a77ea..172594154c 100644 --- a/src/target/mips32_dmaacc.h +++ b/src/target/mips32_dmaacc.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2008 by John McCarthy * * jgmcc@magma.ca * @@ -6,19 +8,6 @@ * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_MIPS32_DMAACC_H diff --git a/src/target/mips32_pracc.c b/src/target/mips32_pracc.c index 9f8762e349..22edf6a410 100644 --- a/src/target/mips32_pracc.c +++ b/src/target/mips32_pracc.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * @@ -8,19 +10,6 @@ * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * - * * - * 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/>. * ***************************************************************************/ /* @@ -72,6 +61,7 @@ #include <helper/time_support.h> #include <jtag/adapter.h> +#include "mips_cpu.h" #include "mips32.h" #include "mips32_pracc.h" @@ -161,7 +151,7 @@ static int mips32_pracc_clean_text_jump(struct mips_ejtag *ejtag_info) return ERROR_OK; } -int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx, +static int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx, uint32_t *param_out, bool check_last) { int code_count = 0; @@ -334,7 +324,7 @@ void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr) ctx->store_count++; } -void pracc_add_li32(struct pracc_queue_info *ctx, uint32_t reg_num, uint32_t data, bool optimize) +static void pracc_add_li32(struct pracc_queue_info *ctx, uint32_t reg_num, uint32_t data, bool optimize) { if (LOWER16(data) == 0 && optimize) pracc_add(ctx, 0, MIPS32_LUI(ctx->isa, reg_num, UPPER16(data))); /* load only upper value */ @@ -463,6 +453,8 @@ static int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, u pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 8, UPPER16((addr + 0x8000)))); /* load $8 with modified upper addr */ pracc_add(&ctx, 0, MIPS32_LW(ctx.isa, 8, LOWER16(addr), 8)); /* lw $8, LOWER16(addr)($8) */ + if (mips32_cpu_support_sync(ejtag_info)) + pracc_add(&ctx, 0, MIPS32_SYNC(ctx.isa)); pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET, 15)); /* sw $8,PRACC_OUT_OFFSET($15) */ pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */ @@ -519,6 +511,8 @@ int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size else pracc_add(&ctx, 0, MIPS32_LBU(ctx.isa, 8, LOWER16(addr), 9)); + if (mips32_cpu_support_sync(ejtag_info)) + pracc_add(&ctx, 0, MIPS32_SYNC(ctx.isa)); pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + i * 4, /* store $8 at param out */ MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + i * 4, 15)); addr += size; @@ -561,6 +555,8 @@ int mips32_cp0_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp0_r pracc_queue_init(&ctx); pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ + if (mips32_cpu_support_hazard_barrier(ejtag_info)) + pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa)); pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 8, cp0_reg, cp0_sel)); /* move cp0 reg / sel to $8 */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */ @@ -582,6 +578,8 @@ int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_r pracc_add_li32(&ctx, 15, val, 0); /* Load val to $15 */ pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, cp0_reg, cp0_sel)); /* write $15 to cp0 reg / sel */ + if (mips32_cpu_support_hazard_barrier(ejtag_info)) + pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa)); pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */ @@ -797,6 +795,7 @@ int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int siz if ((KSEGX(addr) == KSEG1) || ((addr >= 0xff200000) && (addr <= 0xff3fffff))) return retval; /*Nothing to do*/ + /* Reads Config0 */ mips32_cp0_read(ejtag_info, &conf, 16, 0); switch (KSEGX(addr)) { @@ -824,19 +823,40 @@ int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int siz uint32_t start_addr = addr; uint32_t end_addr = addr + count * size; uint32_t rel = (conf & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT; - if (rel > 1) { - LOG_DEBUG("Unknown release in cache code"); + /* FIXME: In MIPS Release 6, the encoding of CACHE instr has changed */ + if (rel > MIPS32_RELEASE_2) { + LOG_DEBUG("Unsupported MIPS Release ( > 5)"); return ERROR_FAIL; } retval = mips32_pracc_synchronize_cache(ejtag_info, start_addr, end_addr, cached, rel); + } else { + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; + + pracc_queue_init(&ctx); + if (mips32_cpu_support_sync(ejtag_info)) + pracc_add(&ctx, 0, MIPS32_SYNC(ctx.isa)); + if (mips32_cpu_support_hazard_barrier(ejtag_info)) + pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa)); + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ + pracc_add(&ctx, 0, MIPS32_NOP); + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); + if (ctx.retval != ERROR_OK) { + LOG_ERROR("Unable to barrier"); + retval = ctx.retval; + } + pracc_queue_free(&ctx); } return retval; } -int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs) +int mips32_pracc_write_regs(struct mips32_common *mips32) { + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; + uint32_t *gprs = mips32->core_regs.gpr; + uint32_t *c0rs = mips32->core_regs.cp0; + pracc_queue_init(&ctx); uint32_t cp0_write_code[] = { @@ -848,69 +868,250 @@ int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs) MIPS32_MTC0(ctx.isa, 1, 24, 0), /* move $1 to depc (pc) */ }; + uint32_t cp0_write_data[] = { + /* status */ + c0rs[0], + /* lo */ + gprs[32], + /* hi */ + gprs[33], + /* badvaddr */ + c0rs[1], + /* cause */ + c0rs[2], + /* depc (pc) */ + c0rs[3], + }; + + /* Write CP0 Status Register first, changes on EXL or ERL bits + * may lead to different behaviour on writing to other CP0 registers. + */ + for (size_t i = 0; i < ARRAY_SIZE(cp0_write_code); i++) { + /* load CP0 value in $1 */ + pracc_add_li32(&ctx, 1, cp0_write_data[i], 0); + /* write value from $1 to CP0 register */ + pracc_add(&ctx, 0, cp0_write_code[i]); + } + + if (mips32_cpu_support_hazard_barrier(ejtag_info)) + pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa)); /* load registers 2 to 31 with li32, optimize */ for (int i = 2; i < 32; i++) - pracc_add_li32(&ctx, i, regs[i], 1); + pracc_add_li32(&ctx, i, gprs[i], 1); - for (int i = 0; i != 6; i++) { - pracc_add_li32(&ctx, 1, regs[i + 32], 0); /* load CPO value in $1 */ - pracc_add(&ctx, 0, cp0_write_code[i]); /* write value from $1 to CPO register */ - } - pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); /* load $15 in DeSave */ - pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 1, UPPER16((regs[1])))); /* load upper half word in $1 */ - pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 1, 1, LOWER16((regs[1])))); /* load lower half word in $1 */ + /* load $15 in DeSave */ + pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); + /* load upper half word in $1 */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 1, UPPER16((gprs[1])))); + /* jump to start */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); + /* load lower half word in $1 */ + pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 1, 1, LOWER16((gprs[1])))); ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); - ejtag_info->reg8 = regs[8]; - ejtag_info->reg9 = regs[9]; + ejtag_info->reg8 = gprs[8]; + ejtag_info->reg9 = gprs[9]; pracc_queue_free(&ctx); return ctx.retval; } -int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs) +/* Saves content in `$1` to `DeSave(cp0.31.0)` and loads `MIPS32_PRACC_BASE_ADDR` into `$1` */ +static void mips32_pracc_store_regs_set_base_addr(struct pracc_queue_info *ctx) { - struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; - pracc_queue_init(&ctx); + /* move $1 to COP0 DeSave */ + pracc_add(ctx, 0, MIPS32_MTC0(ctx->isa, 1, 31, 0)); + /* $1 = MIP32_PRACC_BASE_ADDR */ + pracc_add(ctx, 0, MIPS32_LUI(ctx->isa, 1, PRACC_UPPER_BASE_ADDR)); +} - uint32_t cp0_read_code[] = { - MIPS32_MFC0(ctx.isa, 8, 12, 0), /* move status to $8 */ - MIPS32_MFLO(ctx.isa, 8), /* move lo to $8 */ - MIPS32_MFHI(ctx.isa, 8), /* move hi to $8 */ - MIPS32_MFC0(ctx.isa, 8, 8, 0), /* move badvaddr to $8 */ - MIPS32_MFC0(ctx.isa, 8, 13, 0), /* move cause to $8 */ - MIPS32_MFC0(ctx.isa, 8, 24, 0), /* move depc (pc) to $8 */ +/* This function assumes the address for saving is stored in `$1`. + * And that action is performed in `mips32_pracc_set_save_base_addr`. + */ +static void mips32_pracc_store_regs_gpr(struct pracc_queue_info *ctx, unsigned int offset_gpr) +{ + for (int i = 2; i != 32; i++) + pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + offset_gpr + (i * 4), + MIPS32_SW(ctx->isa, i, PRACC_OUT_OFFSET + offset_gpr + (i * 4), 1)); +} + +static void mips32_pracc_store_regs_lohi(struct pracc_queue_info *ctx) +{ + uint32_t lohi_read_code[] = { + MIPS32_MFLO(ctx->isa, 8), /* move lo to $8 */ + MIPS32_MFHI(ctx->isa, 8), /* move hi to $8 */ }; - pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 1, 31, 0)); /* move $1 to COP0 DeSave */ - pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 1, PRACC_UPPER_BASE_ADDR)); /* $1 = MIP32_PRACC_BASE_ADDR */ + /* store lo & hi */ + for (int i = 0; i < 2; i++) { + /* load COP0 needed registers to $8 */ + pracc_add(ctx, 0, lohi_read_code[i]); + /* store $8 at PARAM OUT */ + pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + (i + 32) * 4, + MIPS32_SW(ctx->isa, 8, PRACC_OUT_OFFSET + (i + 32) * 4, 1)); + } +} + +/* Saves CP0 registers [status, badvaddr, cause, depc] */ +static void mips32_pracc_store_regs_cp0_context(struct pracc_queue_info *ctx, unsigned int offset_cp0) +{ + uint32_t cp0_read_code[] = { + MIPS32_MFC0(ctx->isa, 8, 12, 0), /* move status to $8 */ + MIPS32_MFC0(ctx->isa, 8, 8, 0), /* move badvaddr to $8 */ + MIPS32_MFC0(ctx->isa, 8, 13, 0), /* move cause to $8 */ + MIPS32_MFC0(ctx->isa, 8, 24, 0), /* move depc (pc) to $8 */ + }; - for (int i = 2; i != 32; i++) /* store GPR's 2 to 31 */ - pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + (i * 4), - MIPS32_SW(ctx.isa, i, PRACC_OUT_OFFSET + (i * 4), 1)); + /* store cp0 */ + for (size_t i = 0; i < ARRAY_SIZE(cp0_read_code); i++) { + size_t offset = offset_cp0 + (i * 4); - for (int i = 0; i != 6; i++) { - pracc_add(&ctx, 0, cp0_read_code[i]); /* load COP0 needed registers to $8 */ - pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + (i + 32) * 4, /* store $8 at PARAM OUT */ - MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + (i + 32) * 4, 1)); + /* load COP0 needed registers to $8 */ + pracc_add(ctx, 0, cp0_read_code[i]); + /* store $8 at PARAM OUT */ + pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + offset, + MIPS32_SW(ctx->isa, 8, PRACC_OUT_OFFSET + offset, 1)); } - pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 8, 31, 0)); /* move DeSave to $8, reg1 value */ - pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + 4, /* store reg1 value from $8 to param out */ - MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + 4, 1)); +} - pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 1, 31, 0)); /* move COP0 DeSave to $1, restore reg1 */ - pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); /* load $15 in DeSave */ +/* Loads original content of $1 into $8, + * then store it to the batch data access address. + * Finally it restores $1 from DeSave. + */ +static void mips32_pracc_store_regs_restore(struct pracc_queue_info *ctx) +{ + /* move DeSave to $8, reg1 value */ + pracc_add(ctx, 0, MIPS32_MFC0(ctx->isa, 8, 31, 0)); + /* store reg1 value from $8 to param out */ + pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + 4, + MIPS32_SW(ctx->isa, 8, PRACC_OUT_OFFSET + 4, 1)); + + /* move COP0 DeSave to $1, restore reg1 */ + pracc_add(ctx, 0, MIPS32_MFC0(ctx->isa, 1, 31, 0)); +} + +/* This function performs following actions: + * Saves `$1` to `DeSave`, + * then load `PRACC_UPPER_BASE_ADDR` for saving the register data structure into `$1`, + * Saves `$2` ~ `$31` to `PRACC_UPPER_BASE_ADDR + offset_gpr` + * Saves HI and LO, + * Saves necessary cp0 registers. +*/ +static void mips32_pracc_store_regs(struct pracc_queue_info *ctx, + unsigned int offset_gpr, unsigned int offset_cp0) +{ + mips32_pracc_store_regs_set_base_addr(ctx); + mips32_pracc_store_regs_gpr(ctx, offset_gpr); + mips32_pracc_store_regs_lohi(ctx); + mips32_pracc_store_regs_cp0_context(ctx, offset_cp0); + mips32_pracc_store_regs_restore(ctx); +} + +int mips32_pracc_read_regs(struct mips32_common *mips32) +{ + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; + struct mips32_core_regs *core_regs = &mips32->core_regs; + unsigned int offset_gpr = ((uint8_t *)&core_regs->gpr[0]) - (uint8_t *)core_regs; + unsigned int offset_cp0 = ((uint8_t *)&core_regs->cp0[0]) - (uint8_t *)core_regs; + + /* + * This procedure has to be in 2 distinctive steps, because we can + * only know whether FP is enabled after reading CP0. + * + * Step 1: Read everything except CP1 stuff + * Step 2: Read CP1 stuff if FP is implemented + */ - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, regs, 1); + pracc_queue_init(&ctx); + + mips32_pracc_store_regs(&ctx, offset_gpr, offset_cp0); + + /* jump to start */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); + /* load $15 in DeSave */ + pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); + + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, (uint32_t *)&mips32->core_regs, 1); - ejtag_info->reg8 = regs[8]; /* reg8 is saved but not restored, next called function should restore it */ - ejtag_info->reg9 = regs[9]; pracc_queue_free(&ctx); + + /* reg8 is saved but not restored, next called function should restore it */ + ejtag_info->reg8 = mips32->core_regs.gpr[8]; + ejtag_info->reg9 = mips32->core_regs.gpr[9]; + + /* we only care if FP is actually impl'd and if cp1 is enabled */ + /* since we already read cp0 in the prev step */ + /* now we know what's in cp0.status */ + /* TODO: Read FPRs */ + return ctx.retval; } +/** + * mips32_pracc_fastdata_xfer_synchronize_cache - Synchronize cache for fast data transfer + * @param[in] ejtag_info: EJTAG information structure + * @param[in] addr: Starting address for cache synchronization + * @param[in] size: Size of each data element + * @param[in] count: Number of data elements + * + * @brief Synchronizes the cache for fast data transfer based on + * the specified address and cache configuration. + * If the region is cacheable (write-back cache or write-through cache), + * it synchronizes the cache for the specified range. + * The synchronization is performed using the MIPS32 cache synchronization function. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_pracc_fastdata_xfer_synchronize_cache(struct mips_ejtag *ejtag_info, + uint32_t addr, int size, int count) +{ + int retval = ERROR_OK; + + if ((KSEGX(addr) == KSEG1) || (addr >= 0xff200000 && addr <= 0xff3fffff)) // DESEG? + return retval; /*Nothing to do*/ + + int cached = 0; + uint32_t conf = 0; + + mips32_cp0_read(ejtag_info, &conf, 16, 0); + + switch (KSEGX(addr)) { + case KUSEG: + cached = (conf & MIPS32_CONFIG0_KU_MASK) >> MIPS32_CONFIG0_KU_SHIFT; + break; + case KSEG0: + cached = (conf & MIPS32_CONFIG0_K0_MASK) >> MIPS32_CONFIG0_K0_SHIFT; + break; + case KSEG2: + case KSEG3: + cached = (conf & MIPS32_CONFIG0_K23_MASK) >> MIPS32_CONFIG0_K23_SHIFT; + break; + default: + /* what ? */ + break; + } + + /** + * Check cacheability bits coherency algorithm + * is the region cacheable or uncached. + * If cacheable we have to synchronize the cache + */ + if (cached == 3 || cached == 0) { /* Write back cache or write through cache */ + uint32_t start_addr = addr; + uint32_t end_addr = addr + count * size; + uint32_t rel = (conf & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT; + /* FIXME: In MIPS Release 6, the encoding of CACHE instr has changed */ + if (rel > MIPS32_RELEASE_2) { + LOG_DEBUG("Unsupported MIPS Release ( > 5)"); + return ERROR_FAIL; + } + retval = mips32_pracc_synchronize_cache(ejtag_info, start_addr, end_addr, cached, rel); + } + + return retval; +} + /* fastdata upload/download requires an initialized working area * to load the download code; it should not be called otherwise * fetch order from the fastdata area @@ -931,13 +1132,17 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are /* start of fastdata area in t0 */ MIPS32_LUI(isa, 8, UPPER16(MIPS32_PRACC_FASTDATA_AREA)), MIPS32_ORI(isa, 8, 8, LOWER16(MIPS32_PRACC_FASTDATA_AREA)), - MIPS32_LW(isa, 9, 0, 8), /* start addr in t1 */ - MIPS32_LW(isa, 10, 0, 8), /* end addr to t2 */ - /* loop: */ + MIPS32_LW(isa, 9, 0, 8), /* start addr in t1 */ + mips32_cpu_support_sync(ejtag_info) ? MIPS32_SYNC(isa) : MIPS32_NOP, /* barrier for ordering */ + MIPS32_LW(isa, 10, 0, 8), /* end addr to t2 */ + mips32_cpu_support_sync(ejtag_info) ? MIPS32_SYNC(isa) : MIPS32_NOP, /* barrier for ordering */ + /* loop: */ write_t ? MIPS32_LW(isa, 11, 0, 8) : MIPS32_LW(isa, 11, 0, 9), /* from xfer area : from memory */ write_t ? MIPS32_SW(isa, 11, 0, 9) : MIPS32_SW(isa, 11, 0, 8), /* to memory : to xfer area */ - MIPS32_BNE(isa, 10, 9, NEG16(3 << isa)), /* bne $t2,t1,loop */ + mips32_cpu_support_sync(ejtag_info) ? MIPS32_SYNC(isa) : MIPS32_NOP, /* barrier for ordering */ + + MIPS32_BNE(isa, 10, 9, NEG16(4 << isa)), /* bne $t2,t1,loop */ MIPS32_ADDI(isa, 9, 9, 4), /* addi t1,t1,4 */ MIPS32_LW(isa, 8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15), @@ -947,7 +1152,9 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are MIPS32_LUI(isa, 15, UPPER16(MIPS32_PRACC_TEXT)), MIPS32_ORI(isa, 15, 15, LOWER16(MIPS32_PRACC_TEXT) | isa), /* isa bit for JR instr */ - MIPS32_JR(isa, 15), /* jr start */ + mips32_cpu_support_hazard_barrier(ejtag_info) + ? MIPS32_JRHB(isa, 15) + : MIPS32_JR(isa, 15), /* jr start */ MIPS32_MFC0(isa, 15, 31, 0), /* move COP0 DeSave to $15 */ }; @@ -967,7 +1174,9 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are uint32_t jmp_code[] = { MIPS32_LUI(isa, 15, UPPER16(source->address)), /* load addr of jump in $15 */ MIPS32_ORI(isa, 15, 15, LOWER16(source->address) | isa), /* isa bit for JR instr */ - MIPS32_JR(isa, 15), /* jump to ram program */ + mips32_cpu_support_hazard_barrier(ejtag_info) + ? MIPS32_JRHB(isa, 15) + : MIPS32_JR(isa, 15), /* jump to ram program */ isa ? MIPS32_XORI(isa, 15, 15, 1) : MIPS32_NOP, /* drop isa bit, needed for LW/SW instructions */ }; @@ -1031,5 +1240,5 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are if (ejtag_info->pa_addr != MIPS32_PRACC_TEXT) LOG_ERROR("mini program did not return to start"); - return retval; + return mips32_pracc_fastdata_xfer_synchronize_cache(ejtag_info, addr, 4, count); } diff --git a/src/target/mips32_pracc.h b/src/target/mips32_pracc.h index 30edaec0a2..78d087213c 100644 --- a/src/target/mips32_pracc.h +++ b/src/target/mips32_pracc.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * @@ -6,19 +8,6 @@ * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_MIPS32_PRACC_H @@ -47,6 +36,8 @@ #define PRACC_BLOCK 128 /* 1 Kbyte */ +struct mips32_common; + struct pa_list { uint32_t instr; uint32_t addr; @@ -62,9 +53,10 @@ struct pracc_queue_info { struct pa_list *pracc_list; /* Code and store addresses at dmseg */ }; +struct mips32_common; + void pracc_queue_init(struct pracc_queue_info *ctx); void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr); -void pracc_add_li32(struct pracc_queue_info *ctx, uint32_t reg_num, uint32_t data, bool optimize); void pracc_queue_free(struct pracc_queue_info *ctx); int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx, uint32_t *buf, bool check_last); @@ -76,11 +68,8 @@ int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source, int write_t, uint32_t addr, int count, uint32_t *buf); -int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs); -int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs); - -int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx, - uint32_t *param_out, bool check_last); +int mips32_pracc_read_regs(struct mips32_common *mips32); +int mips32_pracc_write_regs(struct mips32_common *mips32); /** * \b mips32_cp0_read diff --git a/src/target/mips64.c b/src/target/mips64.c index 347cdfc4be..48f4563dc6 100644 --- a/src/target/mips64.c +++ b/src/target/mips64.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Support for processors implementing MIPS64 instruction set * @@ -10,8 +12,6 @@ * Copyright (C) 2008 by Spencer Oliver * Copyright (C) 2008 by David T.L. Wong * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev - * - * SPDX-License-Identifier: GPL-2.0-or-later */ #ifdef HAVE_CONFIG_H @@ -247,8 +247,8 @@ static int mips64_set_core_reg(struct reg *reg, uint8_t *buf) return ERROR_TARGET_NOT_HALTED; buf_set_u64(reg->value, 0, 64, value); - reg->dirty = 1; - reg->valid = 1; + reg->dirty = true; + reg->valid = true; return ERROR_OK; } @@ -265,8 +265,8 @@ static int mips64_read_core_reg(struct target *target, int num) reg_value = mips64->core_regs[num]; buf_set_u64(mips64->core_cache->reg_list[num].value, 0, 64, reg_value); - mips64->core_cache->reg_list[num].valid = 1; - mips64->core_cache->reg_list[num].dirty = 0; + mips64->core_cache->reg_list[num].valid = true; + mips64->core_cache->reg_list[num].dirty = false; return ERROR_OK; } @@ -284,8 +284,8 @@ static int mips64_write_core_reg(struct target *target, int num) reg_value = buf_get_u64(mips64->core_cache->reg_list[num].value, 0, 64); mips64->core_regs[num] = reg_value; LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num, reg_value); - mips64->core_cache->reg_list[num].valid = 1; - mips64->core_cache->reg_list[num].dirty = 0; + mips64->core_cache->reg_list[num].valid = true; + mips64->core_cache->reg_list[num].dirty = false; return ERROR_OK; } @@ -297,8 +297,8 @@ int mips64_invalidate_core_regs(struct target *target) unsigned int i; for (i = 0; i < mips64->core_cache->num_regs; i++) { - mips64->core_cache->reg_list[i].valid = 0; - mips64->core_cache->reg_list[i].dirty = 0; + mips64->core_cache->reg_list[i].valid = false; + mips64->core_cache->reg_list[i].dirty = false; } return ERROR_OK; @@ -459,7 +459,7 @@ int mips64_init_arch_info(struct target *target, struct mips64_common *mips64, int mips64_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, - target_addr_t exit_point, int timeout_ms, void *arch_info) + target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { /* TODO */ return ERROR_OK; diff --git a/src/target/mips64.h b/src/target/mips64.h index 3453e4ed1a..ae0811c547 100644 --- a/src/target/mips64.h +++ b/src/target/mips64.h @@ -19,7 +19,7 @@ #include "register.h" #include "mips64_pracc.h" -#define MIPS64_COMMON_MAGIC 0xB640B640 +#define MIPS64_COMMON_MAGIC 0xB640B640U /* MIPS64 CP0 registers */ #define MIPS64_C0_INDEX 0 @@ -81,7 +81,8 @@ struct mips64_comparator { }; struct mips64_common { - uint32_t common_magic; + unsigned int common_magic; + void *arch_info; struct reg_cache *core_cache; struct mips_ejtag ejtag_info; @@ -212,7 +213,7 @@ int mips64_build_reg_cache(struct target *target); int mips64_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, - int timeout_ms, void *arch_info); + unsigned int timeout_ms, void *arch_info); int mips64_configure_break_unit(struct target *target); int mips64_enable_interrupts(struct target *target, bool enable); int mips64_examine(struct target *target); diff --git a/src/target/mips64_pracc.c b/src/target/mips64_pracc.c index 81a4cfbfaa..b083f5ce8b 100644 --- a/src/target/mips64_pracc.c +++ b/src/target/mips64_pracc.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Support for processors implementing MIPS64 instruction set * @@ -9,8 +11,6 @@ * Copyright (C) 2008 by Spencer Oliver * Copyright (C) 2008 by David T.L. Wong * Copyright (C) 2010 by Konstantin Kostyukhin, Nikolay Shmyrev - * - * SPDX-License-Identifier: GPL-2.0-or-later */ #ifdef HAVE_CONFIG_H diff --git a/src/target/mips64_pracc.h b/src/target/mips64_pracc.h index 65ff6e6ac8..19d1519466 100644 --- a/src/target/mips64_pracc.h +++ b/src/target/mips64_pracc.h @@ -29,7 +29,7 @@ #undef LOWER16 #define UPPER16(v) ((uint32_t)((v >> 16) & 0xFFFF)) #define LOWER16(v) ((uint32_t)(v & 0xFFFF)) -#define MIPS64_PRACC_FASTDATA_AREA 0xffffffffFF200000 +#define MIPS64_PRACC_FASTDATA_AREA 0xffffffffFF200000ull #define MIPS64_PRACC_FASTDATA_SIZE 16 #define MIPS64_FASTDATA_HANDLER_SIZE 0x80 diff --git a/src/target/mips_cpu.h b/src/target/mips_cpu.h new file mode 100644 index 0000000000..c3b7b54ba7 --- /dev/null +++ b/src/target/mips_cpu.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef OPENOCD_TARGET_MIPS_CPU_H +#define OPENOCD_TARGET_MIPS_CPU_H + +/* + * NOTE: The proper detection of certain CPUs can become quite complicated. + * Please consult the following Linux kernel code when adding new CPUs: + * arch/mips/include/asm/cpu.h + * arch/mips/kernel/cpu-probe.c + */ + +/* Assigned Company values for bits 23:16 of the PRId register. */ +#define PRID_COMP_MASK 0xff0000 + +#define PRID_COMP_LEGACY 0x000000 +#define PRID_COMP_MTI 0x010000 +#define PRID_COMP_BROADCOM 0x020000 +#define PRID_COMP_ALCHEMY 0x030000 +#define PRID_COMP_LEXRA 0x0b0000 +#define PRID_COMP_ALTERA 0x100000 +#define PRID_COMP_INGENIC_E1 0xe10000 + +/* + * Assigned Processor ID (implementation) values for bits 15:8 of the PRId + * register. In order to detect a certain CPU type exactly eventually additional + * registers may need to be examined. + */ +#define PRID_IMP_MASK 0xff00 + +#define PRID_IMP_MAPTIV_UC 0x9D00 +#define PRID_IMP_MAPTIV_UP 0x9E00 +#define PRID_IMP_IAPTIV_CM 0xA000 +#define PRID_IMP_IAPTIV 0xA100 +#define PRID_IMP_M5150 0xA700 + +#define PRID_IMP_XBURST_REV1 0x0200 /* XBurst®1 with MXU1.0/MXU1.1 SIMD ISA */ + +#endif /* OPENOCD_TARGET_MIPS_CPU_H */ diff --git a/src/target/mips_ejtag.c b/src/target/mips_ejtag.c index b21a1bdc4c..389461cae6 100644 --- a/src/target/mips_ejtag.c +++ b/src/target/mips_ejtag.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * @@ -5,19 +7,6 @@ * Copyright (C) 2008 by David T.L. Wong * * * * Copyright (C) 2009 by David N. Claffey <dnclaffey@gmail.com> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -58,7 +47,7 @@ int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info) return mips_ejtag_drscan_32(ejtag_info, &ejtag_info->idcode); } -static int mips_ejtag_get_impcode(struct mips_ejtag *ejtag_info) +int mips_ejtag_get_impcode(struct mips_ejtag *ejtag_info) { mips_ejtag_set_instr(ejtag_info, EJTAG_INST_IMPCODE); @@ -270,9 +259,12 @@ int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info) { struct pa_list pracc_list = {.instr = MIPS32_DRET(ejtag_info->isa), .addr = 0}; struct pracc_queue_info ctx = {.max_code = 1, .pracc_list = &pracc_list, .code_count = 1, .store_count = 0}; + struct mips32_common *mips32 = container_of(ejtag_info, + struct mips32_common, ejtag_info); /* execute our dret instruction */ - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 0); /* shift out instr, omit last check */ + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, + mips32->cpu_quirks & EJTAG_QUIRK_PAD_DRET); /* pic32mx workaround, false pending at low core clock */ jtag_add_sleep(1000); @@ -340,7 +332,7 @@ static void ejtag_v26_print_imp(struct mips_ejtag *ejtag_info) EJTAG_IMP_HAS(EJTAG_V26_IMP_DINT) ? " DINT" : ""); } -static void ejtag_main_print_imp(struct mips_ejtag *ejtag_info) +void ejtag_main_print_imp(struct mips_ejtag *ejtag_info) { LOG_DEBUG("EJTAG main: features:%s%s%s%s%s", EJTAG_IMP_HAS(EJTAG_IMP_ASID8) ? " ASID_8" : "", diff --git a/src/target/mips_ejtag.h b/src/target/mips_ejtag.h index e50101b0fa..7376e5141d 100644 --- a/src/target/mips_ejtag.h +++ b/src/target/mips_ejtag.h @@ -1,21 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_MIPS_EJTAG_H @@ -134,11 +123,12 @@ /* Debug Control Register DCR */ #define EJTAG_DCR 0xFF300000 -#define EJTAG_DCR_ENM (1 << 29) -#define EJTAG_DCR_DB (1 << 17) -#define EJTAG_DCR_IB (1 << 16) -#define EJTAG_DCR_INTE (1 << 4) -#define EJTAG_DCR_MP (1 << 2) +#define EJTAG_DCR_ENM BIT(29) +#define EJTAG_DCR_FDC BIT(18) +#define EJTAG_DCR_DB BIT(17) +#define EJTAG_DCR_IB BIT(16) +#define EJTAG_DCR_INTE BIT(4) +#define EJTAG_DCR_MP BIT(2) /* breakpoint support */ /* EJTAG_V20_* was tested on Broadcom BCM7401 @@ -196,10 +186,27 @@ #define EJTAG64_V25_IBA0 0xFFFFFFFFFF301100ull #define EJTAG64_V25_IBS 0xFFFFFFFFFF301000ull +static const struct dcr_feature { + int bit; + const char *name; +} dcr_features[] = { + {22, "DAS"}, + {18, "FDC"}, + {17, "DataBrk"}, + {16, "InstBrk"}, + {15, "Inverted Data value"}, + {14, "Data value stored"}, + {10, "Complex Breakpoints"}, + { 9, "PC Sampling"}, +}; + +#define EJTAG_DCR_ENTRIES (ARRAY_SIZE(dcr_features)) + struct mips_ejtag { struct jtag_tap *tap; uint32_t impcode; uint32_t idcode; + uint32_t prid; uint32_t ejtag_ctrl; int fast_access_save; uint32_t config_regs; /* number of config registers read */ @@ -254,6 +261,9 @@ int mips_ejtag_init(struct mips_ejtag *ejtag_info); int mips_ejtag_config_step(struct mips_ejtag *ejtag_info, int enable_step); int mips64_ejtag_config_step(struct mips_ejtag *ejtag_info, bool enable_step); +void ejtag_main_print_imp(struct mips_ejtag *ejtag_info); +int mips_ejtag_get_impcode(struct mips_ejtag *ejtag_info); + static inline void mips_le_to_h_u32(jtag_callback_data_t arg) { uint8_t *in = (uint8_t *)arg; diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index 8601193453..ad98089614 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * @@ -8,19 +10,6 @@ * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -47,6 +36,8 @@ static int mips_m4k_internal_restore(struct target *target, int current, static int mips_m4k_halt(struct target *target); static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer); +static int mips_m4k_bulk_read_memory(struct target *target, target_addr_t address, + uint32_t count, uint8_t *buffer); static int mips_m4k_examine_debug_reason(struct target *target) { @@ -109,17 +100,19 @@ static int mips_m4k_debug_entry(struct target *target) /* attempt to find halt reason */ mips_m4k_examine_debug_reason(target); + mips32_cpu_probe(target); + mips32_read_config_regs(target); /* default to mips32 isa, it will be changed below if required */ mips32->isa_mode = MIPS32_ISA_MIPS32; /* other than mips32 only and isa bit set ? */ - if (mips32->isa_imp && buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1)) + if (mips32->isa_imp && buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 1)) mips32->isa_mode = mips32->isa_imp == 2 ? MIPS32_ISA_MIPS16E : MIPS32_ISA_MMIPS32; LOG_DEBUG("entered debug state at PC 0x%" PRIx32 ", target->state: %s", - buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32), + buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32), target_state_name(target)); return ERROR_OK; @@ -149,7 +142,7 @@ static int mips_m4k_halt_smp(struct target *target) ret = mips_m4k_halt(curr); if (ret != ERROR_OK) { - LOG_ERROR("halt failed target->coreid: %" PRId32, curr->coreid); + LOG_TARGET_ERROR(curr, "halt failed."); retval = ret; } } @@ -419,8 +412,8 @@ static int mips_m4k_restore_smp(struct target *target, uint32_t address, int han handle_breakpoints, 0); if (ret != ERROR_OK) { - LOG_ERROR("target->coreid :%" PRId32 " failed to resume at address :0x%" PRIx32, - curr->coreid, address); + LOG_TARGET_ERROR(curr, "failed to resume at address: 0x%" PRIx32, + address); retval = ret; } } @@ -450,18 +443,18 @@ static int mips_m4k_internal_restore(struct target *target, int current, /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { mips_m4k_isa_filter(mips32->isa_imp, &address); - buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address); - mips32->core_cache->reg_list[MIPS32_PC].dirty = true; - mips32->core_cache->reg_list[MIPS32_PC].valid = true; + buf_set_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32, address); + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].dirty = true; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].valid = true; } if ((mips32->isa_imp > 1) && debug_execution) /* if more than one isa supported */ - buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1, mips32->isa_mode); + buf_set_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 1, mips32->isa_mode); if (!current) resume_pc = address; else - resume_pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32); + resume_pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32); mips32_restore_context(target); @@ -544,15 +537,15 @@ static int mips_m4k_step(struct target *target, int current, /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { mips_m4k_isa_filter(mips32->isa_imp, &address); - buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address); - mips32->core_cache->reg_list[MIPS32_PC].dirty = true; - mips32->core_cache->reg_list[MIPS32_PC].valid = true; + buf_set_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32, address); + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].dirty = true; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].valid = true; } /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { breakpoint = breakpoint_find(target, - buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32)); + buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32)); if (breakpoint) mips_m4k_unset_breakpoint(target, breakpoint); } @@ -911,7 +904,7 @@ static int mips_m4k_set_watchpoint(struct target *target, LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } - watchpoint->number = wp_num; + watchpoint_set(watchpoint, wp_num); comparator_list[wp_num].used = 1; comparator_list[wp_num].bp_value = watchpoint->address; @@ -1032,6 +1025,12 @@ static int mips_m4k_read_memory(struct target *target, target_addr_t address, if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; + if (size == 4 && count > 32) { + int retval = mips_m4k_bulk_read_memory(target, address, count, buffer); + if (retval == ERROR_OK) + return ERROR_OK; + LOG_WARNING("Falling back to non-bulk read"); + } /* since we don't know if buffer is aligned, we allocate new mem that is always aligned */ void *t = NULL; @@ -1229,8 +1228,8 @@ static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t addre fast_data_area = mips32->fast_data_area; - if (address <= fast_data_area->address + fast_data_area->size && - fast_data_area->address <= address + count) { + if (address < (fast_data_area->address + fast_data_area->size) && + fast_data_area->address < (address + count)) { LOG_ERROR("fast_data (" TARGET_ADDR_FMT ") is within write area " "(" TARGET_ADDR_FMT "-" TARGET_ADDR_FMT ").", fast_data_area->address, address, address + count); @@ -1260,6 +1259,71 @@ static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t addre return retval; } +static int mips_m4k_bulk_read_memory(struct target *target, target_addr_t address, + uint32_t count, uint8_t *buffer) +{ + struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + struct working_area *fast_data_area; + int retval; + int write_t = 0; + + LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "", + address, count); + + /* check alignment */ + if (address & 0x3u) + return ERROR_TARGET_UNALIGNED_ACCESS; + + if (!mips32->fast_data_area) { + /* Get memory for block read handler + * we preserve this area between calls and gain a speed increase + * of about 3kb/sec when reading flash + * this will be released/nulled by the system when the target is resumed or reset */ + retval = target_alloc_working_area(target, + MIPS32_FASTDATA_HANDLER_SIZE, + &mips32->fast_data_area); + if (retval != ERROR_OK) { + LOG_ERROR("No working area available"); + return retval; + } + + /* reset fastadata state so the algo get reloaded */ + ejtag_info->fast_access_save = -1; + } + + fast_data_area = mips32->fast_data_area; + + if (address < (fast_data_area->address + fast_data_area->size) && + fast_data_area->address < (address + count)) { + LOG_ERROR("fast_data (" TARGET_ADDR_FMT ") is within read area " + "(" TARGET_ADDR_FMT "-" TARGET_ADDR_FMT ").", + fast_data_area->address, address, address + count); + LOG_ERROR("Change work-area-phys or load_image address!"); + return ERROR_FAIL; + } + + /* mips32_pracc_fastdata_xfer requires uint32_t in host endianness, */ + /* but byte array represents target endianness */ + uint32_t *t = malloc(count * sizeof(uint32_t)); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + retval = mips32_pracc_fastdata_xfer(ejtag_info, mips32->fast_data_area, write_t, address, + count, t); + + target_buffer_set_u32_array(target, buffer, count, t); + + free(t); + + if (retval != ERROR_OK) + LOG_ERROR("Fastdata access Failed"); + + return retval; +} + static int mips_m4k_verify_pointer(struct command_invocation *cmd, struct mips_m4k_common *mips_m4k) { @@ -1368,7 +1432,7 @@ static const struct command_registration mips_m4k_exec_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -const struct command_registration mips_m4k_command_handlers[] = { +static const struct command_registration mips_m4k_command_handlers[] = { { .chain = mips32_command_handlers, }, diff --git a/src/target/mips_m4k.h b/src/target/mips_m4k.h index ea09ae527f..f63d72f73c 100644 --- a/src/target/mips_m4k.h +++ b/src/target/mips_m4k.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * @@ -6,19 +8,6 @@ * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_MIPS_M4K_H @@ -26,12 +15,14 @@ struct target; -#define MIPSM4K_COMMON_MAGIC 0xB321B321 +#define MIPSM4K_COMMON_MAGIC 0xB321B321U struct mips_m4k_common { - uint32_t common_magic; - bool is_pic32mx; + unsigned int common_magic; + struct mips32_common mips32; + + bool is_pic32mx; }; static inline struct mips_m4k_common * @@ -52,6 +43,5 @@ static inline void mips_m4k_isa_filter(enum mips32_isa_imp isa_imp, target_addr_ } } } -extern const struct command_registration mips_m4k_command_handlers[]; #endif /* OPENOCD_TARGET_MIPS_M4K_H */ diff --git a/src/target/mips_mips64.c b/src/target/mips_mips64.c index 5d821d7cb9..9921e93807 100644 --- a/src/target/mips_mips64.c +++ b/src/target/mips_mips64.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * MIPS64 generic target support * @@ -8,8 +10,6 @@ * Based on the work of: * Copyright (C) 2008 by Spencer Oliver * Copyright (C) 2008 by David T.L. Wong - * - * SPDX-License-Identifier: GPL-2.0-or-later */ #ifdef HAVE_CONFIG_H @@ -205,12 +205,6 @@ static int mips_mips64_deassert_reset(struct target *target) return ERROR_OK; } -static int mips_mips64_soft_reset_halt(struct target *target) -{ - /* TODO */ - return ERROR_OK; -} - static int mips_mips64_single_step_core(struct target *target) { struct mips64_common *mips64 = target->arch_info; @@ -612,7 +606,7 @@ static int mips_mips64_resume(struct target *target, int current, address = mips64_extend_sign(address); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted %d", target->state); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -631,8 +625,8 @@ static int mips_mips64_resume(struct target *target, int current, /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u64(pc->value, 0, 64, address); - pc->dirty = 1; - pc->valid = 1; + pc->dirty = true; + pc->valid = true; } resume_pc = buf_get_u64(pc->value, 0, 64); @@ -712,7 +706,7 @@ static int mips_mips64_step(struct target *target, int current, int retval = ERROR_OK; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -723,8 +717,8 @@ static int mips_mips64_step(struct target *target, int current, * <address> */ if (!current) { buf_set_u64(pc->value, 0, 64, address); - pc->dirty = 1; - pc->valid = 1; + pc->dirty = true; + pc->valid = true; } /* the front-end may request us not to handle breakpoints */ @@ -810,7 +804,7 @@ static int mips_mips64_remove_breakpoint(struct target *target, int retval = ERROR_OK; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -871,7 +865,7 @@ static int mips_mips64_remove_watchpoint(struct target *target, int retval = ERROR_OK; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -892,7 +886,7 @@ static int mips_mips64_read_memory(struct target *target, uint64_t address, void *t; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted %d", target->state); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1020,7 +1014,7 @@ static int mips_mips64_write_memory(struct target *target, uint64_t address, int retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1168,7 +1162,7 @@ struct target_type mips_mips64_target = { .assert_reset = mips_mips64_assert_reset, .deassert_reset = mips_mips64_deassert_reset, - .soft_reset_halt = mips_mips64_soft_reset_halt, + /* TODO: add .soft_reset_halt */ .get_gdb_reg_list = mips64_get_gdb_reg_list, diff --git a/src/target/mips_mips64.h b/src/target/mips_mips64.h index 69fb2a6f98..9841deb2fd 100644 --- a/src/target/mips_mips64.h +++ b/src/target/mips_mips64.h @@ -17,7 +17,8 @@ #include "helper/types.h" struct mips_mips64_common { - int common_magic; + unsigned int common_magic; + struct mips64_common mips64_common; }; diff --git a/src/target/nds32.c b/src/target/nds32.c deleted file mode 100644 index f0fb74d310..0000000000 --- a/src/target/nds32.c +++ /dev/null @@ -1,2624 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <helper/log.h> -#include <helper/binarybuffer.h> -#include "nds32.h" -#include "nds32_aice.h" -#include "nds32_tlb.h" -#include "nds32_disassembler.h" - -struct nds32_edm_operation nds32_edm_ops[NDS32_EDM_OPERATION_MAX_NUM]; -uint32_t nds32_edm_ops_num; - -const char *nds32_debug_type_name[11] = { - "SOFTWARE BREAK", - "SOFTWARE BREAK_16", - "HARDWARE BREAKPOINT", - "DATA ADDR WATCHPOINT PRECISE", - "DATA VALUE WATCHPOINT PRECISE", - "DATA VALUE WATCHPOINT IMPRECISE", - "DEBUG INTERRUPT", - "HARDWARE SINGLE STEP", - "DATA ADDR WATCHPOINT NEXT PRECISE", - "DATA VALUE WATCHPOINT NEXT PRECISE", - "LOAD STORE GLOBAL STOP", -}; - -static const int nds32_lm_size_table[16] = { - 4 * 1024, - 8 * 1024, - 16 * 1024, - 32 * 1024, - 64 * 1024, - 128 * 1024, - 256 * 1024, - 512 * 1024, - 1024 * 1024, - 1 * 1024, - 2 * 1024, -}; - -static const int nds32_line_size_table[6] = { - 0, - 8, - 16, - 32, - 64, - 128, -}; - -static int nds32_get_core_reg(struct reg *reg) -{ - int retval; - struct nds32_reg *reg_arch_info = reg->arch_info; - struct target *target = reg_arch_info->target; - struct nds32 *nds32 = target_to_nds32(target); - struct aice_port_s *aice = target_to_aice(target); - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (reg->valid) { - uint32_t val = buf_get_u32(reg_arch_info->value, 0, 32); - LOG_DEBUG("reading register(cached) %" PRIi32 "(%s), value: 0x%8.8" PRIx32, - reg_arch_info->num, reg->name, val); - return ERROR_OK; - } - - int mapped_regnum = nds32->register_map(nds32, reg_arch_info->num); - - if (reg_arch_info->enable == false) { - buf_set_u32(reg_arch_info->value, 0, 32, NDS32_REGISTER_DISABLE); - retval = ERROR_FAIL; - } else { - uint32_t val = 0; - if ((nds32->fpu_enable == false) - && (nds32_reg_type(mapped_regnum) == NDS32_REG_TYPE_FPU)) { - retval = ERROR_OK; - } else if ((nds32->audio_enable == false) - && (nds32_reg_type(mapped_regnum) == NDS32_REG_TYPE_AUMR)) { - retval = ERROR_OK; - } else { - retval = aice_read_register(aice, mapped_regnum, &val); - } - buf_set_u32(reg_arch_info->value, 0, 32, val); - - LOG_DEBUG("reading register %" PRIi32 "(%s), value: 0x%8.8" PRIx32, - reg_arch_info->num, reg->name, val); - } - - if (retval == ERROR_OK) { - reg->valid = true; - reg->dirty = false; - } - - return retval; -} - -static int nds32_get_core_reg_64(struct reg *reg) -{ - int retval; - struct nds32_reg *reg_arch_info = reg->arch_info; - struct target *target = reg_arch_info->target; - struct nds32 *nds32 = target_to_nds32(target); - struct aice_port_s *aice = target_to_aice(target); - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (reg->valid) - return ERROR_OK; - - if (reg_arch_info->enable == false) { - buf_set_u64(reg_arch_info->value, 0, 64, NDS32_REGISTER_DISABLE); - retval = ERROR_FAIL; - } else { - uint64_t val = 0; - if ((nds32->fpu_enable == false) - && ((reg_arch_info->num >= FD0) && (reg_arch_info->num <= FD31))) { - retval = ERROR_OK; - } else { - retval = aice_read_reg_64(aice, reg_arch_info->num, &val); - } - buf_set_u64(reg_arch_info->value, 0, 64, val); - } - - if (retval == ERROR_OK) { - reg->valid = true; - reg->dirty = false; - } - - return retval; -} - -static int nds32_update_psw(struct nds32 *nds32) -{ - uint32_t value_ir0; - struct aice_port_s *aice = target_to_aice(nds32->target); - - nds32_get_mapped_reg(nds32, IR0, &value_ir0); - - /* Save data memory endian */ - if ((value_ir0 >> 5) & 0x1) { - nds32->data_endian = TARGET_BIG_ENDIAN; - aice_set_data_endian(aice, AICE_BIG_ENDIAN); - } else { - nds32->data_endian = TARGET_LITTLE_ENDIAN; - aice_set_data_endian(aice, AICE_LITTLE_ENDIAN); - } - - /* Save translation status */ - nds32->memory.address_translation = ((value_ir0 >> 7) & 0x1) ? true : false; - - return ERROR_OK; -} - -static int nds32_update_mmu_info(struct nds32 *nds32) -{ - uint32_t value; - - /* Update MMU control status */ - nds32_get_mapped_reg(nds32, MR0, &value); - nds32->mmu_config.default_min_page_size = value & 0x1; - nds32->mmu_config.multiple_page_size_in_use = (value >> 10) & 0x1; - - return ERROR_OK; -} - -static int nds32_update_cache_info(struct nds32 *nds32) -{ - uint32_t value; - - if (nds32_get_mapped_reg(nds32, MR8, &value) == ERROR_OK) { - if (value & 0x1) - nds32->memory.icache.enable = true; - else - nds32->memory.icache.enable = false; - - if (value & 0x2) - nds32->memory.dcache.enable = true; - else - nds32->memory.dcache.enable = false; - } else { - nds32->memory.icache.enable = false; - nds32->memory.dcache.enable = false; - } - - return ERROR_OK; -} - -static int nds32_update_lm_info(struct nds32 *nds32) -{ - struct nds32_memory *memory = &(nds32->memory); - uint32_t value_mr6; - uint32_t value_mr7; - - nds32_get_mapped_reg(nds32, MR6, &value_mr6); - if (value_mr6 & 0x1) - memory->ilm_enable = true; - else - memory->ilm_enable = false; - - if (memory->ilm_align_ver == 0) { /* 1MB aligned */ - memory->ilm_start = value_mr6 & 0xFFF00000; - memory->ilm_end = memory->ilm_start + memory->ilm_size; - } else if (memory->ilm_align_ver == 1) { /* aligned to local memory size */ - memory->ilm_start = value_mr6 & 0xFFFFFC00; - memory->ilm_end = memory->ilm_start + memory->ilm_size; - } else { - memory->ilm_start = -1; - memory->ilm_end = -1; - } - - nds32_get_mapped_reg(nds32, MR7, &value_mr7); - if (value_mr7 & 0x1) - memory->dlm_enable = true; - else - memory->dlm_enable = false; - - if (memory->dlm_align_ver == 0) { /* 1MB aligned */ - memory->dlm_start = value_mr7 & 0xFFF00000; - memory->dlm_end = memory->dlm_start + memory->dlm_size; - } else if (memory->dlm_align_ver == 1) { /* aligned to local memory size */ - memory->dlm_start = value_mr7 & 0xFFFFFC00; - memory->dlm_end = memory->dlm_start + memory->dlm_size; - } else { - memory->dlm_start = -1; - memory->dlm_end = -1; - } - - return ERROR_OK; -} - -/** - * If fpu/audio is disabled, to access fpu/audio registers will cause - * exceptions. So, we need to check if fpu/audio is enabled or not as - * target is halted. If fpu/audio is disabled, as users access fpu/audio - * registers, OpenOCD will return fake value 0 instead of accessing - * registers through DIM. - */ -static int nds32_check_extension(struct nds32 *nds32) -{ - uint32_t value; - - nds32_get_mapped_reg(nds32, FUCPR, &value); - if (value == NDS32_REGISTER_DISABLE) { - nds32->fpu_enable = false; - nds32->audio_enable = false; - return ERROR_OK; - } - - if (value & 0x1) - nds32->fpu_enable = true; - else - nds32->fpu_enable = false; - - if (value & 0x80000000) - nds32->audio_enable = true; - else - nds32->audio_enable = false; - - return ERROR_OK; -} - -static int nds32_set_core_reg(struct reg *reg, uint8_t *buf) -{ - struct nds32_reg *reg_arch_info = reg->arch_info; - struct target *target = reg_arch_info->target; - struct nds32 *nds32 = target_to_nds32(target); - struct aice_port_s *aice = target_to_aice(target); - uint32_t value = buf_get_u32(buf, 0, 32); - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - int mapped_regnum = nds32->register_map(nds32, reg_arch_info->num); - - /* ignore values that will generate exception */ - if (nds32_reg_exception(mapped_regnum, value)) - return ERROR_OK; - - LOG_DEBUG("writing register %" PRIi32 "(%s) with value 0x%8.8" PRIx32, - reg_arch_info->num, reg->name, value); - - if ((nds32->fpu_enable == false) && - (nds32_reg_type(mapped_regnum) == NDS32_REG_TYPE_FPU)) { - - buf_set_u32(reg->value, 0, 32, 0); - } else if ((nds32->audio_enable == false) && - (nds32_reg_type(mapped_regnum) == NDS32_REG_TYPE_AUMR)) { - - buf_set_u32(reg->value, 0, 32, 0); - } else { - buf_set_u32(reg->value, 0, 32, value); - uint32_t val = buf_get_u32(reg_arch_info->value, 0, 32); - aice_write_register(aice, mapped_regnum, val); - - /* After set value to registers, read the value from target - * to avoid W1C inconsistency. */ - aice_read_register(aice, mapped_regnum, &val); - buf_set_u32(reg_arch_info->value, 0, 32, val); - } - - reg->valid = true; - reg->dirty = false; - - /* update registers to take effect right now */ - if (mapped_regnum == IR0) { - nds32_update_psw(nds32); - } else if (mapped_regnum == MR0) { - nds32_update_mmu_info(nds32); - } else if ((mapped_regnum == MR6) || (mapped_regnum == MR7)) { - /* update lm information */ - nds32_update_lm_info(nds32); - } else if (mapped_regnum == MR8) { - nds32_update_cache_info(nds32); - } else if (mapped_regnum == FUCPR) { - /* update audio/fpu setting */ - nds32_check_extension(nds32); - } - - return ERROR_OK; -} - -static int nds32_set_core_reg_64(struct reg *reg, uint8_t *buf) -{ - struct nds32_reg *reg_arch_info = reg->arch_info; - struct target *target = reg_arch_info->target; - struct nds32 *nds32 = target_to_nds32(target); - uint32_t low_part = buf_get_u32(buf, 0, 32); - uint32_t high_part = buf_get_u32(buf, 32, 32); - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if ((nds32->fpu_enable == false) && - ((reg_arch_info->num >= FD0) && (reg_arch_info->num <= FD31))) { - - buf_set_u32(reg->value, 0, 32, 0); - buf_set_u32(reg->value, 32, 32, 0); - - reg->valid = true; - reg->dirty = false; - } else { - buf_set_u32(reg->value, 0, 32, low_part); - buf_set_u32(reg->value, 32, 32, high_part); - - reg->valid = true; - reg->dirty = true; - } - - return ERROR_OK; -} - -static const struct reg_arch_type nds32_reg_access_type = { - .get = nds32_get_core_reg, - .set = nds32_set_core_reg, -}; - -static const struct reg_arch_type nds32_reg_access_type_64 = { - .get = nds32_get_core_reg_64, - .set = nds32_set_core_reg_64, -}; - -static struct reg_cache *nds32_build_reg_cache(struct target *target, - struct nds32 *nds32) -{ - struct reg_cache *cache = calloc(sizeof(struct reg_cache), 1); - struct reg *reg_list = calloc(TOTAL_REG_NUM, sizeof(struct reg)); - struct nds32_reg *reg_arch_info = calloc(TOTAL_REG_NUM, sizeof(struct nds32_reg)); - int i; - - if (!cache || !reg_list || !reg_arch_info) { - free(cache); - free(reg_list); - free(reg_arch_info); - return NULL; - } - - cache->name = "Andes registers"; - cache->next = NULL; - cache->reg_list = reg_list; - cache->num_regs = 0; - - for (i = 0; i < TOTAL_REG_NUM; i++) { - reg_arch_info[i].num = i; - reg_arch_info[i].target = target; - reg_arch_info[i].nds32 = nds32; - reg_arch_info[i].enable = false; - - reg_list[i].name = nds32_reg_simple_name(i); - reg_list[i].number = reg_arch_info[i].num; - reg_list[i].size = nds32_reg_size(i); - reg_list[i].arch_info = ®_arch_info[i]; - - reg_list[i].reg_data_type = calloc(sizeof(struct reg_data_type), 1); - - if (reg_arch_info[i].num >= FD0 && reg_arch_info[i].num <= FD31) { - reg_list[i].value = reg_arch_info[i].value; - reg_list[i].type = &nds32_reg_access_type_64; - - reg_list[i].reg_data_type->type = REG_TYPE_IEEE_DOUBLE; - reg_list[i].reg_data_type->id = "ieee_double"; - reg_list[i].group = "float"; - } else { - reg_list[i].value = reg_arch_info[i].value; - reg_list[i].type = &nds32_reg_access_type; - reg_list[i].group = "general"; - - if ((reg_arch_info[i].num >= FS0) && (reg_arch_info[i].num <= FS31)) { - reg_list[i].reg_data_type->type = REG_TYPE_IEEE_SINGLE; - reg_list[i].reg_data_type->id = "ieee_single"; - reg_list[i].group = "float"; - } else if ((reg_arch_info[i].num == FPCSR) || - (reg_arch_info[i].num == FPCFG)) { - reg_list[i].group = "float"; - } else if ((reg_arch_info[i].num == R28) || - (reg_arch_info[i].num == R29) || - (reg_arch_info[i].num == R31)) { - reg_list[i].reg_data_type->type = REG_TYPE_DATA_PTR; - reg_list[i].reg_data_type->id = "data_ptr"; - } else if ((reg_arch_info[i].num == R30) || - (reg_arch_info[i].num == PC)) { - reg_list[i].reg_data_type->type = REG_TYPE_CODE_PTR; - reg_list[i].reg_data_type->id = "code_ptr"; - } else { - reg_list[i].reg_data_type->type = REG_TYPE_UINT32; - reg_list[i].reg_data_type->id = "uint32"; - } - } - - if (reg_arch_info[i].num >= R16 && reg_arch_info[i].num <= R25) - reg_list[i].caller_save = true; - else - reg_list[i].caller_save = false; - - reg_list[i].feature = malloc(sizeof(struct reg_feature)); - - if (reg_arch_info[i].num >= R0 && reg_arch_info[i].num <= IFC_LP) - reg_list[i].feature->name = "org.gnu.gdb.nds32.core"; - else if (reg_arch_info[i].num >= CR0 && reg_arch_info[i].num <= SECUR0) - reg_list[i].feature->name = "org.gnu.gdb.nds32.system"; - else if (reg_arch_info[i].num >= D0L24 && reg_arch_info[i].num <= CBE3) - reg_list[i].feature->name = "org.gnu.gdb.nds32.audio"; - else if (reg_arch_info[i].num >= FPCSR && reg_arch_info[i].num <= FD31) - reg_list[i].feature->name = "org.gnu.gdb.nds32.fpu"; - - cache->num_regs++; - } - - nds32->core_cache = cache; - - return cache; -} - -static int nds32_reg_cache_init(struct target *target, struct nds32 *nds32) -{ - struct reg_cache *cache; - - cache = nds32_build_reg_cache(target, nds32); - if (!cache) - return ERROR_FAIL; - - *register_get_last_cache_p(&target->reg_cache) = cache; - - return ERROR_OK; -} - -static struct reg *nds32_reg_current(struct nds32 *nds32, unsigned regnum) -{ - struct reg *r; - - r = nds32->core_cache->reg_list + regnum; - - return r; -} - -int nds32_full_context(struct nds32 *nds32) -{ - uint32_t value, value_ir0; - - /* save $pc & $psw */ - nds32_get_mapped_reg(nds32, PC, &value); - nds32_get_mapped_reg(nds32, IR0, &value_ir0); - - nds32_update_psw(nds32); - nds32_update_mmu_info(nds32); - nds32_update_cache_info(nds32); - nds32_update_lm_info(nds32); - - nds32_check_extension(nds32); - - return ERROR_OK; -} - -/* get register value internally */ -int nds32_get_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t *value) -{ - struct reg_cache *reg_cache = nds32->core_cache; - struct reg *r; - - if (regnum > reg_cache->num_regs) - return ERROR_FAIL; - - r = nds32_reg_current(nds32, regnum); - - if (r->type->get(r) != ERROR_OK) - return ERROR_FAIL; - - *value = buf_get_u32(r->value, 0, 32); - - return ERROR_OK; -} - -/** set register internally */ -int nds32_set_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t value) -{ - struct reg_cache *reg_cache = nds32->core_cache; - struct reg *r; - uint8_t set_value[4]; - - if (regnum > reg_cache->num_regs) - return ERROR_FAIL; - - r = nds32_reg_current(nds32, regnum); - - buf_set_u32(set_value, 0, 32, value); - - return r->type->set(r, set_value); -} - -/** get general register list */ -static int nds32_get_general_reg_list(struct nds32 *nds32, - struct reg **reg_list[], int *reg_list_size) -{ - struct reg *reg_current; - int i; - int current_idx; - - /** freed in gdb_server.c */ - *reg_list = malloc(sizeof(struct reg *) * (IFC_LP - R0 + 1)); - current_idx = 0; - - for (i = R0; i < IFC_LP + 1; i++) { - reg_current = nds32_reg_current(nds32, i); - if (((struct nds32_reg *)reg_current->arch_info)->enable) { - (*reg_list)[current_idx] = reg_current; - current_idx++; - } - } - *reg_list_size = current_idx; - - return ERROR_OK; -} - -/** get all register list */ -static int nds32_get_all_reg_list(struct nds32 *nds32, - struct reg **reg_list[], int *reg_list_size) -{ - struct reg_cache *reg_cache = nds32->core_cache; - struct reg *reg_current; - unsigned int i; - - *reg_list_size = reg_cache->num_regs; - - /** freed in gdb_server.c */ - *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); - - for (i = 0; i < reg_cache->num_regs; i++) { - reg_current = nds32_reg_current(nds32, i); - reg_current->exist = ((struct nds32_reg *) - reg_current->arch_info)->enable; - (*reg_list)[i] = reg_current; - } - - return ERROR_OK; -} - -/** get all register list */ -int nds32_get_gdb_reg_list(struct target *target, - struct reg **reg_list[], int *reg_list_size, - enum target_register_class reg_class) -{ - struct nds32 *nds32 = target_to_nds32(target); - - switch (reg_class) { - case REG_CLASS_ALL: - return nds32_get_all_reg_list(nds32, reg_list, reg_list_size); - case REG_CLASS_GENERAL: - return nds32_get_general_reg_list(nds32, reg_list, reg_list_size); - default: - return ERROR_FAIL; - } - - return ERROR_FAIL; -} - -static int nds32_select_memory_mode(struct target *target, uint32_t address, - uint32_t length, uint32_t *end_address) -{ - struct nds32 *nds32 = target_to_nds32(target); - struct aice_port_s *aice = target_to_aice(target); - struct nds32_memory *memory = &(nds32->memory); - struct nds32_edm *edm = &(nds32->edm); - uint32_t dlm_start, dlm_end; - uint32_t ilm_start, ilm_end; - uint32_t address_end = address + length; - - /* init end_address */ - *end_address = address_end; - - if (memory->access_channel == NDS_MEMORY_ACC_CPU) - return ERROR_OK; - - if (edm->access_control == false) { - LOG_DEBUG("EDM does not support ACC_CTL"); - return ERROR_OK; - } - - if (edm->direct_access_local_memory == false) { - LOG_DEBUG("EDM does not support DALM"); - aice_memory_mode(aice, NDS_MEMORY_SELECT_MEM); - return ERROR_OK; - } - - if (memory->mode != NDS_MEMORY_SELECT_AUTO) { - LOG_DEBUG("Memory mode is not AUTO"); - return ERROR_OK; - } - - /* set default mode */ - aice_memory_mode(aice, NDS_MEMORY_SELECT_MEM); - - if ((memory->ilm_base != 0) && (memory->ilm_enable == true)) { - ilm_start = memory->ilm_start; - ilm_end = memory->ilm_end; - - /* case 1, address < ilm_start */ - if (address < ilm_start) { - if (ilm_start < address_end) { - /* update end_address to split non-ILM from ILM */ - *end_address = ilm_start; - } - /* MEM mode */ - aice_memory_mode(aice, NDS_MEMORY_SELECT_MEM); - } else if ((ilm_start <= address) && (address < ilm_end)) { - /* case 2, ilm_start <= address < ilm_end */ - if (ilm_end < address_end) { - /* update end_address to split non-ILM from ILM */ - *end_address = ilm_end; - } - /* ILM mode */ - aice_memory_mode(aice, NDS_MEMORY_SELECT_ILM); - } else { /* case 3, ilm_end <= address */ - /* MEM mode */ - aice_memory_mode(aice, NDS_MEMORY_SELECT_MEM); - } - - return ERROR_OK; - } else { - LOG_DEBUG("ILM is not enabled"); - } - - if ((memory->dlm_base != 0) && (memory->dlm_enable == true)) { - dlm_start = memory->dlm_start; - dlm_end = memory->dlm_end; - - /* case 1, address < dlm_start */ - if (address < dlm_start) { - if (dlm_start < address_end) { - /* update end_address to split non-DLM from DLM */ - *end_address = dlm_start; - } - /* MEM mode */ - aice_memory_mode(aice, NDS_MEMORY_SELECT_MEM); - } else if ((dlm_start <= address) && (address < dlm_end)) { - /* case 2, dlm_start <= address < dlm_end */ - if (dlm_end < address_end) { - /* update end_address to split non-DLM from DLM */ - *end_address = dlm_end; - } - /* DLM mode */ - aice_memory_mode(aice, NDS_MEMORY_SELECT_DLM); - } else { /* case 3, dlm_end <= address */ - /* MEM mode */ - aice_memory_mode(aice, NDS_MEMORY_SELECT_MEM); - } - - return ERROR_OK; - } else { - LOG_DEBUG("DLM is not enabled"); - } - - return ERROR_OK; -} - -int nds32_read_buffer(struct target *target, uint32_t address, - uint32_t size, uint8_t *buffer) -{ - struct nds32 *nds32 = target_to_nds32(target); - struct nds32_memory *memory = &(nds32->memory); - - if ((memory->access_channel == NDS_MEMORY_ACC_CPU) && - (target->state != TARGET_HALTED)) { - LOG_WARNING("target was not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - LOG_DEBUG("READ BUFFER: ADDR %08" PRIx32 " SIZE %08" PRIx32, - address, - size); - - int retval = ERROR_OK; - struct aice_port_s *aice = target_to_aice(target); - uint32_t end_address; - - if (((address % 2) == 0) && (size == 2)) { - nds32_select_memory_mode(target, address, 2, &end_address); - return aice_read_mem_unit(aice, address, 2, 1, buffer); - } - - /* handle unaligned head bytes */ - if (address % 4) { - uint32_t unaligned = 4 - (address % 4); - - if (unaligned > size) - unaligned = size; - - nds32_select_memory_mode(target, address, unaligned, &end_address); - retval = aice_read_mem_unit(aice, address, 1, unaligned, buffer); - if (retval != ERROR_OK) - return retval; - - buffer += unaligned; - address += unaligned; - size -= unaligned; - } - - /* handle aligned words */ - if (size >= 4) { - int aligned = size - (size % 4); - int read_len; - - do { - nds32_select_memory_mode(target, address, aligned, &end_address); - - read_len = end_address - address; - - if (read_len > 8) - retval = aice_read_mem_bulk(aice, address, read_len, buffer); - else - retval = aice_read_mem_unit(aice, address, 4, read_len / 4, buffer); - - if (retval != ERROR_OK) - return retval; - - buffer += read_len; - address += read_len; - size -= read_len; - aligned -= read_len; - - } while (aligned != 0); - } - - /*prevent byte access when possible (avoid AHB access limitations in some cases)*/ - if (size >= 2) { - int aligned = size - (size % 2); - nds32_select_memory_mode(target, address, aligned, &end_address); - retval = aice_read_mem_unit(aice, address, 2, aligned / 2, buffer); - if (retval != ERROR_OK) - return retval; - - buffer += aligned; - address += aligned; - size -= aligned; - } - /* handle tail writes of less than 4 bytes */ - if (size > 0) { - nds32_select_memory_mode(target, address, size, &end_address); - retval = aice_read_mem_unit(aice, address, 1, size, buffer); - if (retval != ERROR_OK) - return retval; - } - - return ERROR_OK; -} - -int nds32_read_memory(struct target *target, uint32_t address, - uint32_t size, uint32_t count, uint8_t *buffer) -{ - struct aice_port_s *aice = target_to_aice(target); - - return aice_read_mem_unit(aice, address, size, count, buffer); -} - -int nds32_read_phys_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) -{ - struct aice_port_s *aice = target_to_aice(target); - struct nds32 *nds32 = target_to_nds32(target); - struct nds32_memory *memory = &(nds32->memory); - enum nds_memory_access orig_channel; - int result; - - /* switch to BUS access mode to skip MMU */ - orig_channel = memory->access_channel; - memory->access_channel = NDS_MEMORY_ACC_BUS; - aice_memory_access(aice, memory->access_channel); - - /* The input address is physical address. No need to do address translation. */ - result = aice_read_mem_unit(aice, address, size, count, buffer); - - /* restore to origin access mode */ - memory->access_channel = orig_channel; - aice_memory_access(aice, memory->access_channel); - - return result; -} - -int nds32_write_buffer(struct target *target, uint32_t address, - uint32_t size, const uint8_t *buffer) -{ - struct nds32 *nds32 = target_to_nds32(target); - struct nds32_memory *memory = &(nds32->memory); - - if ((memory->access_channel == NDS_MEMORY_ACC_CPU) && - (target->state != TARGET_HALTED)) { - LOG_WARNING("target was not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - LOG_DEBUG("WRITE BUFFER: ADDR %08" PRIx32 " SIZE %08" PRIx32, - address, - size); - - struct aice_port_s *aice = target_to_aice(target); - int retval = ERROR_OK; - uint32_t end_address; - - if (((address % 2) == 0) && (size == 2)) { - nds32_select_memory_mode(target, address, 2, &end_address); - return aice_write_mem_unit(aice, address, 2, 1, buffer); - } - - /* handle unaligned head bytes */ - if (address % 4) { - uint32_t unaligned = 4 - (address % 4); - - if (unaligned > size) - unaligned = size; - - nds32_select_memory_mode(target, address, unaligned, &end_address); - retval = aice_write_mem_unit(aice, address, 1, unaligned, buffer); - if (retval != ERROR_OK) - return retval; - - buffer += unaligned; - address += unaligned; - size -= unaligned; - } - - /* handle aligned words */ - if (size >= 4) { - int aligned = size - (size % 4); - int write_len; - - do { - nds32_select_memory_mode(target, address, aligned, &end_address); - - write_len = end_address - address; - if (write_len > 8) - retval = aice_write_mem_bulk(aice, address, write_len, buffer); - else - retval = aice_write_mem_unit(aice, address, 4, write_len / 4, buffer); - if (retval != ERROR_OK) - return retval; - - buffer += write_len; - address += write_len; - size -= write_len; - aligned -= write_len; - - } while (aligned != 0); - } - - /* handle tail writes of less than 4 bytes */ - if (size > 0) { - nds32_select_memory_mode(target, address, size, &end_address); - retval = aice_write_mem_unit(aice, address, 1, size, buffer); - if (retval != ERROR_OK) - return retval; - } - - return retval; -} - -int nds32_write_memory(struct target *target, uint32_t address, - uint32_t size, uint32_t count, const uint8_t *buffer) -{ - struct aice_port_s *aice = target_to_aice(target); - - return aice_write_mem_unit(aice, address, size, count, buffer); -} - -int nds32_write_phys_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer) -{ - struct aice_port_s *aice = target_to_aice(target); - struct nds32 *nds32 = target_to_nds32(target); - struct nds32_memory *memory = &(nds32->memory); - enum nds_memory_access orig_channel; - int result; - - /* switch to BUS access mode to skip MMU */ - orig_channel = memory->access_channel; - memory->access_channel = NDS_MEMORY_ACC_BUS; - aice_memory_access(aice, memory->access_channel); - - /* The input address is physical address. No need to do address translation. */ - result = aice_write_mem_unit(aice, address, size, count, buffer); - - /* restore to origin access mode */ - memory->access_channel = orig_channel; - aice_memory_access(aice, memory->access_channel); - - return result; -} - -int nds32_mmu(struct target *target, int *enabled) -{ - if (target->state != TARGET_HALTED) { - LOG_ERROR("%s: target not halted", __func__); - return ERROR_TARGET_INVALID; - } - - struct nds32 *nds32 = target_to_nds32(target); - struct nds32_memory *memory = &(nds32->memory); - struct nds32_mmu_config *mmu_config = &(nds32->mmu_config); - - if ((mmu_config->memory_protection == 2) && (memory->address_translation == true)) - *enabled = 1; - else - *enabled = 0; - - return ERROR_OK; -} - -int nds32_arch_state(struct target *target) -{ - struct nds32 *nds32 = target_to_nds32(target); - - if (nds32->common_magic != NDS32_COMMON_MAGIC) { - LOG_ERROR("BUG: called for a non-Andes target"); - return ERROR_FAIL; - } - - uint32_t value_pc, value_psw; - - nds32_get_mapped_reg(nds32, PC, &value_pc); - nds32_get_mapped_reg(nds32, IR0, &value_psw); - - LOG_USER("target halted due to %s\n" - "psw: 0x%8.8" PRIx32 " pc: 0x%8.8" PRIx32 "%s", - debug_reason_name(target), - value_psw, - value_pc, - nds32->virtual_hosting ? ", virtual hosting" : ""); - - /* save pc value to pseudo register pc */ - struct reg *reg = register_get_by_name(target->reg_cache, "pc", true); - buf_set_u32(reg->value, 0, 32, value_pc); - - return ERROR_OK; -} - -static void nds32_init_must_have_registers(struct nds32 *nds32) -{ - struct reg_cache *reg_cache = nds32->core_cache; - - /** MUST have general registers */ - ((struct nds32_reg *)reg_cache->reg_list[R0].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R1].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R2].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R3].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R4].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R5].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R6].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R7].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R8].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R9].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R10].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R15].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R28].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R29].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R30].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R31].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[PC].arch_info)->enable = true; - - /** MUST have configuration system registers */ - ((struct nds32_reg *)reg_cache->reg_list[CR0].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[CR1].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[CR2].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[CR3].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[CR4].arch_info)->enable = true; - - /** MUST have interrupt system registers */ - ((struct nds32_reg *)reg_cache->reg_list[IR0].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR1].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR3].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR4].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR6].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR9].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR11].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR14].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR15].arch_info)->enable = true; - - /** MUST have MMU system registers */ - ((struct nds32_reg *)reg_cache->reg_list[MR0].arch_info)->enable = true; - - /** MUST have EDM system registers */ - ((struct nds32_reg *)reg_cache->reg_list[DR40].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[DR42].arch_info)->enable = true; -} - -static int nds32_init_memory_config(struct nds32 *nds32) -{ - uint32_t value_cr1; /* ICM_CFG */ - uint32_t value_cr2; /* DCM_CFG */ - struct nds32_memory *memory = &(nds32->memory); - - /* read $cr1 to init instruction memory information */ - nds32_get_mapped_reg(nds32, CR1, &value_cr1); - memory->icache.set = value_cr1 & 0x7; - memory->icache.way = (value_cr1 >> 3) & 0x7; - memory->icache.line_size = (value_cr1 >> 6) & 0x7; - memory->icache.lock_support = (value_cr1 >> 9) & 0x1; - - memory->ilm_base = (value_cr1 >> 10) & 0x7; - memory->ilm_align_ver = (value_cr1 >> 13) & 0x3; - - /* read $cr2 to init data memory information */ - nds32_get_mapped_reg(nds32, CR2, &value_cr2); - memory->dcache.set = value_cr2 & 0x7; - memory->dcache.way = (value_cr2 >> 3) & 0x7; - memory->dcache.line_size = (value_cr2 >> 6) & 0x7; - memory->dcache.lock_support = (value_cr2 >> 9) & 0x1; - - memory->dlm_base = (value_cr2 >> 10) & 0x7; - memory->dlm_align_ver = (value_cr2 >> 13) & 0x3; - - return ERROR_OK; -} - -static void nds32_init_config(struct nds32 *nds32) -{ - uint32_t value_cr0; - uint32_t value_cr3; - uint32_t value_cr4; - struct nds32_cpu_version *cpu_version = &(nds32->cpu_version); - struct nds32_mmu_config *mmu_config = &(nds32->mmu_config); - struct nds32_misc_config *misc_config = &(nds32->misc_config); - - nds32_get_mapped_reg(nds32, CR0, &value_cr0); - nds32_get_mapped_reg(nds32, CR3, &value_cr3); - nds32_get_mapped_reg(nds32, CR4, &value_cr4); - - /* config cpu version */ - cpu_version->performance_extension = value_cr0 & 0x1; - cpu_version->_16bit_extension = (value_cr0 >> 1) & 0x1; - cpu_version->performance_extension_2 = (value_cr0 >> 2) & 0x1; - cpu_version->cop_fpu_extension = (value_cr0 >> 3) & 0x1; - cpu_version->string_extension = (value_cr0 >> 4) & 0x1; - cpu_version->revision = (value_cr0 >> 16) & 0xFF; - cpu_version->cpu_id_family = (value_cr0 >> 24) & 0xF; - cpu_version->cpu_id_version = (value_cr0 >> 28) & 0xF; - - /* config MMU */ - mmu_config->memory_protection = value_cr3 & 0x3; - mmu_config->memory_protection_version = (value_cr3 >> 2) & 0x1F; - mmu_config->fully_associative_tlb = (value_cr3 >> 7) & 0x1; - if (mmu_config->fully_associative_tlb) { - mmu_config->tlb_size = (value_cr3 >> 8) & 0x7F; - } else { - mmu_config->tlb_ways = (value_cr3 >> 8) & 0x7; - mmu_config->tlb_sets = (value_cr3 >> 11) & 0x7; - } - mmu_config->_8k_page_support = (value_cr3 >> 15) & 0x1; - mmu_config->extra_page_size_support = (value_cr3 >> 16) & 0xFF; - mmu_config->tlb_lock = (value_cr3 >> 24) & 0x1; - mmu_config->hardware_page_table_walker = (value_cr3 >> 25) & 0x1; - mmu_config->default_endian = (value_cr3 >> 26) & 0x1; - mmu_config->partition_num = (value_cr3 >> 27) & 0x1; - mmu_config->invisible_tlb = (value_cr3 >> 28) & 0x1; - mmu_config->vlpt = (value_cr3 >> 29) & 0x1; - mmu_config->ntme = (value_cr3 >> 30) & 0x1; - mmu_config->drde = (value_cr3 >> 31) & 0x1; - - /* config misc */ - misc_config->edm = value_cr4 & 0x1; - misc_config->local_memory_dma = (value_cr4 >> 1) & 0x1; - misc_config->performance_monitor = (value_cr4 >> 2) & 0x1; - misc_config->high_speed_memory_port = (value_cr4 >> 3) & 0x1; - misc_config->debug_tracer = (value_cr4 >> 4) & 0x1; - misc_config->div_instruction = (value_cr4 >> 5) & 0x1; - misc_config->mac_instruction = (value_cr4 >> 6) & 0x1; - misc_config->audio_isa = (value_cr4 >> 7) & 0x3; - misc_config->l2_cache = (value_cr4 >> 9) & 0x1; - misc_config->reduce_register = (value_cr4 >> 10) & 0x1; - misc_config->addr_24 = (value_cr4 >> 11) & 0x1; - misc_config->interruption_level = (value_cr4 >> 12) & 0x1; - misc_config->baseline_instruction = (value_cr4 >> 13) & 0x7; - misc_config->no_dx_register = (value_cr4 >> 16) & 0x1; - misc_config->implement_dependant_register = (value_cr4 >> 17) & 0x1; - misc_config->implement_dependant_sr_encoding = (value_cr4 >> 18) & 0x1; - misc_config->ifc = (value_cr4 >> 19) & 0x1; - misc_config->mcu = (value_cr4 >> 20) & 0x1; - misc_config->shadow = (value_cr4 >> 21) & 0x7; - misc_config->ex9 = (value_cr4 >> 24) & 0x1; - - nds32_init_memory_config(nds32); -} - -static int nds32_init_option_registers(struct nds32 *nds32) -{ - struct reg_cache *reg_cache = nds32->core_cache; - struct nds32_cpu_version *cpu_version = &(nds32->cpu_version); - struct nds32_mmu_config *mmu_config = &(nds32->mmu_config); - struct nds32_misc_config *misc_config = &(nds32->misc_config); - struct nds32_memory *memory_config = &(nds32->memory); - - bool no_cr5; - bool mr10_exist; - bool no_racr0; - - if (((cpu_version->cpu_id_family == 0xC) || (cpu_version->cpu_id_family == 0xD)) && - ((cpu_version->revision & 0xFC) == 0)) { - no_cr5 = true; - mr10_exist = true; - no_racr0 = true; - } else { - no_cr5 = false; - mr10_exist = false; - no_racr0 = false; - } - - if (misc_config->reduce_register == false) { - ((struct nds32_reg *)reg_cache->reg_list[R11].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R12].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R13].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R14].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R16].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R17].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R18].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R19].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R20].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R21].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R22].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R23].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R24].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R25].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R26].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[R27].arch_info)->enable = true; - } - - if (misc_config->no_dx_register == false) { - ((struct nds32_reg *)reg_cache->reg_list[D0LO].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[D0HI].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[D1LO].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[D1HI].arch_info)->enable = true; - } - - if (misc_config->ex9) - ((struct nds32_reg *)reg_cache->reg_list[ITB].arch_info)->enable = true; - - if (no_cr5 == false) - ((struct nds32_reg *)reg_cache->reg_list[CR5].arch_info)->enable = true; - - if (cpu_version->cop_fpu_extension) { - ((struct nds32_reg *)reg_cache->reg_list[CR6].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[FPCSR].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[FPCFG].arch_info)->enable = true; - } - - if (mmu_config->memory_protection == 1) { - /* Secure MPU has no IPC, IPSW, P_ITYPE */ - ((struct nds32_reg *)reg_cache->reg_list[IR1].arch_info)->enable = false; - ((struct nds32_reg *)reg_cache->reg_list[IR9].arch_info)->enable = false; - } - - if (nds32->privilege_level != 0) - ((struct nds32_reg *)reg_cache->reg_list[IR3].arch_info)->enable = false; - - if (misc_config->mcu == true) - ((struct nds32_reg *)reg_cache->reg_list[IR4].arch_info)->enable = false; - - if (misc_config->interruption_level == false) { - ((struct nds32_reg *)reg_cache->reg_list[IR2].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR5].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR10].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR12].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR13].arch_info)->enable = true; - - /* Secure MPU has no IPC, IPSW, P_ITYPE */ - if (mmu_config->memory_protection != 1) - ((struct nds32_reg *)reg_cache->reg_list[IR7].arch_info)->enable = true; - } - - if ((cpu_version->cpu_id_family == 0x9) || - (cpu_version->cpu_id_family == 0xA) || - (cpu_version->cpu_id_family == 0xC) || - (cpu_version->cpu_id_family == 0xD)) - ((struct nds32_reg *)reg_cache->reg_list[IR8].arch_info)->enable = true; - - if (misc_config->shadow == 1) { - ((struct nds32_reg *)reg_cache->reg_list[IR16].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR17].arch_info)->enable = true; - } - - if (misc_config->ifc) - ((struct nds32_reg *)reg_cache->reg_list[IFC_LP].arch_info)->enable = true; - - if (nds32->privilege_level != 0) - ((struct nds32_reg *)reg_cache->reg_list[MR0].arch_info)->enable = false; - - if (mmu_config->memory_protection == 1) { - if (mmu_config->memory_protection_version == 24) - ((struct nds32_reg *)reg_cache->reg_list[MR4].arch_info)->enable = true; - - if (nds32->privilege_level == 0) { - if ((mmu_config->memory_protection_version == 16) || - (mmu_config->memory_protection_version == 24)) { - ((struct nds32_reg *)reg_cache->reg_list[MR11].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[SECUR0].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR20].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR22].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR24].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR30].arch_info)->enable = true; - - if (misc_config->shadow == 1) { - ((struct nds32_reg *)reg_cache->reg_list[IR21].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR23].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR25].arch_info)->enable = true; - } - } - } - } else if (mmu_config->memory_protection == 2) { - ((struct nds32_reg *)reg_cache->reg_list[MR1].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[MR4].arch_info)->enable = true; - - if ((cpu_version->cpu_id_family != 0xA) && (cpu_version->cpu_id_family != 0xC) && - (cpu_version->cpu_id_family != 0xD)) - ((struct nds32_reg *)reg_cache->reg_list[MR5].arch_info)->enable = true; - } - - if (mmu_config->memory_protection > 0) { - ((struct nds32_reg *)reg_cache->reg_list[MR2].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[MR3].arch_info)->enable = true; - } - - if (memory_config->ilm_base != 0) - if (nds32->privilege_level == 0) - ((struct nds32_reg *)reg_cache->reg_list[MR6].arch_info)->enable = true; - - if (memory_config->dlm_base != 0) - if (nds32->privilege_level == 0) - ((struct nds32_reg *)reg_cache->reg_list[MR7].arch_info)->enable = true; - - if ((memory_config->icache.line_size != 0) && (memory_config->dcache.line_size != 0)) - ((struct nds32_reg *)reg_cache->reg_list[MR8].arch_info)->enable = true; - - if (misc_config->high_speed_memory_port) - ((struct nds32_reg *)reg_cache->reg_list[MR9].arch_info)->enable = true; - - if (mr10_exist) - ((struct nds32_reg *)reg_cache->reg_list[MR10].arch_info)->enable = true; - - if (misc_config->edm) { - int dr_reg_n = nds32->edm.breakpoint_num * 5; - - for (int i = 0 ; i < dr_reg_n ; i++) - ((struct nds32_reg *)reg_cache->reg_list[DR0 + i].arch_info)->enable = true; - - ((struct nds32_reg *)reg_cache->reg_list[DR41].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[DR43].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[DR44].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[DR45].arch_info)->enable = true; - } - - if (misc_config->debug_tracer) { - ((struct nds32_reg *)reg_cache->reg_list[DR46].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[DR47].arch_info)->enable = true; - } - - if (misc_config->performance_monitor) { - ((struct nds32_reg *)reg_cache->reg_list[PFR0].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[PFR1].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[PFR2].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[PFR3].arch_info)->enable = true; - } - - if (misc_config->local_memory_dma) { - ((struct nds32_reg *)reg_cache->reg_list[DMAR0].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[DMAR1].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[DMAR2].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[DMAR3].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[DMAR4].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[DMAR5].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[DMAR6].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[DMAR7].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[DMAR8].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[DMAR9].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[DMAR10].arch_info)->enable = true; - } - - if ((misc_config->local_memory_dma || misc_config->performance_monitor) && - (no_racr0 == false)) - ((struct nds32_reg *)reg_cache->reg_list[RACR].arch_info)->enable = true; - - if (cpu_version->cop_fpu_extension || (misc_config->audio_isa != 0)) - ((struct nds32_reg *)reg_cache->reg_list[FUCPR].arch_info)->enable = true; - - if (misc_config->audio_isa != 0) { - if (misc_config->audio_isa > 1) { - ((struct nds32_reg *)reg_cache->reg_list[D0L24].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[D1L24].arch_info)->enable = true; - } - - ((struct nds32_reg *)reg_cache->reg_list[I0].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[I1].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[I2].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[I3].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[I4].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[I5].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[I6].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[I7].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[M1].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[M2].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[M3].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[M5].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[M6].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[M7].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[MOD].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[LBE].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[LE].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[LC].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[ADM_VBASE].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[SHFT_CTL0].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[SHFT_CTL1].arch_info)->enable = true; - - uint32_t value_mod; - uint32_t fucpr_backup; - /* enable fpu and get configuration */ - nds32_get_mapped_reg(nds32, FUCPR, &fucpr_backup); - if ((fucpr_backup & 0x80000000) == 0) - nds32_set_mapped_reg(nds32, FUCPR, fucpr_backup | 0x80000000); - nds32_get_mapped_reg(nds32, MOD, &value_mod); - /* restore origin fucpr value */ - if ((fucpr_backup & 0x80000000) == 0) - nds32_set_mapped_reg(nds32, FUCPR, fucpr_backup); - - if ((value_mod >> 6) & 0x1) { - ((struct nds32_reg *)reg_cache->reg_list[CB_CTL].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[CBB0].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[CBB1].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[CBB2].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[CBB3].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[CBE0].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[CBE1].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[CBE2].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[CBE3].arch_info)->enable = true; - } - } - - if ((cpu_version->cpu_id_family == 0x9) || - (cpu_version->cpu_id_family == 0xA) || - (cpu_version->cpu_id_family == 0xC)) { - - ((struct nds32_reg *)reg_cache->reg_list[IDR0].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IDR1].arch_info)->enable = true; - - if ((cpu_version->cpu_id_family == 0xC) && (cpu_version->revision == 0x0C)) - ((struct nds32_reg *)reg_cache->reg_list[IDR0].arch_info)->enable = false; - } - - uint32_t ir3_value; - uint32_t ivb_prog_pri_lvl; - uint32_t ivb_ivic_ver; - - nds32_get_mapped_reg(nds32, IR3, &ir3_value); - ivb_prog_pri_lvl = ir3_value & 0x1; - ivb_ivic_ver = (ir3_value >> 11) & 0x3; - - if ((ivb_prog_pri_lvl == 1) || (ivb_ivic_ver >= 1)) { - ((struct nds32_reg *)reg_cache->reg_list[IR18].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR19].arch_info)->enable = true; - } - - if (ivb_ivic_ver >= 1) { - ((struct nds32_reg *)reg_cache->reg_list[IR26].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR27].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR28].arch_info)->enable = true; - ((struct nds32_reg *)reg_cache->reg_list[IR29].arch_info)->enable = true; - } - - return ERROR_OK; -} - -int nds32_init_register_table(struct nds32 *nds32) -{ - nds32_init_must_have_registers(nds32); - - return ERROR_OK; -} - -int nds32_add_software_breakpoint(struct target *target, - struct breakpoint *breakpoint) -{ - uint32_t data; - uint32_t check_data; - uint32_t break_insn; - - /* check the breakpoint size */ - target->type->read_buffer(target, breakpoint->address, 4, (uint8_t *)&data); - - /* backup origin instruction - * instruction is big-endian */ - if (*(char *)&data & 0x80) { /* 16-bits instruction */ - breakpoint->length = 2; - break_insn = NDS32_BREAK_16; - } else { /* 32-bits instruction */ - breakpoint->length = 4; - break_insn = NDS32_BREAK_32; - } - - free(breakpoint->orig_instr); - - breakpoint->orig_instr = malloc(breakpoint->length); - memcpy(breakpoint->orig_instr, &data, breakpoint->length); - - /* self-modified code */ - target->type->write_buffer(target, breakpoint->address, breakpoint->length, (const uint8_t *)&break_insn); - /* write_back & invalidate dcache & invalidate icache */ - nds32_cache_sync(target, breakpoint->address, breakpoint->length); - - /* read back to check */ - target->type->read_buffer(target, breakpoint->address, breakpoint->length, (uint8_t *)&check_data); - if (memcmp(&check_data, &break_insn, breakpoint->length) == 0) - return ERROR_OK; - - return ERROR_FAIL; -} - -int nds32_remove_software_breakpoint(struct target *target, - struct breakpoint *breakpoint) -{ - uint32_t check_data; - uint32_t break_insn; - - if (breakpoint->length == 2) - break_insn = NDS32_BREAK_16; - else if (breakpoint->length == 4) - break_insn = NDS32_BREAK_32; - else - return ERROR_FAIL; - - target->type->read_buffer(target, breakpoint->address, breakpoint->length, - (uint8_t *)&check_data); - - /* break instruction is modified */ - if (memcmp(&check_data, &break_insn, breakpoint->length) != 0) - return ERROR_FAIL; - - /* self-modified code */ - target->type->write_buffer(target, breakpoint->address, breakpoint->length, - breakpoint->orig_instr); - - /* write_back & invalidate dcache & invalidate icache */ - nds32_cache_sync(target, breakpoint->address, breakpoint->length); - - return ERROR_OK; -} - -/** - * Restore the processor context on an Andes target. The full processor - * context is analyzed to see if any of the registers are dirty on this end, but - * have a valid new value. If this is the case, the processor is changed to the - * appropriate mode and the new register values are written out to the - * processor. If there happens to be a dirty register with an invalid value, an - * error will be logged. - * - * @param target Pointer to the Andes target to have its context restored - * @return Error status if the target is not halted. - */ -int nds32_restore_context(struct target *target) -{ - struct nds32 *nds32 = target_to_nds32(target); - struct aice_port_s *aice = target_to_aice(target); - struct reg_cache *reg_cache = nds32->core_cache; - struct reg *reg; - struct nds32_reg *reg_arch_info; - unsigned int i; - - LOG_DEBUG("-"); - - if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* check if there are dirty registers */ - for (i = 0; i < reg_cache->num_regs; i++) { - reg = &(reg_cache->reg_list[i]); - if (reg->dirty == true) { - if (reg->valid == true) { - - LOG_DEBUG("examining dirty reg: %s", reg->name); - LOG_DEBUG("writing register %d with value 0x%8.8" PRIx32, - i, buf_get_u32(reg->value, 0, 32)); - - reg_arch_info = reg->arch_info; - if (reg_arch_info->num >= FD0 && reg_arch_info->num <= FD31) { - uint64_t val = buf_get_u64(reg_arch_info->value, 0, 64); - aice_write_reg_64(aice, reg_arch_info->num, val); - } else { - uint32_t val = buf_get_u32(reg_arch_info->value, 0, 32); - aice_write_register(aice, reg_arch_info->num, val); - } - - reg->valid = true; - reg->dirty = false; - } - } - } - - return ERROR_OK; -} - -int nds32_edm_config(struct nds32 *nds32) -{ - struct target *target = nds32->target; - struct aice_port_s *aice = target_to_aice(target); - uint32_t edm_cfg; - uint32_t edm_ctl; - - aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg); - - nds32->edm.version = (edm_cfg >> 16) & 0xFFFF; - LOG_INFO("EDM version 0x%04x", nds32->edm.version); - - nds32->edm.breakpoint_num = (edm_cfg & 0x7) + 1; - - if ((nds32->edm.version & 0x1000) || (nds32->edm.version >= 0x60)) - nds32->edm.access_control = true; - else - nds32->edm.access_control = false; - - if ((edm_cfg >> 4) & 0x1) - nds32->edm.direct_access_local_memory = true; - else - nds32->edm.direct_access_local_memory = false; - - if (nds32->edm.version <= 0x20) - nds32->edm.direct_access_local_memory = false; - - aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl); - if (edm_ctl & (0x1 << 29)) - nds32->edm.support_max_stop = true; - else - nds32->edm.support_max_stop = false; - - /* set passcode for secure MCU */ - nds32_login(nds32); - - return ERROR_OK; -} - -int nds32_config(struct nds32 *nds32) -{ - nds32_init_config(nds32); - - /* init optional system registers according to config registers */ - nds32_init_option_registers(nds32); - - /* get max interrupt level */ - if (nds32->misc_config.interruption_level) - nds32->max_interrupt_level = 2; - else - nds32->max_interrupt_level = 3; - - /* get ILM/DLM size from MR6/MR7 */ - uint32_t value_mr6, value_mr7; - uint32_t size_index; - nds32_get_mapped_reg(nds32, MR6, &value_mr6); - size_index = (value_mr6 >> 1) & 0xF; - nds32->memory.ilm_size = nds32_lm_size_table[size_index]; - - nds32_get_mapped_reg(nds32, MR7, &value_mr7); - size_index = (value_mr7 >> 1) & 0xF; - nds32->memory.dlm_size = nds32_lm_size_table[size_index]; - - return ERROR_OK; -} - -int nds32_init_arch_info(struct target *target, struct nds32 *nds32) -{ - target->arch_info = nds32; - nds32->target = target; - - nds32->common_magic = NDS32_COMMON_MAGIC; - nds32->init_arch_info_after_halted = false; - nds32->auto_convert_hw_bp = true; - nds32->global_stop = false; - nds32->soft_reset_halt = false; - nds32->edm_passcode = NULL; - nds32->privilege_level = 0; - nds32->boot_time = 1500; - nds32->reset_halt_as_examine = false; - nds32->keep_target_edm_ctl = false; - nds32->word_access_mem = false; - nds32->virtual_hosting = true; - nds32->hit_syscall = false; - nds32->active_syscall_id = NDS32_SYSCALL_UNDEFINED; - nds32->virtual_hosting_errno = 0; - nds32->virtual_hosting_ctrl_c = false; - nds32->attached = false; - - nds32->syscall_break.asid = 0; - nds32->syscall_break.length = 4; - nds32->syscall_break.is_set = false; - nds32->syscall_break.orig_instr = NULL; - nds32->syscall_break.next = NULL; - nds32->syscall_break.unique_id = 0x515CAll + target->target_number; - nds32->syscall_break.linked_brp = 0; - - nds32_reg_init(); - - if (nds32_reg_cache_init(target, nds32) == ERROR_FAIL) - return ERROR_FAIL; - - if (nds32_init_register_table(nds32) != ERROR_OK) - return ERROR_FAIL; - - return ERROR_OK; -} - -int nds32_virtual_to_physical(struct target *target, target_addr_t address, target_addr_t *physical) -{ - struct nds32 *nds32 = target_to_nds32(target); - - if (nds32->memory.address_translation == false) { - *physical = address; - return ERROR_OK; - } - - if (nds32_probe_tlb(nds32, address, physical) == ERROR_OK) - return ERROR_OK; - - if (nds32_walk_page_table(nds32, address, physical) == ERROR_OK) - return ERROR_OK; - - return ERROR_FAIL; -} - -int nds32_cache_sync(struct target *target, target_addr_t address, uint32_t length) -{ - struct aice_port_s *aice = target_to_aice(target); - struct nds32 *nds32 = target_to_nds32(target); - struct nds32_cache *dcache = &(nds32->memory.dcache); - struct nds32_cache *icache = &(nds32->memory.icache); - uint32_t dcache_line_size = nds32_line_size_table[dcache->line_size]; - uint32_t icache_line_size = nds32_line_size_table[icache->line_size]; - uint32_t cur_address; - int result; - uint32_t start_line, end_line; - uint32_t cur_line; - - if ((dcache->line_size != 0) && (dcache->enable == true)) { - /* address / dcache_line_size */ - start_line = address >> (dcache->line_size + 2); - /* (address + length - 1) / dcache_line_size */ - end_line = (address + length - 1) >> (dcache->line_size + 2); - - for (cur_address = address, cur_line = start_line; - cur_line <= end_line; - cur_address += dcache_line_size, cur_line++) { - /* D$ write back */ - result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1D_VA_WB, cur_address); - if (result != ERROR_OK) - return result; - - /* D$ invalidate */ - result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1D_VA_INVAL, cur_address); - if (result != ERROR_OK) - return result; - } - } - - if ((icache->line_size != 0) && (icache->enable == true)) { - /* address / icache_line_size */ - start_line = address >> (icache->line_size + 2); - /* (address + length - 1) / icache_line_size */ - end_line = (address + length - 1) >> (icache->line_size + 2); - - for (cur_address = address, cur_line = start_line; - cur_line <= end_line; - cur_address += icache_line_size, cur_line++) { - /* Because PSW.IT is turned off under debug exception, address MUST - * be physical address. L1I_VA_INVALIDATE uses PSW.IT to decide - * address translation or not. */ - target_addr_t physical_addr; - if (target->type->virt2phys(target, cur_address, &physical_addr) == ERROR_FAIL) - return ERROR_FAIL; - - /* I$ invalidate */ - result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1I_VA_INVAL, physical_addr); - if (result != ERROR_OK) - return result; - } - } - - return ERROR_OK; -} - -uint32_t nds32_nextpc(struct nds32 *nds32, int current, uint32_t address) -{ - if (!current) - nds32_set_mapped_reg(nds32, PC, address); - else - nds32_get_mapped_reg(nds32, PC, &address); - - return address; -} - -int nds32_step(struct target *target, int current, - target_addr_t address, int handle_breakpoints) -{ - LOG_DEBUG("target->state: %s", - target_state_name(target)); - - if (target->state != TARGET_HALTED) { - LOG_WARNING("target was not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - struct nds32 *nds32 = target_to_nds32(target); - - address = nds32_nextpc(nds32, current, address); - - LOG_DEBUG("STEP PC %08" TARGET_PRIxADDR "%s", address, !current ? "!" : ""); - - /** set DSSIM */ - uint32_t ir14_value; - nds32_get_mapped_reg(nds32, IR14, &ir14_value); - if (nds32->step_isr_enable) - ir14_value |= (0x1 << 31); - else - ir14_value &= ~(0x1 << 31); - nds32_set_mapped_reg(nds32, IR14, ir14_value); - - /* check hit_syscall before leave_debug_state() because - * leave_debug_state() may clear hit_syscall flag */ - bool no_step = false; - if (nds32->hit_syscall) - /* step after hit_syscall should be ignored because - * leave_debug_state will step implicitly to skip the - * syscall */ - no_step = true; - - /********* TODO: maybe create another function to handle this part */ - CHECK_RETVAL(nds32->leave_debug_state(nds32, true)); - CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); - - if (no_step == false) { - struct aice_port_s *aice = target_to_aice(target); - if (aice_step(aice) != ERROR_OK) - return ERROR_FAIL; - } - - /* save state */ - CHECK_RETVAL(nds32->enter_debug_state(nds32, true)); - /********* TODO: maybe create another function to handle this part */ - - /* restore DSSIM */ - if (nds32->step_isr_enable) { - nds32_get_mapped_reg(nds32, IR14, &ir14_value); - ir14_value &= ~(0x1 << 31); - nds32_set_mapped_reg(nds32, IR14, ir14_value); - } - - CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); - - return ERROR_OK; -} - -static int nds32_step_without_watchpoint(struct nds32 *nds32) -{ - struct target *target = nds32->target; - - if (target->state != TARGET_HALTED) { - LOG_WARNING("target was not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /** set DSSIM */ - uint32_t ir14_value; - nds32_get_mapped_reg(nds32, IR14, &ir14_value); - if (nds32->step_isr_enable) - ir14_value |= (0x1 << 31); - else - ir14_value &= ~(0x1 << 31); - nds32_set_mapped_reg(nds32, IR14, ir14_value); - - /********* TODO: maybe create another function to handle this part */ - CHECK_RETVAL(nds32->leave_debug_state(nds32, false)); - - struct aice_port_s *aice = target_to_aice(target); - - if (aice_step(aice) != ERROR_OK) - return ERROR_FAIL; - - /* save state */ - CHECK_RETVAL(nds32->enter_debug_state(nds32, false)); - /********* TODO: maybe create another function to handle this part */ - - /* restore DSSIM */ - if (nds32->step_isr_enable) { - nds32_get_mapped_reg(nds32, IR14, &ir14_value); - ir14_value &= ~(0x1 << 31); - nds32_set_mapped_reg(nds32, IR14, ir14_value); - } - - return ERROR_OK; -} - -int nds32_target_state(struct nds32 *nds32, enum target_state *state) -{ - struct aice_port_s *aice = target_to_aice(nds32->target); - enum aice_target_state_s nds32_state; - - if (aice_state(aice, &nds32_state) != ERROR_OK) - return ERROR_FAIL; - - switch (nds32_state) { - case AICE_DISCONNECT: - LOG_INFO("USB is disconnected"); - return ERROR_FAIL; - case AICE_TARGET_DETACH: - LOG_INFO("Target is disconnected"); - return ERROR_FAIL; - case AICE_TARGET_UNKNOWN: - *state = TARGET_UNKNOWN; - break; - case AICE_TARGET_RUNNING: - *state = TARGET_RUNNING; - break; - case AICE_TARGET_HALTED: - *state = TARGET_HALTED; - break; - case AICE_TARGET_RESET: - *state = TARGET_RESET; - break; - case AICE_TARGET_DEBUG_RUNNING: - *state = TARGET_DEBUG_RUNNING; - break; - default: - return ERROR_FAIL; - } - - return ERROR_OK; -} - -int nds32_examine_debug_reason(struct nds32 *nds32) -{ - uint32_t reason; - struct target *target = nds32->target; - - if (nds32->hit_syscall == true) { - LOG_DEBUG("Hit syscall breakpoint"); - target->debug_reason = DBG_REASON_BREAKPOINT; - return ERROR_OK; - } - - nds32->get_debug_reason(nds32, &reason); - - LOG_DEBUG("nds32 examines debug reason: %s", nds32_debug_type_name[reason]); - - /* Examine debug reason */ - switch (reason) { - case NDS32_DEBUG_BREAK: - case NDS32_DEBUG_BREAK_16: - case NDS32_DEBUG_INST_BREAK: - { - uint32_t value_pc; - uint32_t opcode; - struct nds32_instruction instruction; - - nds32_get_mapped_reg(nds32, PC, &value_pc); - - if (nds32_read_opcode(nds32, value_pc, &opcode) != ERROR_OK) - return ERROR_FAIL; - if (nds32_evaluate_opcode(nds32, opcode, value_pc, &instruction) != ERROR_OK) - return ERROR_FAIL; - - /* hit 'break 0x7FFF' */ - if ((instruction.info.opc_6 == 0x32) && - (instruction.info.sub_opc == 0xA) && - (instruction.info.imm == 0x7FFF)) { - target->debug_reason = DBG_REASON_EXIT; - } else - target->debug_reason = DBG_REASON_BREAKPOINT; - } - break; - case NDS32_DEBUG_DATA_ADDR_WATCHPOINT_PRECISE: - case NDS32_DEBUG_DATA_VALUE_WATCHPOINT_PRECISE: - case NDS32_DEBUG_LOAD_STORE_GLOBAL_STOP: /* GLOBAL_STOP is precise exception */ - { - int result; - - result = nds32->get_watched_address(nds32, - &(nds32->watched_address), reason); - /* do single step(without watchpoints) to skip the "watched" instruction */ - nds32_step_without_watchpoint(nds32); - - /* before single_step, save exception address */ - if (result != ERROR_OK) - return ERROR_FAIL; - - target->debug_reason = DBG_REASON_WATCHPOINT; - } - break; - case NDS32_DEBUG_DEBUG_INTERRUPT: - target->debug_reason = DBG_REASON_DBGRQ; - break; - case NDS32_DEBUG_HARDWARE_SINGLE_STEP: - target->debug_reason = DBG_REASON_SINGLESTEP; - break; - case NDS32_DEBUG_DATA_VALUE_WATCHPOINT_IMPRECISE: - case NDS32_DEBUG_DATA_ADDR_WATCHPOINT_NEXT_PRECISE: - case NDS32_DEBUG_DATA_VALUE_WATCHPOINT_NEXT_PRECISE: - if (nds32->get_watched_address(nds32, &(nds32->watched_address), reason) != ERROR_OK) - return ERROR_FAIL; - - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - default: - target->debug_reason = DBG_REASON_UNDEFINED; - break; - } - - return ERROR_OK; -} - -int nds32_login(struct nds32 *nds32) -{ - struct target *target = nds32->target; - struct aice_port_s *aice = target_to_aice(target); - uint32_t passcode_length; - char command_sequence[129]; - char command_str[33]; - char code_str[9]; - uint32_t copy_length; - uint32_t code; - uint32_t i; - - LOG_DEBUG("nds32_login"); - - if (nds32->edm_passcode) { - /* convert EDM passcode to command sequences */ - passcode_length = strlen(nds32->edm_passcode); - command_sequence[0] = '\0'; - for (i = 0; i < passcode_length; i += 8) { - if (passcode_length - i < 8) - copy_length = passcode_length - i; - else - copy_length = 8; - - strncpy(code_str, nds32->edm_passcode + i, copy_length); - code_str[copy_length] = '\0'; - code = strtoul(code_str, NULL, 16); - - sprintf(command_str, "write_misc gen_port0 0x%" PRIx32 ";", code); - strcat(command_sequence, command_str); - } - - if (aice_program_edm(aice, command_sequence) != ERROR_OK) - return ERROR_FAIL; - - /* get current privilege level */ - uint32_t value_edmsw; - aice_read_debug_reg(aice, NDS_EDM_SR_EDMSW, &value_edmsw); - nds32->privilege_level = (value_edmsw >> 16) & 0x3; - LOG_INFO("Current privilege level: %d", nds32->privilege_level); - } - - if (nds32_edm_ops_num > 0) { - const char *reg_name; - for (i = 0 ; i < nds32_edm_ops_num ; i++) { - code = nds32_edm_ops[i].value; - if (nds32_edm_ops[i].reg_no == 6) - reg_name = "gen_port0"; - else if (nds32_edm_ops[i].reg_no == 7) - reg_name = "gen_port1"; - else - return ERROR_FAIL; - - sprintf(command_str, "write_misc %s 0x%" PRIx32 ";", reg_name, code); - if (aice_program_edm(aice, command_str) != ERROR_OK) - return ERROR_FAIL; - } - } - - return ERROR_OK; -} - -int nds32_halt(struct target *target) -{ - struct nds32 *nds32 = target_to_nds32(target); - struct aice_port_s *aice = target_to_aice(target); - enum target_state state; - - LOG_DEBUG("target->state: %s", - target_state_name(target)); - - if (target->state == TARGET_HALTED) { - LOG_DEBUG("target was already halted"); - return ERROR_OK; - } - - if (nds32_target_state(nds32, &state) != ERROR_OK) - return ERROR_FAIL; - - if (state != TARGET_HALTED) - /* TODO: if state == TARGET_HALTED, check ETYPE is DBGI or not */ - if (aice_halt(aice) != ERROR_OK) - return ERROR_FAIL; - - CHECK_RETVAL(nds32->enter_debug_state(nds32, true)); - - CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); - - return ERROR_OK; -} - -/* poll current target status */ -int nds32_poll(struct target *target) -{ - struct nds32 *nds32 = target_to_nds32(target); - enum target_state state; - - if (nds32_target_state(nds32, &state) != ERROR_OK) - return ERROR_FAIL; - - if (state == TARGET_HALTED) { - if (target->state != TARGET_HALTED) { - /* if false_hit, continue free_run */ - if (nds32->enter_debug_state(nds32, true) != ERROR_OK) { - struct aice_port_s *aice = target_to_aice(target); - aice_run(aice); - return ERROR_OK; - } - - LOG_DEBUG("Change target state to TARGET_HALTED."); - - target_call_event_callbacks(target, TARGET_EVENT_HALTED); - } - } else if (state == TARGET_RESET) { - if (target->state == TARGET_HALTED) { - /* similar to assert srst */ - register_cache_invalidate(nds32->core_cache); - target->state = TARGET_RESET; - - /* TODO: deassert srst */ - } else if (target->state == TARGET_RUNNING) { - /* reset as running */ - LOG_WARNING("<-- TARGET WARNING! The debug target has been reset. -->"); - } - } else { - if (target->state != TARGET_RUNNING && target->state != TARGET_DEBUG_RUNNING) { - LOG_DEBUG("Change target state to TARGET_RUNNING."); - target->state = TARGET_RUNNING; - target->debug_reason = DBG_REASON_NOTHALTED; - } - } - - return ERROR_OK; -} - -int nds32_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) -{ - LOG_DEBUG("current %d address %08" TARGET_PRIxADDR - " handle_breakpoints %d" - " debug_execution %d", - current, address, handle_breakpoints, debug_execution); - - struct nds32 *nds32 = target_to_nds32(target); - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - address = nds32_nextpc(nds32, current, address); - - LOG_DEBUG("RESUME PC %08" TARGET_PRIxADDR "%s", address, !current ? "!" : ""); - - if (!debug_execution) - target_free_all_working_areas(target); - - /* Disable HSS to avoid users misuse HSS */ - if (nds32_reach_max_interrupt_level(nds32) == false) { - uint32_t value_ir0; - nds32_get_mapped_reg(nds32, IR0, &value_ir0); - value_ir0 &= ~(0x1 << 11); - nds32_set_mapped_reg(nds32, IR0, value_ir0); - } - - CHECK_RETVAL(nds32->leave_debug_state(nds32, true)); - CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); - - if (nds32->virtual_hosting_ctrl_c == false) { - struct aice_port_s *aice = target_to_aice(target); - aice_run(aice); - } else - nds32->virtual_hosting_ctrl_c = false; - - target->debug_reason = DBG_REASON_NOTHALTED; - if (!debug_execution) - target->state = TARGET_RUNNING; - else - target->state = TARGET_DEBUG_RUNNING; - - LOG_DEBUG("target->state: %s", - target_state_name(target)); - - return ERROR_OK; -} - -static int nds32_soft_reset_halt(struct target *target) -{ - /* TODO: test it */ - struct nds32 *nds32 = target_to_nds32(target); - struct aice_port_s *aice = target_to_aice(target); - - aice_assert_srst(aice, AICE_SRST); - - /* halt core and set pc to 0x0 */ - int retval = target_halt(target); - if (retval != ERROR_OK) - return retval; - - /* start fetching from IVB */ - uint32_t value_ir3; - nds32_get_mapped_reg(nds32, IR3, &value_ir3); - nds32_set_mapped_reg(nds32, PC, value_ir3 & 0xFFFF0000); - - return ERROR_OK; -} - -int nds32_assert_reset(struct target *target) -{ - struct nds32 *nds32 = target_to_nds32(target); - struct aice_port_s *aice = target_to_aice(target); - struct nds32_cpu_version *cpu_version = &(nds32->cpu_version); - - /* TODO: apply hw reset signal in not examined state */ - if (!(target_was_examined(target))) { - LOG_WARNING("Reset is not asserted because the target is not examined."); - LOG_WARNING("Use a reset button or power cycle the target."); - return ERROR_TARGET_NOT_EXAMINED; - } - - if (target->reset_halt) { - if ((nds32->soft_reset_halt) - || (nds32->edm.version < 0x51) - || ((nds32->edm.version == 0x51) - && (cpu_version->revision == 0x1C) - && (cpu_version->cpu_id_family == 0xC) - && (cpu_version->cpu_id_version == 0x0))) - nds32_soft_reset_halt(target); - else - aice_assert_srst(aice, AICE_RESET_HOLD); - } else { - aice_assert_srst(aice, AICE_SRST); - alive_sleep(nds32->boot_time); - } - - /* set passcode for secure MCU after core reset */ - nds32_login(nds32); - - /* registers are now invalid */ - register_cache_invalidate(nds32->core_cache); - - target->state = TARGET_RESET; - - return ERROR_OK; -} - -static int nds32_gdb_attach(struct nds32 *nds32) -{ - LOG_DEBUG("nds32_gdb_attach, target coreid: %" PRId32, nds32->target->coreid); - - if (nds32->attached == false) { - - if (nds32->keep_target_edm_ctl) { - /* backup target EDM_CTL */ - struct aice_port_s *aice = target_to_aice(nds32->target); - aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &nds32->backup_edm_ctl); - } - - target_halt(nds32->target); - - nds32->attached = true; - } - - return ERROR_OK; -} - -static int nds32_gdb_detach(struct nds32 *nds32) -{ - LOG_DEBUG("nds32_gdb_detach"); - bool backup_virtual_hosting_setting; - - if (nds32->attached) { - - backup_virtual_hosting_setting = nds32->virtual_hosting; - /* turn off virtual hosting before resume as gdb-detach */ - nds32->virtual_hosting = false; - target_resume(nds32->target, 1, 0, 0, 0); - nds32->virtual_hosting = backup_virtual_hosting_setting; - - if (nds32->keep_target_edm_ctl) { - /* restore target EDM_CTL */ - struct aice_port_s *aice = target_to_aice(nds32->target); - aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, nds32->backup_edm_ctl); - } - - nds32->attached = false; - } - - return ERROR_OK; -} - -static int nds32_callback_event_handler(struct target *target, - enum target_event event, void *priv) -{ - int retval = ERROR_OK; - int target_number = *(int *)priv; - - if (target_number != target->target_number) - return ERROR_OK; - - struct nds32 *nds32 = target_to_nds32(target); - - switch (event) { - case TARGET_EVENT_GDB_ATTACH: - retval = nds32_gdb_attach(nds32); - break; - case TARGET_EVENT_GDB_DETACH: - retval = nds32_gdb_detach(nds32); - break; - default: - break; - } - - return retval; -} - -int nds32_init(struct nds32 *nds32) -{ - /* Initialize anything we can set up without talking to the target */ - nds32->memory.access_channel = NDS_MEMORY_ACC_CPU; - - /* register event callback */ - target_register_event_callback(nds32_callback_event_handler, - &(nds32->target->target_number)); - - return ERROR_OK; -} - -int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) -{ - /* fill syscall parameters to file-I/O info */ - if (!fileio_info) { - LOG_ERROR("Target has not initial file-I/O data structure"); - return ERROR_FAIL; - } - - struct nds32 *nds32 = target_to_nds32(target); - uint32_t value_ir6; - uint32_t syscall_id; - - if (nds32->hit_syscall == false) - return ERROR_FAIL; - - nds32_get_mapped_reg(nds32, IR6, &value_ir6); - syscall_id = (value_ir6 >> 16) & 0x7FFF; - nds32->active_syscall_id = syscall_id; - - LOG_DEBUG("hit syscall ID: 0x%" PRIx32, syscall_id); - - /* free previous identifier storage */ - free(fileio_info->identifier); - fileio_info->identifier = NULL; - - uint32_t reg_r0, reg_r1, reg_r2; - nds32_get_mapped_reg(nds32, R0, ®_r0); - nds32_get_mapped_reg(nds32, R1, ®_r1); - nds32_get_mapped_reg(nds32, R2, ®_r2); - - switch (syscall_id) { - case NDS32_SYSCALL_EXIT: - fileio_info->identifier = malloc(5); - sprintf(fileio_info->identifier, "exit"); - fileio_info->param_1 = reg_r0; - break; - case NDS32_SYSCALL_OPEN: - { - uint8_t filename[256]; - fileio_info->identifier = malloc(5); - sprintf(fileio_info->identifier, "open"); - fileio_info->param_1 = reg_r0; - /* reserve fileio_info->param_2 for length of path */ - fileio_info->param_3 = reg_r1; - fileio_info->param_4 = reg_r2; - - target->type->read_buffer(target, reg_r0, 256, filename); - fileio_info->param_2 = strlen((char *)filename); - } - break; - case NDS32_SYSCALL_CLOSE: - fileio_info->identifier = malloc(6); - sprintf(fileio_info->identifier, "close"); - fileio_info->param_1 = reg_r0; - break; - case NDS32_SYSCALL_READ: - fileio_info->identifier = malloc(5); - sprintf(fileio_info->identifier, "read"); - fileio_info->param_1 = reg_r0; - fileio_info->param_2 = reg_r1; - fileio_info->param_3 = reg_r2; - break; - case NDS32_SYSCALL_WRITE: - fileio_info->identifier = malloc(6); - sprintf(fileio_info->identifier, "write"); - fileio_info->param_1 = reg_r0; - fileio_info->param_2 = reg_r1; - fileio_info->param_3 = reg_r2; - break; - case NDS32_SYSCALL_LSEEK: - fileio_info->identifier = malloc(6); - sprintf(fileio_info->identifier, "lseek"); - fileio_info->param_1 = reg_r0; - fileio_info->param_2 = reg_r1; - fileio_info->param_3 = reg_r2; - break; - case NDS32_SYSCALL_UNLINK: - { - uint8_t filename[256]; - fileio_info->identifier = malloc(7); - sprintf(fileio_info->identifier, "unlink"); - fileio_info->param_1 = reg_r0; - /* reserve fileio_info->param_2 for length of path */ - - target->type->read_buffer(target, reg_r0, 256, filename); - fileio_info->param_2 = strlen((char *)filename); - } - break; - case NDS32_SYSCALL_RENAME: - { - uint8_t filename[256]; - fileio_info->identifier = malloc(7); - sprintf(fileio_info->identifier, "rename"); - fileio_info->param_1 = reg_r0; - /* reserve fileio_info->param_2 for length of old path */ - fileio_info->param_3 = reg_r1; - /* reserve fileio_info->param_4 for length of new path */ - - target->type->read_buffer(target, reg_r0, 256, filename); - fileio_info->param_2 = strlen((char *)filename); - - target->type->read_buffer(target, reg_r1, 256, filename); - fileio_info->param_4 = strlen((char *)filename); - } - break; - case NDS32_SYSCALL_FSTAT: - fileio_info->identifier = malloc(6); - sprintf(fileio_info->identifier, "fstat"); - fileio_info->param_1 = reg_r0; - fileio_info->param_2 = reg_r1; - break; - case NDS32_SYSCALL_STAT: - { - uint8_t filename[256]; - fileio_info->identifier = malloc(5); - sprintf(fileio_info->identifier, "stat"); - fileio_info->param_1 = reg_r0; - /* reserve fileio_info->param_2 for length of old path */ - fileio_info->param_3 = reg_r1; - - target->type->read_buffer(target, reg_r0, 256, filename); - fileio_info->param_2 = strlen((char *)filename) + 1; - } - break; - case NDS32_SYSCALL_GETTIMEOFDAY: - fileio_info->identifier = malloc(13); - sprintf(fileio_info->identifier, "gettimeofday"); - fileio_info->param_1 = reg_r0; - fileio_info->param_2 = reg_r1; - break; - case NDS32_SYSCALL_ISATTY: - fileio_info->identifier = malloc(7); - sprintf(fileio_info->identifier, "isatty"); - fileio_info->param_1 = reg_r0; - break; - case NDS32_SYSCALL_SYSTEM: - { - uint8_t command[256]; - fileio_info->identifier = malloc(7); - sprintf(fileio_info->identifier, "system"); - fileio_info->param_1 = reg_r0; - /* reserve fileio_info->param_2 for length of old path */ - - target->type->read_buffer(target, reg_r0, 256, command); - fileio_info->param_2 = strlen((char *)command); - } - break; - case NDS32_SYSCALL_ERRNO: - fileio_info->identifier = malloc(6); - sprintf(fileio_info->identifier, "errno"); - nds32_set_mapped_reg(nds32, R0, nds32->virtual_hosting_errno); - break; - default: - fileio_info->identifier = malloc(8); - sprintf(fileio_info->identifier, "unknown"); - break; - } - - return ERROR_OK; -} - -int nds32_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c) -{ - LOG_DEBUG("syscall return code: 0x%x, errno: 0x%x , ctrl_c: %s", - retcode, fileio_errno, ctrl_c ? "true" : "false"); - - struct nds32 *nds32 = target_to_nds32(target); - - nds32_set_mapped_reg(nds32, R0, (uint32_t)retcode); - - nds32->virtual_hosting_errno = fileio_errno; - nds32->virtual_hosting_ctrl_c = ctrl_c; - nds32->active_syscall_id = NDS32_SYSCALL_UNDEFINED; - - return ERROR_OK; -} - -int nds32_profiling(struct target *target, uint32_t *samples, - uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) -{ - /* sample $PC every 10 milliseconds */ - uint32_t iteration = seconds * 100; - struct aice_port_s *aice = target_to_aice(target); - struct nds32 *nds32 = target_to_nds32(target); - - /* REVISIT: can nds32 profile without halting? */ - if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted (profiling)", target->cmd_name); - return ERROR_TARGET_NOT_HALTED; - } - - if (max_num_samples < iteration) - iteration = max_num_samples; - - int pc_regnum = nds32->register_map(nds32, PC); - aice_profiling(aice, 10, iteration, pc_regnum, samples, num_samples); - - register_cache_invalidate(nds32->core_cache); - - return ERROR_OK; -} - -int nds32_gdb_fileio_write_memory(struct nds32 *nds32, uint32_t address, - uint32_t size, const uint8_t *buffer) -{ - if ((nds32->active_syscall_id == NDS32_SYSCALL_FSTAT) || - (nds32->active_syscall_id == NDS32_SYSCALL_STAT)) { - /* If doing GDB file-I/O, target should convert 'struct stat' - * from gdb-format to target-format */ - uint8_t stat_buffer[NDS32_STRUCT_STAT_SIZE]; - /* st_dev 2 */ - stat_buffer[0] = buffer[3]; - stat_buffer[1] = buffer[2]; - /* st_ino 2 */ - stat_buffer[2] = buffer[7]; - stat_buffer[3] = buffer[6]; - /* st_mode 4 */ - stat_buffer[4] = buffer[11]; - stat_buffer[5] = buffer[10]; - stat_buffer[6] = buffer[9]; - stat_buffer[7] = buffer[8]; - /* st_nlink 2 */ - stat_buffer[8] = buffer[15]; - stat_buffer[9] = buffer[16]; - /* st_uid 2 */ - stat_buffer[10] = buffer[19]; - stat_buffer[11] = buffer[18]; - /* st_gid 2 */ - stat_buffer[12] = buffer[23]; - stat_buffer[13] = buffer[22]; - /* st_rdev 2 */ - stat_buffer[14] = buffer[27]; - stat_buffer[15] = buffer[26]; - /* st_size 4 */ - stat_buffer[16] = buffer[35]; - stat_buffer[17] = buffer[34]; - stat_buffer[18] = buffer[33]; - stat_buffer[19] = buffer[32]; - /* st_atime 4 */ - stat_buffer[20] = buffer[55]; - stat_buffer[21] = buffer[54]; - stat_buffer[22] = buffer[53]; - stat_buffer[23] = buffer[52]; - /* st_spare1 4 */ - stat_buffer[24] = 0; - stat_buffer[25] = 0; - stat_buffer[26] = 0; - stat_buffer[27] = 0; - /* st_mtime 4 */ - stat_buffer[28] = buffer[59]; - stat_buffer[29] = buffer[58]; - stat_buffer[30] = buffer[57]; - stat_buffer[31] = buffer[56]; - /* st_spare2 4 */ - stat_buffer[32] = 0; - stat_buffer[33] = 0; - stat_buffer[34] = 0; - stat_buffer[35] = 0; - /* st_ctime 4 */ - stat_buffer[36] = buffer[63]; - stat_buffer[37] = buffer[62]; - stat_buffer[38] = buffer[61]; - stat_buffer[39] = buffer[60]; - /* st_spare3 4 */ - stat_buffer[40] = 0; - stat_buffer[41] = 0; - stat_buffer[42] = 0; - stat_buffer[43] = 0; - /* st_blksize 4 */ - stat_buffer[44] = buffer[43]; - stat_buffer[45] = buffer[42]; - stat_buffer[46] = buffer[41]; - stat_buffer[47] = buffer[40]; - /* st_blocks 4 */ - stat_buffer[48] = buffer[51]; - stat_buffer[49] = buffer[50]; - stat_buffer[50] = buffer[49]; - stat_buffer[51] = buffer[48]; - /* st_spare4 8 */ - stat_buffer[52] = 0; - stat_buffer[53] = 0; - stat_buffer[54] = 0; - stat_buffer[55] = 0; - stat_buffer[56] = 0; - stat_buffer[57] = 0; - stat_buffer[58] = 0; - stat_buffer[59] = 0; - - return nds32_write_buffer(nds32->target, address, NDS32_STRUCT_STAT_SIZE, stat_buffer); - } else if (nds32->active_syscall_id == NDS32_SYSCALL_GETTIMEOFDAY) { - /* If doing GDB file-I/O, target should convert 'struct timeval' - * from gdb-format to target-format */ - uint8_t timeval_buffer[NDS32_STRUCT_TIMEVAL_SIZE]; - timeval_buffer[0] = buffer[3]; - timeval_buffer[1] = buffer[2]; - timeval_buffer[2] = buffer[1]; - timeval_buffer[3] = buffer[0]; - timeval_buffer[4] = buffer[11]; - timeval_buffer[5] = buffer[10]; - timeval_buffer[6] = buffer[9]; - timeval_buffer[7] = buffer[8]; - - return nds32_write_buffer(nds32->target, address, NDS32_STRUCT_TIMEVAL_SIZE, timeval_buffer); - } - - return nds32_write_buffer(nds32->target, address, size, buffer); -} - -int nds32_reset_halt(struct nds32 *nds32) -{ - LOG_INFO("reset halt as init"); - - struct aice_port_s *aice = target_to_aice(nds32->target); - aice_assert_srst(aice, AICE_RESET_HOLD); - - return ERROR_OK; -} diff --git a/src/target/nds32.h b/src/target/nds32.h deleted file mode 100644 index c447673431..0000000000 --- a/src/target/nds32.h +++ /dev/null @@ -1,457 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_TARGET_NDS32_H -#define OPENOCD_TARGET_NDS32_H - -#include <jtag/jtag.h> -#include "target.h" -#include "target_type.h" -#include "register.h" -#include "breakpoints.h" -#include "nds32_reg.h" -#include "nds32_insn.h" -#include "nds32_edm.h" - -#define NDS32_EDM_OPERATION_MAX_NUM 64 - -#define CHECK_RETVAL(action) \ - do { \ - int __retval = (action); \ - if (__retval != ERROR_OK) { \ - LOG_DEBUG("error while calling \"%s\"", \ - # action); \ - return __retval; \ - } \ - } while (0) - -/** - * @file - * Holds the interface to Andes cores. - */ - -extern const char *nds32_debug_type_name[11]; - -enum nds32_debug_reason { - NDS32_DEBUG_BREAK = 0, - NDS32_DEBUG_BREAK_16, - NDS32_DEBUG_INST_BREAK, - NDS32_DEBUG_DATA_ADDR_WATCHPOINT_PRECISE, - NDS32_DEBUG_DATA_VALUE_WATCHPOINT_PRECISE, - NDS32_DEBUG_DATA_VALUE_WATCHPOINT_IMPRECISE, - NDS32_DEBUG_DEBUG_INTERRUPT, - NDS32_DEBUG_HARDWARE_SINGLE_STEP, - NDS32_DEBUG_DATA_ADDR_WATCHPOINT_NEXT_PRECISE, - NDS32_DEBUG_DATA_VALUE_WATCHPOINT_NEXT_PRECISE, - NDS32_DEBUG_LOAD_STORE_GLOBAL_STOP, -}; - -#define NDS32_STRUCT_STAT_SIZE 60 -#define NDS32_STRUCT_TIMEVAL_SIZE 8 - -enum nds32_syscall_id { - NDS32_SYSCALL_UNDEFINED = 0, - NDS32_SYSCALL_EXIT = 1, - NDS32_SYSCALL_OPEN = 2, - NDS32_SYSCALL_CLOSE = 3, - NDS32_SYSCALL_READ = 4, - NDS32_SYSCALL_WRITE = 5, - NDS32_SYSCALL_LSEEK = 6, - NDS32_SYSCALL_UNLINK = 7, - NDS32_SYSCALL_RENAME = 3001, - NDS32_SYSCALL_FSTAT = 10, - NDS32_SYSCALL_STAT = 15, - NDS32_SYSCALL_GETTIMEOFDAY = 19, - NDS32_SYSCALL_ISATTY = 3002, - NDS32_SYSCALL_SYSTEM = 3003, - NDS32_SYSCALL_ERRNO = 6001, -}; - -#define NDS32_COMMON_MAGIC 0xADE5ADE5U - -struct nds32_edm { - - /** EDM_CFG.VER, indicate the EDM version */ - int version; - - /** The number of hardware breakpoints */ - int breakpoint_num; - - /** EDM_CFG.DALM, indicate if direct local memory access - * feature is supported or not */ - bool direct_access_local_memory; - - /** Support ACC_CTL register */ - bool access_control; - - /** */ - bool support_max_stop; -}; - -struct nds32_cache { - - /** enable cache or not */ - bool enable; - - /** cache sets per way */ - int set; - - /** cache ways */ - int way; - - /** cache line size */ - int line_size; - - /** cache locking support */ - bool lock_support; -}; - -struct nds32_memory { - - /** ICache */ - struct nds32_cache icache; - - /** DCache */ - struct nds32_cache dcache; - - /** On-chip instruction local memory base */ - int ilm_base; - - /** On-chip instruction local memory size */ - int ilm_size; - - /** ILM base register alignment version */ - int ilm_align_ver; - - /** DLM is enabled or not */ - bool ilm_enable; - - /** DLM start address */ - int ilm_start; - - /** DLM end address */ - int ilm_end; - - /** On-chip data local memory base */ - int dlm_base; - - /** On-chip data local memory size */ - int dlm_size; - - /** DLM base register alignment version */ - int dlm_align_ver; - - /** DLM is enabled or not */ - bool dlm_enable; - - /** DLM start address */ - int dlm_start; - - /** DLM end address */ - int dlm_end; - - /** Memory access method */ - enum nds_memory_access access_channel; - - /** Memory access mode */ - enum nds_memory_select mode; - - /** Address translation */ - bool address_translation; -}; - -struct nds32_cpu_version { - bool performance_extension; - bool _16bit_extension; - bool performance_extension_2; - bool cop_fpu_extension; - bool string_extension; - - int revision; - int cpu_id_family; - int cpu_id_version; -}; - -struct nds32_mmu_config { - int memory_protection; - int memory_protection_version; - bool fully_associative_tlb; - int tlb_size; - int tlb_ways; - int tlb_sets; - bool _8k_page_support; - int extra_page_size_support; - bool tlb_lock; - bool hardware_page_table_walker; - bool default_endian; - int partition_num; - bool invisible_tlb; - bool vlpt; - bool ntme; - bool drde; - int default_min_page_size; - bool multiple_page_size_in_use; -}; - -struct nds32_misc_config { - bool edm; - bool local_memory_dma; - bool performance_monitor; - bool high_speed_memory_port; - bool debug_tracer; - bool div_instruction; - bool mac_instruction; - int audio_isa; - bool l2_cache; - bool reduce_register; - bool addr_24; - bool interruption_level; - int baseline_instruction; - bool no_dx_register; - bool implement_dependant_register; - bool implement_dependant_sr_encoding; - bool ifc; - bool mcu; - bool ex9; - int shadow; -}; - -/** - * Represents a generic Andes core. - */ -struct nds32 { - uint32_t common_magic; - struct reg_cache *core_cache; - - /** Handle for the debug module. */ - struct nds32_edm edm; - - /** Memory information */ - struct nds32_memory memory; - - /** cpu version */ - struct nds32_cpu_version cpu_version; - - /** MMU configuration */ - struct nds32_mmu_config mmu_config; - - /** Misc configuration */ - struct nds32_misc_config misc_config; - - /** Retrieve all core registers, for display. */ - int (*full_context)(struct nds32 *nds32); - - /** Register mappings */ - int (*register_map)(struct nds32 *nds32, int reg_no); - - /** Get debug exception virtual address */ - int (*get_debug_reason)(struct nds32 *nds32, uint32_t *reason); - - /** Restore target registers may be modified in debug state */ - int (*leave_debug_state)(struct nds32 *nds32, bool enable_watchpoint); - - /** Backup target registers may be modified in debug state */ - int (*enter_debug_state)(struct nds32 *nds32, bool enable_watchpoint); - - /** Get address hit watchpoint */ - int (*get_watched_address)(struct nds32 *nds32, uint32_t *address, uint32_t reason); - - /** maximum interrupt level */ - uint32_t max_interrupt_level; - - /** current interrupt level */ - uint32_t current_interrupt_level; - - uint32_t watched_address; - - /** Flag reporting whether virtual hosting is active. */ - bool virtual_hosting; - - /** Flag reporting whether continue/step hits syscall or not */ - bool hit_syscall; - - /** Value to be returned by virtual hosting SYS_ERRNO request. */ - int virtual_hosting_errno; - - /** Flag reporting whether syscall is aborted */ - bool virtual_hosting_ctrl_c; - - /** Record syscall ID for other operations to do special processing for target */ - int active_syscall_id; - - struct breakpoint syscall_break; - - /** Flag reporting whether global stop is active. */ - bool global_stop; - - /** Flag reporting whether to use soft-reset-halt or not as issuing reset-halt. */ - bool soft_reset_halt; - - /** reset-halt as target examine */ - bool reset_halt_as_examine; - - /** backup/restore target EDM_CTL value. As debugging target debug - * handler, it should be true. */ - bool keep_target_edm_ctl; - - /* Value of $EDM_CTL before target enters debug mode */ - uint32_t backup_edm_ctl; - - /** always use word-aligned address to access memory */ - bool word_access_mem; - - /** EDM passcode for debugging secure MCU */ - char *edm_passcode; - - /** current privilege_level if using secure MCU. value 0 is the highest level. */ - int privilege_level; - - /** Period to wait after SRST. */ - uint32_t boot_time; - - /** Flag to indicate HSS steps into ISR or not */ - bool step_isr_enable; - - /** Flag to indicate register table is ready or not */ - bool init_arch_info_after_halted; - - /** Flag to indicate audio-extension is enabled or not */ - bool audio_enable; - - /** Flag to indicate fpu-extension is enabled or not */ - bool fpu_enable; - - /* Andes Core has mixed endian model. Instruction is always big-endian. - * Data may be big or little endian. Device registers may have different - * endian from data and instruction. */ - /** Endian of data memory */ - enum target_endianness data_endian; - - /** Endian of device registers */ - enum target_endianness device_reg_endian; - - /** Flag to indicate if auto convert software breakpoints to - * hardware breakpoints or not in ROM */ - bool auto_convert_hw_bp; - - /* Flag to indicate the target is attached by debugger or not */ - bool attached; - - /** Backpointer to the target. */ - struct target *target; - - void *arch_info; -}; - -struct nds32_reg { - int32_t num; - uint8_t value[8]; - struct target *target; - struct nds32 *nds32; - bool enable; -}; - -struct nds32_edm_operation { - uint32_t reg_no; - uint32_t value; -}; - -extern int nds32_config(struct nds32 *nds32); -extern int nds32_init_arch_info(struct target *target, struct nds32 *nds32); -extern int nds32_full_context(struct nds32 *nds32); -extern int nds32_arch_state(struct target *target); -extern int nds32_add_software_breakpoint(struct target *target, - struct breakpoint *breakpoint); -extern int nds32_remove_software_breakpoint(struct target *target, - struct breakpoint *breakpoint); - -extern int nds32_get_gdb_reg_list(struct target *target, - struct reg **reg_list[], int *reg_list_size, - enum target_register_class reg_class); - -extern int nds32_write_buffer(struct target *target, uint32_t address, - uint32_t size, const uint8_t *buffer); -extern int nds32_read_buffer(struct target *target, uint32_t address, - uint32_t size, uint8_t *buffer); -extern int nds32_read_memory(struct target *target, uint32_t address, - uint32_t size, uint32_t count, uint8_t *buffer); -extern int nds32_write_memory(struct target *target, uint32_t address, - uint32_t size, uint32_t count, const uint8_t *buffer); - -extern int nds32_init_register_table(struct nds32 *nds32); -extern int nds32_init_memory_info(struct nds32 *nds32); -extern int nds32_restore_context(struct target *target); -extern int nds32_get_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t *value); -extern int nds32_set_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t value); - -extern int nds32_edm_config(struct nds32 *nds32); -extern int nds32_cache_sync(struct target *target, target_addr_t address, uint32_t length); -extern int nds32_mmu(struct target *target, int *enabled); -extern int nds32_virtual_to_physical(struct target *target, target_addr_t address, - target_addr_t *physical); -extern int nds32_read_phys_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer); -extern int nds32_write_phys_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer); -extern uint32_t nds32_nextpc(struct nds32 *nds32, int current, uint32_t address); -extern int nds32_examine_debug_reason(struct nds32 *nds32); -extern int nds32_step(struct target *target, int current, - target_addr_t address, int handle_breakpoints); -extern int nds32_target_state(struct nds32 *nds32, enum target_state *state); -extern int nds32_halt(struct target *target); -extern int nds32_poll(struct target *target); -extern int nds32_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution); -extern int nds32_assert_reset(struct target *target); -extern int nds32_init(struct nds32 *nds32); -extern int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info); -extern int nds32_gdb_fileio_write_memory(struct nds32 *nds32, uint32_t address, - uint32_t size, const uint8_t *buffer); -extern int nds32_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c); -extern int nds32_reset_halt(struct nds32 *nds32); -extern int nds32_login(struct nds32 *nds32); -extern int nds32_profiling(struct target *target, uint32_t *samples, - uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds); - -/** Convert target handle to generic Andes target state handle. */ -static inline struct nds32 *target_to_nds32(struct target *target) -{ - assert(target); - return target->arch_info; -} - -/** */ -static inline struct aice_port_s *target_to_aice(struct target *target) -{ - assert(target); - return target->tap->priv; -} - -static inline bool is_nds32(struct nds32 *nds32) -{ - assert(nds32); - return nds32->common_magic == NDS32_COMMON_MAGIC; -} - -static inline bool nds32_reach_max_interrupt_level(struct nds32 *nds32) -{ - assert(nds32); - return nds32->max_interrupt_level == nds32->current_interrupt_level; -} - -#endif /* OPENOCD_TARGET_NDS32_H */ diff --git a/src/target/nds32_aice.c b/src/target/nds32_aice.c deleted file mode 100644 index b01f8c09e8..0000000000 --- a/src/target/nds32_aice.c +++ /dev/null @@ -1,158 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes technology. * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <helper/log.h> -#include "nds32_aice.h" - -int aice_read_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t *val) -{ - if (!aice->port->api->read_reg_64) { - LOG_WARNING("Not implemented: %s", __func__); - return ERROR_FAIL; - } - - return aice->port->api->read_reg_64(aice->coreid, num, val); -} - -int aice_write_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t val) -{ - if (!aice->port->api->write_reg_64) { - LOG_WARNING("Not implemented: %s", __func__); - return ERROR_FAIL; - } - - return aice->port->api->write_reg_64(aice->coreid, num, val); -} - -int aice_read_tlb(struct aice_port_s *aice, target_addr_t virtual_address, - target_addr_t *physical_address) -{ - if (!aice->port->api->read_tlb) { - LOG_WARNING("Not implemented: %s", __func__); - return ERROR_FAIL; - } - - return aice->port->api->read_tlb(aice->coreid, virtual_address, physical_address); -} - -int aice_cache_ctl(struct aice_port_s *aice, uint32_t subtype, uint32_t address) -{ - if (!aice->port->api->cache_ctl) { - LOG_WARNING("Not implemented: %s", __func__); - return ERROR_FAIL; - } - - return aice->port->api->cache_ctl(aice->coreid, subtype, address); -} - -int aice_set_retry_times(struct aice_port_s *aice, uint32_t a_retry_times) -{ - if (!aice->port->api->set_retry_times) { - LOG_WARNING("Not implemented: %s", __func__); - return ERROR_FAIL; - } - - return aice->port->api->set_retry_times(a_retry_times); -} - -int aice_program_edm(struct aice_port_s *aice, char *command_sequence) -{ - if (!aice->port->api->program_edm) { - LOG_WARNING("Not implemented: %s", __func__); - return ERROR_FAIL; - } - - return aice->port->api->program_edm(aice->coreid, command_sequence); -} - -int aice_set_command_mode(struct aice_port_s *aice, - enum aice_command_mode command_mode) -{ - if (!aice->port->api->set_command_mode) { - LOG_WARNING("Not implemented: %s", __func__); - return ERROR_FAIL; - } - - return aice->port->api->set_command_mode(command_mode); -} - -int aice_execute(struct aice_port_s *aice, uint32_t *instructions, - uint32_t instruction_num) -{ - if (!aice->port->api->execute) { - LOG_WARNING("Not implemented: %s", __func__); - return ERROR_FAIL; - } - - return aice->port->api->execute(aice->coreid, instructions, instruction_num); -} - -int aice_set_custom_srst_script(struct aice_port_s *aice, const char *script) -{ - if (!aice->port->api->set_custom_srst_script) { - LOG_WARNING("Not implemented: %s", __func__); - return ERROR_FAIL; - } - - return aice->port->api->set_custom_srst_script(script); -} - -int aice_set_custom_trst_script(struct aice_port_s *aice, const char *script) -{ - if (!aice->port->api->set_custom_trst_script) { - LOG_WARNING("Not implemented: %s", __func__); - return ERROR_FAIL; - } - - return aice->port->api->set_custom_trst_script(script); -} - -int aice_set_custom_restart_script(struct aice_port_s *aice, const char *script) -{ - if (!aice->port->api->set_custom_restart_script) { - LOG_WARNING("Not implemented: %s", __func__); - return ERROR_FAIL; - } - - return aice->port->api->set_custom_restart_script(script); -} - -int aice_set_count_to_check_dbger(struct aice_port_s *aice, uint32_t count_to_check) -{ - if (!aice->port->api->set_count_to_check_dbger) { - LOG_WARNING("Not implemented: %s", __func__); - return ERROR_FAIL; - } - - return aice->port->api->set_count_to_check_dbger(count_to_check); -} - -int aice_profiling(struct aice_port_s *aice, uint32_t interval, uint32_t iteration, - uint32_t reg_no, uint32_t *samples, uint32_t *num_samples) -{ - if (!aice->port->api->profiling) { - LOG_WARNING("Not implemented: %s", __func__); - return ERROR_FAIL; - } - - return aice->port->api->profiling(aice->coreid, interval, iteration, - reg_no, samples, num_samples); -} diff --git a/src/target/nds32_aice.h b/src/target/nds32_aice.h deleted file mode 100644 index 5ea3b1611b..0000000000 --- a/src/target/nds32_aice.h +++ /dev/null @@ -1,161 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes technology. * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_TARGET_NDS32_AICE_H -#define OPENOCD_TARGET_NDS32_AICE_H - -#include <jtag/aice/aice_port.h> - -int aice_read_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t *val); -int aice_write_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t val); -int aice_read_tlb(struct aice_port_s *aice, target_addr_t virtual_address, - target_addr_t *physical_address); -int aice_cache_ctl(struct aice_port_s *aice, uint32_t subtype, uint32_t address); -int aice_set_retry_times(struct aice_port_s *aice, uint32_t a_retry_times); -int aice_program_edm(struct aice_port_s *aice, char *command_sequence); -int aice_set_command_mode(struct aice_port_s *aice, - enum aice_command_mode command_mode); -int aice_execute(struct aice_port_s *aice, uint32_t *instructions, - uint32_t instruction_num); -int aice_set_custom_srst_script(struct aice_port_s *aice, const char *script); -int aice_set_custom_trst_script(struct aice_port_s *aice, const char *script); -int aice_set_custom_restart_script(struct aice_port_s *aice, const char *script); -int aice_set_count_to_check_dbger(struct aice_port_s *aice, uint32_t count_to_check); -int aice_profiling(struct aice_port_s *aice, uint32_t interval, uint32_t iteration, - uint32_t reg_no, uint32_t *samples, uint32_t *num_samples); - -static inline int aice_open(struct aice_port_s *aice, struct aice_port_param_s *param) -{ - return aice->port->api->open(param); -} - -static inline int aice_close(struct aice_port_s *aice) -{ - return aice->port->api->close(); -} - -static inline int aice_reset(struct aice_port_s *aice) -{ - return aice->port->api->reset(); -} - -static inline int aice_assert_srst(struct aice_port_s *aice, - enum aice_srst_type_s srst) -{ - return aice->port->api->assert_srst(aice->coreid, srst); -} - -static inline int aice_run(struct aice_port_s *aice) -{ - return aice->port->api->run(aice->coreid); -} - -static inline int aice_halt(struct aice_port_s *aice) -{ - return aice->port->api->halt(aice->coreid); -} - -static inline int aice_step(struct aice_port_s *aice) -{ - return aice->port->api->step(aice->coreid); -} - -static inline int aice_read_register(struct aice_port_s *aice, uint32_t num, - uint32_t *val) -{ - return aice->port->api->read_reg(aice->coreid, num, val); -} - -static inline int aice_write_register(struct aice_port_s *aice, uint32_t num, - uint32_t val) -{ - return aice->port->api->write_reg(aice->coreid, num, val); -} - -static inline int aice_read_debug_reg(struct aice_port_s *aice, uint32_t addr, - uint32_t *val) -{ - return aice->port->api->read_debug_reg(aice->coreid, addr, val); -} - -static inline int aice_write_debug_reg(struct aice_port_s *aice, uint32_t addr, - const uint32_t val) -{ - return aice->port->api->write_debug_reg(aice->coreid, addr, val); -} - -static inline int aice_read_mem_unit(struct aice_port_s *aice, uint32_t addr, - uint32_t size, uint32_t count, uint8_t *buffer) -{ - return aice->port->api->read_mem_unit(aice->coreid, addr, size, count, buffer); -} - -static inline int aice_write_mem_unit(struct aice_port_s *aice, uint32_t addr, - uint32_t size, uint32_t count, const uint8_t *buffer) -{ - return aice->port->api->write_mem_unit(aice->coreid, addr, size, count, buffer); -} - -static inline int aice_read_mem_bulk(struct aice_port_s *aice, uint32_t addr, - uint32_t length, uint8_t *buffer) -{ - return aice->port->api->read_mem_bulk(aice->coreid, addr, length, buffer); -} - -static inline int aice_write_mem_bulk(struct aice_port_s *aice, uint32_t addr, - uint32_t length, const uint8_t *buffer) -{ - return aice->port->api->write_mem_bulk(aice->coreid, addr, length, buffer); -} - -static inline int aice_idcode(struct aice_port_s *aice, uint32_t *idcode, - uint8_t *num_of_idcode) -{ - return aice->port->api->idcode(idcode, num_of_idcode); -} - -static inline int aice_state(struct aice_port_s *aice, - enum aice_target_state_s *state) -{ - return aice->port->api->state(aice->coreid, state); -} - -static inline int aice_set_jtag_clock(struct aice_port_s *aice, uint32_t a_clock) -{ - return aice->port->api->set_jtag_clock(a_clock); -} - -static inline int aice_memory_access(struct aice_port_s *aice, - enum nds_memory_access a_access) -{ - return aice->port->api->memory_access(aice->coreid, a_access); -} - -static inline int aice_memory_mode(struct aice_port_s *aice, - enum nds_memory_select mem_select) -{ - return aice->port->api->memory_mode(aice->coreid, mem_select); -} - -static inline int aice_set_data_endian(struct aice_port_s *aice, - enum aice_target_endian target_data_endian) -{ - return aice->port->api->set_data_endian(aice->coreid, target_data_endian); -} - -#endif /* OPENOCD_TARGET_NDS32_AICE_H */ diff --git a/src/target/nds32_cmd.c b/src/target/nds32_cmd.c deleted file mode 100644 index 69c28ac783..0000000000 --- a/src/target/nds32_cmd.c +++ /dev/null @@ -1,1134 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <helper/command.h> -#include "nds32.h" -#include "nds32_aice.h" -#include "nds32_disassembler.h" - -extern struct nds32_edm_operation nds32_edm_ops[NDS32_EDM_OPERATION_MAX_NUM]; -extern uint32_t nds32_edm_ops_num; - -static const char *const nds_memory_access_name[] = { - "BUS", - "CPU", -}; - -static const char *const nds_memory_select_name[] = { - "AUTO", - "MEM", - "ILM", - "DLM", -}; - -COMMAND_HANDLER(handle_nds32_dssim_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) { - if (strcmp(CMD_ARGV[0], "on") == 0) - nds32->step_isr_enable = true; - if (strcmp(CMD_ARGV[0], "off") == 0) - nds32->step_isr_enable = false; - } - - command_print(CMD, "%s: $INT_MASK.DSSIM: %d", target_name(target), - nds32->step_isr_enable); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_memory_access_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - struct aice_port_s *aice = target_to_aice(target); - struct nds32_memory *memory = &(nds32->memory); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) { - if (strcmp(CMD_ARGV[0], "bus") == 0) - memory->access_channel = NDS_MEMORY_ACC_BUS; - else if (strcmp(CMD_ARGV[0], "cpu") == 0) - memory->access_channel = NDS_MEMORY_ACC_CPU; - else /* default access channel is NDS_MEMORY_ACC_CPU */ - memory->access_channel = NDS_MEMORY_ACC_CPU; - - LOG_DEBUG("memory access channel is changed to %s", - nds_memory_access_name[memory->access_channel]); - - aice_memory_access(aice, memory->access_channel); - } else { - command_print(CMD, "%s: memory access channel: %s", - target_name(target), - nds_memory_access_name[memory->access_channel]); - } - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_memory_mode_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - struct aice_port_s *aice = target_to_aice(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) { - - if (nds32->edm.access_control == false) { - command_print(CMD, "%s does not support ACC_CTL. " - "Set memory mode to MEMORY", target_name(target)); - nds32->memory.mode = NDS_MEMORY_SELECT_MEM; - } else if (nds32->edm.direct_access_local_memory == false) { - command_print(CMD, "%s does not support direct access " - "local memory. Set memory mode to MEMORY", - target_name(target)); - nds32->memory.mode = NDS_MEMORY_SELECT_MEM; - - /* set to ACC_CTL */ - aice_memory_mode(aice, nds32->memory.mode); - } else { - if (strcmp(CMD_ARGV[0], "auto") == 0) { - nds32->memory.mode = NDS_MEMORY_SELECT_AUTO; - } else if (strcmp(CMD_ARGV[0], "mem") == 0) { - nds32->memory.mode = NDS_MEMORY_SELECT_MEM; - } else if (strcmp(CMD_ARGV[0], "ilm") == 0) { - if (nds32->memory.ilm_base == 0) - command_print(CMD, "%s does not support ILM", - target_name(target)); - else - nds32->memory.mode = NDS_MEMORY_SELECT_ILM; - } else if (strcmp(CMD_ARGV[0], "dlm") == 0) { - if (nds32->memory.dlm_base == 0) - command_print(CMD, "%s does not support DLM", - target_name(target)); - else - nds32->memory.mode = NDS_MEMORY_SELECT_DLM; - } - - /* set to ACC_CTL */ - aice_memory_mode(aice, nds32->memory.mode); - } - } - - command_print(CMD, "%s: memory mode: %s", - target_name(target), - nds_memory_select_name[nds32->memory.mode]); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_cache_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - struct aice_port_s *aice = target_to_aice(target); - struct nds32_cache *icache = &(nds32->memory.icache); - struct nds32_cache *dcache = &(nds32->memory.dcache); - int result; - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) { - - if (strcmp(CMD_ARGV[0], "invalidate") == 0) { - if ((dcache->line_size != 0) && (dcache->enable == true)) { - /* D$ write back */ - result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1D_WBALL, 0); - if (result != ERROR_OK) { - command_print(CMD, "%s: Write back data cache...failed", - target_name(target)); - return result; - } - - command_print(CMD, "%s: Write back data cache...done", - target_name(target)); - - /* D$ invalidate */ - result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1D_INVALALL, 0); - if (result != ERROR_OK) { - command_print(CMD, "%s: Invalidate data cache...failed", - target_name(target)); - return result; - } - - command_print(CMD, "%s: Invalidate data cache...done", - target_name(target)); - } else { - if (dcache->line_size == 0) - command_print(CMD, "%s: No data cache", - target_name(target)); - else - command_print(CMD, "%s: Data cache disabled", - target_name(target)); - } - - if ((icache->line_size != 0) && (icache->enable == true)) { - /* I$ invalidate */ - result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1I_INVALALL, 0); - if (result != ERROR_OK) { - command_print(CMD, "%s: Invalidate instruction cache...failed", - target_name(target)); - return result; - } - - command_print(CMD, "%s: Invalidate instruction cache...done", - target_name(target)); - } else { - if (icache->line_size == 0) - command_print(CMD, "%s: No instruction cache", - target_name(target)); - else - command_print(CMD, "%s: Instruction cache disabled", - target_name(target)); - } - } else - command_print(CMD, "No valid parameter"); - } - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_icache_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - struct aice_port_s *aice = target_to_aice(target); - struct nds32_cache *icache = &(nds32->memory.icache); - int result; - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) { - - if (icache->line_size == 0) { - command_print(CMD, "%s: No instruction cache", - target_name(target)); - return ERROR_OK; - } - - if (strcmp(CMD_ARGV[0], "invalidate") == 0) { - if (icache->enable == true) { - /* I$ invalidate */ - result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1I_INVALALL, 0); - if (result != ERROR_OK) { - command_print(CMD, "%s: Invalidate instruction cache...failed", - target_name(target)); - return result; - } - - command_print(CMD, "%s: Invalidate instruction cache...done", - target_name(target)); - } else { - command_print(CMD, "%s: Instruction cache disabled", - target_name(target)); - } - } else if (strcmp(CMD_ARGV[0], "enable") == 0) { - uint32_t value; - nds32_get_mapped_reg(nds32, IR8, &value); - nds32_set_mapped_reg(nds32, IR8, value | 0x1); - } else if (strcmp(CMD_ARGV[0], "disable") == 0) { - uint32_t value; - nds32_get_mapped_reg(nds32, IR8, &value); - nds32_set_mapped_reg(nds32, IR8, value & ~0x1); - } else if (strcmp(CMD_ARGV[0], "dump") == 0) { - /* TODO: dump cache content */ - } else { - command_print(CMD, "%s: No valid parameter", target_name(target)); - } - } - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_dcache_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - struct aice_port_s *aice = target_to_aice(target); - struct nds32_cache *dcache = &(nds32->memory.dcache); - int result; - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) { - - if (dcache->line_size == 0) { - command_print(CMD, "%s: No data cache", target_name(target)); - return ERROR_OK; - } - - if (strcmp(CMD_ARGV[0], "invalidate") == 0) { - if (dcache->enable == true) { - /* D$ write back */ - result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1D_WBALL, 0); - if (result != ERROR_OK) { - command_print(CMD, "%s: Write back data cache...failed", - target_name(target)); - return result; - } - - command_print(CMD, "%s: Write back data cache...done", - target_name(target)); - - /* D$ invalidate */ - result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1D_INVALALL, 0); - if (result != ERROR_OK) { - command_print(CMD, "%s: Invalidate data cache...failed", - target_name(target)); - return result; - } - - command_print(CMD, "%s: Invalidate data cache...done", - target_name(target)); - } else { - command_print(CMD, "%s: Data cache disabled", - target_name(target)); - } - } else if (strcmp(CMD_ARGV[0], "enable") == 0) { - uint32_t value; - nds32_get_mapped_reg(nds32, IR8, &value); - nds32_set_mapped_reg(nds32, IR8, value | 0x2); - } else if (strcmp(CMD_ARGV[0], "disable") == 0) { - uint32_t value; - nds32_get_mapped_reg(nds32, IR8, &value); - nds32_set_mapped_reg(nds32, IR8, value & ~0x2); - } else if (strcmp(CMD_ARGV[0], "dump") == 0) { - /* TODO: dump cache content */ - } else { - command_print(CMD, "%s: No valid parameter", target_name(target)); - } - } - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_auto_break_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) { - if (strcmp(CMD_ARGV[0], "on") == 0) - nds32->auto_convert_hw_bp = true; - if (strcmp(CMD_ARGV[0], "off") == 0) - nds32->auto_convert_hw_bp = false; - } - - if (nds32->auto_convert_hw_bp) - command_print(CMD, "%s: convert sw break to hw break on ROM: on", - target_name(target)); - else - command_print(CMD, "%s: convert sw break to hw break on ROM: off", - target_name(target)); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_virtual_hosting_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) { - if (strcmp(CMD_ARGV[0], "on") == 0) - nds32->virtual_hosting = true; - if (strcmp(CMD_ARGV[0], "off") == 0) - nds32->virtual_hosting = false; - } - - if (nds32->virtual_hosting) - command_print(CMD, "%s: virtual hosting: on", target_name(target)); - else - command_print(CMD, "%s: virtual hosting: off", target_name(target)); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_global_stop_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) { - if (strcmp(CMD_ARGV[0], "on") == 0) - nds32->global_stop = true; - if (strcmp(CMD_ARGV[0], "off") == 0) - nds32->global_stop = false; - } - - if (nds32->global_stop) - LOG_INFO("%s: global stop: on", target_name(target)); - else - LOG_INFO("%s: global stop: off", target_name(target)); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_soft_reset_halt_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) { - if (strcmp(CMD_ARGV[0], "on") == 0) - nds32->soft_reset_halt = true; - if (strcmp(CMD_ARGV[0], "off") == 0) - nds32->soft_reset_halt = false; - } - - if (nds32->soft_reset_halt) - LOG_INFO("%s: soft-reset-halt: on", target_name(target)); - else - LOG_INFO("%s: soft-reset-halt: off", target_name(target)); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_boot_time_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], nds32->boot_time); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_login_edm_passcode_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - nds32->edm_passcode = strdup(CMD_ARGV[0]); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_login_edm_operation_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 1) { - - uint32_t misc_reg_no; - uint32_t data; - - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], misc_reg_no); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], data); - - if (nds32_edm_ops_num >= NDS32_EDM_OPERATION_MAX_NUM) - return ERROR_FAIL; - - /* Just save the operation. Execute it in nds32_login() */ - nds32_edm_ops[nds32_edm_ops_num].reg_no = misc_reg_no; - nds32_edm_ops[nds32_edm_ops_num].value = data; - nds32_edm_ops_num++; - } else - return ERROR_FAIL; - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_reset_halt_as_init_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) { - if (strcmp(CMD_ARGV[0], "on") == 0) - nds32->reset_halt_as_examine = true; - if (strcmp(CMD_ARGV[0], "off") == 0) - nds32->reset_halt_as_examine = false; - } - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_keep_target_edm_ctl_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) { - if (strcmp(CMD_ARGV[0], "on") == 0) - nds32->keep_target_edm_ctl = true; - if (strcmp(CMD_ARGV[0], "off") == 0) - nds32->keep_target_edm_ctl = false; - } - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_decode_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 1) { - - uint32_t addr; - uint32_t insn_count; - uint32_t opcode; - uint32_t read_addr; - uint32_t i; - struct nds32_instruction instruction; - - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], insn_count); - - read_addr = addr; - i = 0; - while (i < insn_count) { - if (nds32_read_opcode(nds32, read_addr, &opcode) != ERROR_OK) - return ERROR_FAIL; - if (nds32_evaluate_opcode(nds32, opcode, read_addr, &instruction) != ERROR_OK) - return ERROR_FAIL; - - command_print(CMD, "%s", instruction.text); - - read_addr += instruction.instruction_size; - i++; - } - } else if (CMD_ARGC == 1) { - - uint32_t addr; - uint32_t opcode; - struct nds32_instruction instruction; - - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); - - if (nds32_read_opcode(nds32, addr, &opcode) != ERROR_OK) - return ERROR_FAIL; - if (nds32_evaluate_opcode(nds32, opcode, addr, &instruction) != ERROR_OK) - return ERROR_FAIL; - - command_print(CMD, "%s", instruction.text); - } else - return ERROR_FAIL; - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_word_access_mem_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) { - if (strcmp(CMD_ARGV[0], "on") == 0) - nds32->word_access_mem = true; - if (strcmp(CMD_ARGV[0], "off") == 0) - nds32->word_access_mem = false; - } - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_query_target_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - command_print(CMD, "OCD"); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_query_endian_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - uint32_t value_psw; - nds32_get_mapped_reg(nds32, IR0, &value_psw); - - if (value_psw & 0x20) - command_print(CMD, "%s: BE", target_name(target)); - else - command_print(CMD, "%s: LE", target_name(target)); - - return ERROR_OK; -} - -COMMAND_HANDLER(handle_nds32_query_cpuid_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct nds32 *nds32 = target_to_nds32(target); - - if (!is_nds32(nds32)) { - command_print(CMD, "current target isn't an Andes core"); - return ERROR_FAIL; - } - - command_print(CMD, "CPUID: %s", target_name(target)); - - return ERROR_OK; -} - -static int jim_nds32_bulk_write(Jim_Interp *interp, int argc, Jim_Obj * const *argv) -{ - const char *cmd_name = Jim_GetString(argv[0], NULL); - - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - - if (goi.argc < 3) { - Jim_SetResultFormatted(goi.interp, - "usage: %s <address> <count> <data>", cmd_name); - return JIM_ERR; - } - - int e; - jim_wide address; - e = jim_getopt_wide(&goi, &address); - if (e != JIM_OK) - return e; - - jim_wide count; - e = jim_getopt_wide(&goi, &count); - if (e != JIM_OK) - return e; - - uint32_t *data = malloc(count * sizeof(uint32_t)); - if (!data) - return JIM_ERR; - - jim_wide i; - for (i = 0; i < count; i++) { - jim_wide tmp; - e = jim_getopt_wide(&goi, &tmp); - if (e != JIM_OK) { - free(data); - return e; - } - data[i] = (uint32_t)tmp; - } - - /* all args must be consumed */ - if (goi.argc != 0) { - free(data); - return JIM_ERR; - } - - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - int result; - - result = target_write_buffer(target, address, count * 4, (const uint8_t *)data); - - free(data); - - return result; -} - -static int jim_nds32_multi_write(Jim_Interp *interp, int argc, Jim_Obj * const *argv) -{ - const char *cmd_name = Jim_GetString(argv[0], NULL); - - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - - if (goi.argc < 3) { - Jim_SetResultFormatted(goi.interp, - "usage: %s # of pairs [<address> <data>]+", cmd_name); - return JIM_ERR; - } - - int e; - jim_wide num_of_pairs; - e = jim_getopt_wide(&goi, &num_of_pairs); - if (e != JIM_OK) - return e; - - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - struct aice_port_s *aice = target_to_aice(target); - int result; - uint32_t address; - uint32_t data; - jim_wide i; - - aice_set_command_mode(aice, AICE_COMMAND_MODE_PACK); - for (i = 0; i < num_of_pairs; i++) { - jim_wide tmp; - e = jim_getopt_wide(&goi, &tmp); - if (e != JIM_OK) - break; - address = (uint32_t)tmp; - - e = jim_getopt_wide(&goi, &tmp); - if (e != JIM_OK) - break; - data = (uint32_t)tmp; - - result = target_write_buffer(target, address, 4, (const uint8_t *)&data); - if (result != ERROR_OK) - break; - } - aice_set_command_mode(aice, AICE_COMMAND_MODE_NORMAL); - - /* all args must be consumed */ - if (goi.argc != 0) - return JIM_ERR; - - return ERROR_OK; -} - -static int jim_nds32_bulk_read(Jim_Interp *interp, int argc, Jim_Obj * const *argv) -{ - const char *cmd_name = Jim_GetString(argv[0], NULL); - - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - - if (goi.argc < 2) { - Jim_SetResultFormatted(goi.interp, - "usage: %s <address> <count>", cmd_name); - return JIM_ERR; - } - - int e; - jim_wide address; - e = jim_getopt_wide(&goi, &address); - if (e != JIM_OK) - return e; - - jim_wide count; - e = jim_getopt_wide(&goi, &count); - if (e != JIM_OK) - return e; - - /* all args must be consumed */ - if (goi.argc != 0) - return JIM_ERR; - - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - uint32_t *data = malloc(count * sizeof(uint32_t)); - int result; - result = target_read_buffer(target, address, count * 4, (uint8_t *)data); - char data_str[12]; - - jim_wide i; - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - for (i = 0; i < count; i++) { - sprintf(data_str, "0x%08" PRIx32 " ", data[i]); - Jim_AppendStrings(interp, Jim_GetResult(interp), data_str, NULL); - } - - free(data); - - return result; -} - -static int jim_nds32_read_edm_sr(Jim_Interp *interp, int argc, Jim_Obj * const *argv) -{ - const char *cmd_name = Jim_GetString(argv[0], NULL); - - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - - if (goi.argc < 1) { - Jim_SetResultFormatted(goi.interp, - "usage: %s <edm_sr_name>", cmd_name); - return JIM_ERR; - } - - int e; - const char *edm_sr_name; - int edm_sr_name_len; - e = jim_getopt_string(&goi, &edm_sr_name, &edm_sr_name_len); - if (e != JIM_OK) - return e; - - /* all args must be consumed */ - if (goi.argc != 0) - return JIM_ERR; - - uint32_t edm_sr_number; - uint32_t edm_sr_value; - if (strncmp(edm_sr_name, "edm_dtr", edm_sr_name_len) == 0) - edm_sr_number = NDS_EDM_SR_EDM_DTR; - else if (strncmp(edm_sr_name, "edmsw", edm_sr_name_len) == 0) - edm_sr_number = NDS_EDM_SR_EDMSW; - else - return ERROR_FAIL; - - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - struct aice_port_s *aice = target_to_aice(target); - char data_str[11]; - - aice_read_debug_reg(aice, edm_sr_number, &edm_sr_value); - - sprintf(data_str, "0x%08" PRIx32, edm_sr_value); - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), data_str, NULL); - - return ERROR_OK; -} - -static int jim_nds32_write_edm_sr(Jim_Interp *interp, int argc, Jim_Obj * const *argv) -{ - const char *cmd_name = Jim_GetString(argv[0], NULL); - - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - - if (goi.argc < 2) { - Jim_SetResultFormatted(goi.interp, - "usage: %s <edm_sr_name> <value>", cmd_name); - return JIM_ERR; - } - - int e; - const char *edm_sr_name; - int edm_sr_name_len; - e = jim_getopt_string(&goi, &edm_sr_name, &edm_sr_name_len); - if (e != JIM_OK) - return e; - - jim_wide value; - e = jim_getopt_wide(&goi, &value); - if (e != JIM_OK) - return e; - - /* all args must be consumed */ - if (goi.argc != 0) - return JIM_ERR; - - uint32_t edm_sr_number; - if (strncmp(edm_sr_name, "edm_dtr", edm_sr_name_len) == 0) - edm_sr_number = NDS_EDM_SR_EDM_DTR; - else - return ERROR_FAIL; - - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - struct aice_port_s *aice = target_to_aice(target); - - aice_write_debug_reg(aice, edm_sr_number, value); - - return ERROR_OK; -} - -static const struct command_registration nds32_query_command_handlers[] = { - { - .name = "target", - .handler = handle_nds32_query_target_command, - .mode = COMMAND_EXEC, - .usage = "", - .help = "reply 'OCD' for gdb to identify server-side is OpenOCD", - }, - { - .name = "endian", - .handler = handle_nds32_query_endian_command, - .mode = COMMAND_EXEC, - .usage = "", - .help = "query target endian", - }, - { - .name = "cpuid", - .handler = handle_nds32_query_cpuid_command, - .mode = COMMAND_EXEC, - .usage = "", - .help = "query CPU ID", - }, - - COMMAND_REGISTRATION_DONE -}; - -static const struct command_registration nds32_exec_command_handlers[] = { - { - .name = "dssim", - .handler = handle_nds32_dssim_command, - .mode = COMMAND_EXEC, - .usage = "['on'|'off']", - .help = "display/change $INT_MASK.DSSIM status", - }, - { - .name = "mem_access", - .handler = handle_nds32_memory_access_command, - .mode = COMMAND_EXEC, - .usage = "['bus'|'cpu']", - .help = "display/change memory access channel", - }, - { - .name = "mem_mode", - .handler = handle_nds32_memory_mode_command, - .mode = COMMAND_EXEC, - .usage = "['auto'|'mem'|'ilm'|'dlm']", - .help = "display/change memory mode", - }, - { - .name = "cache", - .handler = handle_nds32_cache_command, - .mode = COMMAND_EXEC, - .usage = "['invalidate']", - .help = "cache control", - }, - { - .name = "icache", - .handler = handle_nds32_icache_command, - .mode = COMMAND_EXEC, - .usage = "['invalidate'|'enable'|'disable'|'dump']", - .help = "icache control", - }, - { - .name = "dcache", - .handler = handle_nds32_dcache_command, - .mode = COMMAND_EXEC, - .usage = "['invalidate'|'enable'|'disable'|'dump']", - .help = "dcache control", - }, - { - .name = "auto_break", - .handler = handle_nds32_auto_break_command, - .mode = COMMAND_EXEC, - .usage = "['on'|'off']", - .help = "convert software breakpoints to hardware breakpoints if needed", - }, - { - .name = "virtual_hosting", - .handler = handle_nds32_virtual_hosting_command, - .mode = COMMAND_ANY, - .usage = "['on'|'off']", - .help = "turn on/off virtual hosting", - }, - { - .name = "global_stop", - .handler = handle_nds32_global_stop_command, - .mode = COMMAND_ANY, - .usage = "['on'|'off']", - .help = "turn on/off global stop. After turning on, every load/store " - "instructions will be stopped to check memory access.", - }, - { - .name = "soft_reset_halt", - .handler = handle_nds32_soft_reset_halt_command, - .mode = COMMAND_ANY, - .usage = "['on'|'off']", - .help = "as issuing rest-halt, to use soft-reset-halt or not." - "the feature is for backward-compatible.", - }, - { - .name = "boot_time", - .handler = handle_nds32_boot_time_command, - .mode = COMMAND_CONFIG, - .usage = "milliseconds", - .help = "set the period to wait after srst.", - }, - { - .name = "login_edm_passcode", - .handler = handle_nds32_login_edm_passcode_command, - .mode = COMMAND_CONFIG, - .usage = "passcode", - .help = "set EDM passcode for secure MCU debugging.", - }, - { - .name = "login_edm_operation", - .handler = handle_nds32_login_edm_operation_command, - .mode = COMMAND_CONFIG, - .usage = "misc_reg_no value", - .help = "add EDM operations for secure MCU debugging.", - }, - { - .name = "reset_halt_as_init", - .handler = handle_nds32_reset_halt_as_init_command, - .mode = COMMAND_CONFIG, - .usage = "['on'|'off']", - .help = "reset halt as openocd init.", - }, - { - .name = "keep_target_edm_ctl", - .handler = handle_nds32_keep_target_edm_ctl_command, - .mode = COMMAND_CONFIG, - .usage = "['on'|'off']", - .help = "Backup/Restore target EDM_CTL register.", - }, - { - .name = "decode", - .handler = handle_nds32_decode_command, - .mode = COMMAND_EXEC, - .usage = "address icount", - .help = "decode instruction.", - }, - { - .name = "word_access_mem", - .handler = handle_nds32_word_access_mem_command, - .mode = COMMAND_ANY, - .usage = "['on'|'off']", - .help = "Always use word-aligned address to access memory.", - }, - { - .name = "bulk_write", - .jim_handler = jim_nds32_bulk_write, - .mode = COMMAND_EXEC, - .help = "Write multiple 32-bit words to target memory", - .usage = "address count data", - }, - { - .name = "multi_write", - .jim_handler = jim_nds32_multi_write, - .mode = COMMAND_EXEC, - .help = "Write multiple addresses/words to target memory", - .usage = "num_of_pairs [address data]+", - }, - { - .name = "bulk_read", - .jim_handler = jim_nds32_bulk_read, - .mode = COMMAND_EXEC, - .help = "Read multiple 32-bit words from target memory", - .usage = "address count", - }, - { - .name = "read_edmsr", - .jim_handler = jim_nds32_read_edm_sr, - .mode = COMMAND_EXEC, - .help = "Read EDM system register", - .usage = "['edmsw'|'edm_dtr']", - }, - { - .name = "write_edmsr", - .jim_handler = jim_nds32_write_edm_sr, - .mode = COMMAND_EXEC, - .help = "Write EDM system register", - .usage = "['edm_dtr'] value", - }, - { - .name = "query", - .mode = COMMAND_EXEC, - .help = "Andes query command group", - .usage = "", - .chain = nds32_query_command_handlers, - }, - - COMMAND_REGISTRATION_DONE -}; - -const struct command_registration nds32_command_handlers[] = { - { - .name = "nds", - .mode = COMMAND_ANY, - .help = "Andes command group", - .usage = "", - .chain = nds32_exec_command_handlers, - }, - COMMAND_REGISTRATION_DONE -}; diff --git a/src/target/nds32_cmd.h b/src/target/nds32_cmd.h deleted file mode 100644 index 543ba54c66..0000000000 --- a/src/target/nds32_cmd.h +++ /dev/null @@ -1,26 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_TARGET_NDS32_CMD_H -#define OPENOCD_TARGET_NDS32_CMD_H - -#include <helper/command.h> - -extern const struct command_registration nds32_command_handlers[]; - -#endif /* OPENOCD_TARGET_NDS32_CMD_H */ diff --git a/src/target/nds32_disassembler.c b/src/target/nds32_disassembler.c deleted file mode 100644 index 0bf74e1782..0000000000 --- a/src/target/nds32_disassembler.c +++ /dev/null @@ -1,3858 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <helper/log.h> -#include <target/target.h> -#include "nds32_disassembler.h" - -static const int enable4_bits[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; - -int nds32_read_opcode(struct nds32 *nds32, uint32_t address, uint32_t *value) -{ - struct target *target = nds32->target; - uint8_t value_buf[4]; - - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; - } - - int retval = target_read_buffer(target, address, 4, value_buf); - - if (retval == ERROR_OK) { - /* instructions are always big-endian */ - *value = be_to_h_u32(value_buf); - - LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%8.8" PRIx32 "", - address, - *value); - } else { - *value = 0x0; - LOG_DEBUG("address: 0x%8.8" PRIx32 " failed", - address); - } - - return retval; -} - -static int nds32_parse_type_0(uint32_t opcode, int32_t *imm) -{ - *imm = opcode & 0x1FFFFFF; - - return ERROR_OK; -} - -static int nds32_parse_type_1(uint32_t opcode, uint8_t *rt, int32_t *imm) -{ - *rt = (opcode >> 20) & 0x1F; - *imm = opcode & 0xFFFFF; - - return ERROR_OK; -} - -static int nds32_parse_type_2(uint32_t opcode, uint8_t *rt, uint8_t *ra, int32_t *imm) -{ - *rt = (opcode >> 20) & 0x1F; - *ra = (opcode >> 15) & 0x1F; - *imm = opcode & 0x7FFF; - - return ERROR_OK; -} - -static int nds32_parse_type_3(uint32_t opcode, uint8_t *rt, uint8_t *ra, - uint8_t *rb, int32_t *imm) -{ - *rt = (opcode >> 20) & 0x1F; - *ra = (opcode >> 15) & 0x1F; - *rb = (opcode >> 10) & 0x1F; - *imm = opcode & 0x3FF; - - return ERROR_OK; -} - -static int nds32_parse_type_4(uint32_t opcode, uint8_t *rt, uint8_t *ra, - uint8_t *rb, uint8_t *rd, uint8_t *sub_opc) -{ - *rt = (opcode >> 20) & 0x1F; - *ra = (opcode >> 15) & 0x1F; - *rb = (opcode >> 10) & 0x1F; - *rd = (opcode >> 5) & 0x1F; - *sub_opc = opcode & 0x1F; - - return ERROR_OK; -} - -/* LBI, LHI, LWI, LBI.bi, LHI.bi, LWI.bi */ -static int nds32_parse_group_0_insn(struct nds32 *nds32, uint32_t opcode, - uint32_t address, - struct nds32_instruction *instruction) -{ - uint8_t opc_6; - - opc_6 = instruction->info.opc_6; - - switch (opc_6 & 0x7) { - case 0: /* LBI */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLBI\t$r%" PRIu8 ",[$r%" PRIu8 "+#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 1: /* LHI */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 16; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLHI\t$r%" PRIu8 ",[$r%" PRIu8 "+#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 2: /* LWI */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 15; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLWI\t$r%" PRIu8 ",[$r%" PRIu8 "+#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 4: /* LBI.bi */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLBI.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 5: /* LHI.bi */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 16; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLHI.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 6: /* LWI.bi */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 15; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLWI.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],#%" PRId32 "", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int nds32_parse_group_1_insn(struct nds32 *nds32, uint32_t opcode, - uint32_t address, struct nds32_instruction *instruction) -{ - uint8_t opc_6; - - opc_6 = instruction->info.opc_6; - - switch (opc_6 & 0x7) { - case 0: /* SBI */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSBI\t$r%" PRIu8 ",[$r%" PRIu8 "+#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 1: /* SHI */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 16; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSHI\t$r%" PRIu8 ",[$r%" PRIu8 "+#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 2: /* SWI */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 15; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSWI\t$r%" PRIu8 ",[$r%" PRIu8 "+#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 4: /* SBI.bi */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSBI.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 5: /* SHI.bi */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 16; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSHI.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 6: /* SWI.bi */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 15; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSWI.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int nds32_parse_group_2_insn(struct nds32 *nds32, uint32_t opcode, - uint32_t address, struct nds32_instruction *instruction) -{ - uint8_t opc_6; - - opc_6 = instruction->info.opc_6; - - switch (opc_6 & 0x7) { - case 0: /* LBSI */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLBSI\t$r%" PRIu8 ",[$r%" PRIu8 "+#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 1: /* LHSI */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 16; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLHSI\t$r%" PRIu8 ",[$r%" PRIu8 "+#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 3: { /* DPREFI */ - uint8_t sub_type; - nds32_parse_type_2(opcode, &sub_type, &(instruction->info.ra), - &(instruction->info.imm)); - instruction->info.sub_opc = sub_type & 0xF; - instruction->type = NDS32_INSN_MISC; - if (sub_type & 0x10) { /* DPREFI.d */ - /* sign-extend */ - instruction->info.imm = (instruction->info.imm << 17) >> 14; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tDPREFI.d\t%" PRIu8 ",[$r%" PRIu8 "+#%" PRId32 "]", - address, - opcode, instruction->info.sub_opc, - instruction->info.ra, instruction->info.imm); - } else { /* DPREFI.w */ - /* sign-extend */ - instruction->info.imm = (instruction->info.imm << 17) >> 15; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tDPREFI.w\t%" PRIu8 ",[$r%" PRIu8 "+#%" PRId32 "]", - address, - opcode, instruction->info.sub_opc, - instruction->info.ra, instruction->info.imm); - } - } - break; - case 4: /* LBSI.bi */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLBSI.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 5: /* LHSI.bi */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 16; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLHSI.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 6: /* LBGP */ - nds32_parse_type_1(opcode, &(instruction->info.rt), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - if ((instruction->info.imm >> 19) & 0x1) { /* LBSI.gp */ - instruction->info.imm = (instruction->info.imm << 13) >> 13; - nds32_get_mapped_reg(nds32, R29, &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLBSI.gp\t$r%" PRIu8 ",[#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.imm); - } else { /* LBI.gp */ - instruction->info.imm = (instruction->info.imm << 13) >> 13; - nds32_get_mapped_reg(nds32, R29, &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLBI.gp\t$r%" PRIu8 ",[#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.imm); - } - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int nds32_parse_mem(struct nds32 *nds32, uint32_t opcode, uint32_t address, - struct nds32_instruction *instruction) -{ - uint32_t sub_opcode = opcode & 0x3F; - uint32_t val_ra, val_rb; - switch (sub_opcode >> 3) { - case 0: - switch (sub_opcode & 0x7) { - case 0: /* LB */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); - nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb); - instruction->access_start = val_ra + - (val_rb << ((instruction->info.imm >> 8) & 0x3)); - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLB\t$r%" PRIu8 ",[$r%" PRIu8 "+($r%" PRIu8 "<<%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 1: /* LH */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); - nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb); - instruction->access_start = val_ra + - (val_rb << ((instruction->info.imm >> 8) & 0x3)); - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLH\t$r%" PRIu8 ",[$r%" PRIu8 "+($r%" PRIu8 "<<%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 2: /* LW */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); - nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb); - instruction->access_start = val_ra + - (val_rb << ((instruction->info.imm >> 8) & 0x3)); - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLW\t$r%" PRIu8 ",[$r%" PRIu8 "+($r%" PRIu8 "<<%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 4: /* LB.bi */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLB.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],($r%" PRIu8 "<<%" PRId32 ")", - address, - opcode, instruction->info.rt, - instruction->info.ra, instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 5: /* LH.bi */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLH.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],($r%" PRIu8 "<<%" PRId32 ")", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 6: /* LW.bi */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLW.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],($r%" PRIu8 "<<%" PRId32 ")", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - } - break; - case 1: - switch (sub_opcode & 0x7) { - case 0: /* SB */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); - nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb); - instruction->access_start = val_ra + - (val_rb << ((instruction->info.imm >> 8) & 0x3)); - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSB\t$r%" PRIu8 ",[$r%" PRIu8 "+($r%" PRIu8 "<<%" PRId32 ")]", - address, - opcode, instruction->info.rt, - instruction->info.ra, instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 1: /* SH */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); - nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb); - instruction->access_start = val_ra + - (val_rb << ((instruction->info.imm >> 8) & 0x3)); - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSH\t$r%" PRIu8 ",[$r%" PRIu8 "+($r%" PRIu8 "<<%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 2: /* SW */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); - nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb); - instruction->access_start = val_ra + - (val_rb << ((instruction->info.imm >> 8) & 0x3)); - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSW\t$r%" PRIu8 ",[$r%" PRIu8 "+($r%" PRIu8 "<<%" PRId32 ")]", - address, - opcode, instruction->info.rt, - instruction->info.ra, instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 4: /* SB.bi */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSB.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],($r%" PRIu8 "<<%" PRId32 ")", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 5: /* SH.bi */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSH.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],($r%" PRIu8 "<<%" PRId32 ")", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 6: /* SW.bi */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSW.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],($r%" PRIu8 "<<%" PRId32 ")", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - } - break; - case 2: - switch (sub_opcode & 0x7) { - case 0: /* LBS */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); - nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb); - instruction->access_start = val_ra + - (val_rb << ((instruction->info.imm >> 8) & 0x3)); - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLBS\t$r%" PRIu8 ",[$r%" PRIu8 "+($r%" PRIu8 "<<%" PRId32 ")]", - address, - opcode, instruction->info.rt, - instruction->info.ra, instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 1: /* LHS */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); - nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb); - instruction->access_start = val_ra + - (val_rb << ((instruction->info.imm >> 8) & 0x3)); - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLHS\t$r%" PRIu8 ",[$r%" PRIu8 "+($r%" PRIu8 "<<%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 3: /* DPREF */ - nds32_parse_type_3(opcode, &(instruction->info.sub_opc), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tDPREF\t#%" PRIu8 ",[$r%" PRIu8 "+($r%" PRIu8 "<<#%" PRId32 ")]", - address, - opcode, instruction->info.sub_opc, - instruction->info.ra, instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 4: /* LBS.bi */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLBS.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],($r%" PRIu8 "<<%" PRId32 ")", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 5: /* LHS.bi */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLHS.bi\t$r%" PRIu8 ",[$r%" PRIu8 "],($r%" PRIu8 "<<%" PRId32 ")", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - } - break; - case 3: - switch (sub_opcode & 0x7) { - case 0: /* LLW */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); - nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb); - instruction->access_start = val_ra + - (val_rb << ((instruction->info.imm >> 8) & 0x3)); - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLLW\t$r%" PRIu8 ",[$r%" PRIu8 "+($r%" PRIu8 "<<%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 1: /* SCW */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); - nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb); - instruction->access_start = val_ra + - (val_rb << ((instruction->info.imm >> 8) & 0x3)); - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSCW\t$r%" PRIu8 ",[$r%" PRIu8 "+($r%" PRIu8 "<<%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - } - break; - case 4: - switch (sub_opcode & 0x7) { - case 0: /* LBUP */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); - nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb); - instruction->access_start = val_ra + - (val_rb << ((instruction->info.imm >> 8) & 0x3)); - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLBUP\t$r%" PRIu8 ",[$r%" PRIu8 "+($r%" PRIu8 "<<%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 2: /* LWUP */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); - nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb); - instruction->access_start = val_ra + - (val_rb << ((instruction->info.imm >> 8) & 0x3)); - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLWUP\t$r%" PRIu8 ",[$r%" PRIu8 "+($r%" PRIu8 "<<%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - } - break; - case 5: - switch (sub_opcode & 0x7) { - case 0: /* SBUP */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); - nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb); - instruction->access_start = val_ra + - (val_rb << ((instruction->info.imm >> 8) & 0x3)); - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSBUP\t$r%" PRIu8 ",[$r%" PRIu8 "+($r%" PRIu8 "<<%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - case 2: /* SWUP */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra); - nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb); - instruction->access_start = val_ra + - (val_rb << ((instruction->info.imm >> 8) & 0x3)); - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSWUP\t$r%" PRIu8 ",[$r%" PRIu8 "+($r%" PRIu8 "<<%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - (instruction->info.imm >> 8) & 0x3); - break; - } - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int nds32_calculate_lsmw_access_range(struct nds32 *nds32, - struct nds32_instruction *instruction) -{ - uint8_t ba; - uint8_t id; - uint8_t enable4; - - enable4 = (instruction->info.imm >> 6) & 0xF; - ba = (instruction->info.imm >> 4) & 0x1; - id = (instruction->info.imm >> 3) & 0x1; - - if (ba) { - nds32_get_mapped_reg(nds32, instruction->info.ra, &(instruction->access_start)); - if (id) { /* decrease */ - /* access_end is the (last_element+1), so no need to minus 4 */ - /* instruction->access_end -= 4; */ - instruction->access_end = instruction->access_start; - } else { /* increase */ - instruction->access_start += 4; - } - } else { - nds32_get_mapped_reg(nds32, instruction->info.ra, &(instruction->access_start)); - instruction->access_end = instruction->access_start - 4; - } - - if (id) { /* decrease */ - instruction->access_start = instruction->access_end - - 4 * (instruction->info.rd - instruction->info.rb + 1); - instruction->access_start -= (4 * enable4_bits[enable4]); - } else { /* increase */ - instruction->access_end = instruction->access_start + - 4 * (instruction->info.rd - instruction->info.rb + 1); - instruction->access_end += (4 * enable4_bits[enable4]); - } - - return ERROR_OK; -} - -static int nds32_parse_lsmw(struct nds32 *nds32, uint32_t opcode, uint32_t address, - struct nds32_instruction *instruction) -{ - if (opcode & 0x20) { /* SMW, SMWA, SMWZB */ - switch (opcode & 0x3) { - /* TODO */ - case 0: /* SMW */ - /* use rd as re */ - nds32_parse_type_3(opcode, &(instruction->info.rb), - &(instruction->info.ra), - &(instruction->info.rd), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_calculate_lsmw_access_range(nds32, instruction); - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSMW\t$r%" PRIu8 ",[$r%" PRIu8 "],$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rb, instruction->info.ra, - instruction->info.rd, - (instruction->info.imm >> 6) & 0xF); - break; - case 1: /* SMWA */ - nds32_parse_type_3(opcode, &(instruction->info.rb), - &(instruction->info.ra), - &(instruction->info.rd), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_calculate_lsmw_access_range(nds32, instruction); - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSMWA\t$r%" PRIu8 ",[$r%" PRIu8 "],$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rb, instruction->info.ra, - instruction->info.rd, - (instruction->info.imm >> 6) & 0xF); - break; - case 2: /* SMWZB */ - nds32_parse_type_3(opcode, &(instruction->info.rb), - &(instruction->info.ra), - &(instruction->info.rd), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - /* TODO: calculate access_start/access_end */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSMWZB\t$r%" PRIu8 ",[$r%" PRIu8 "],$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rb, instruction->info.ra, - instruction->info.rd, - (instruction->info.imm >> 6) & 0xF); - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - } else { /* LMW, LMWA, LMWZB */ - switch (opcode & 0x3) { - case 0: /* LMW */ - nds32_parse_type_3(opcode, &(instruction->info.rb), - &(instruction->info.ra), - &(instruction->info.rd), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_calculate_lsmw_access_range(nds32, instruction); - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLMW\t$r%" PRIu8 ",[$r%" PRIu8 "],$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rb, instruction->info.ra, - instruction->info.rd, - (instruction->info.imm >> 6) & 0xF); - break; - case 1: /* LMWA */ - nds32_parse_type_3(opcode, &(instruction->info.rb), - &(instruction->info.ra), - &(instruction->info.rd), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_calculate_lsmw_access_range(nds32, instruction); - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLMWA\t$r%" PRIu8 ",[$r%" PRIu8 "],$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rb, instruction->info.ra, - instruction->info.rd, - (instruction->info.imm >> 6) & 0xF); - break; - case 2: /* LMWZB */ - nds32_parse_type_3(opcode, &(instruction->info.rb), - &(instruction->info.ra), - &(instruction->info.rd), &(instruction->info.imm)); - instruction->type = NDS32_INSN_LOAD_STORE; - /* TODO: calculate access_start/access_end */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLMWZB\t$r%" PRIu8 ",[$r%" PRIu8 "],$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rb, instruction->info.ra, - instruction->info.rd, - (instruction->info.imm >> 6) & 0xF); - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - } - - return ERROR_OK; -} - -static int nds32_parse_hwgp(struct nds32 *nds32, uint32_t opcode, uint32_t address, - struct nds32_instruction *instruction) -{ - switch ((opcode >> 18) & 0x3) { - case 0: /* LHI.gp */ - nds32_parse_type_1(opcode, &(instruction->info.rt), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 14) >> 13; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, R29, &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLHI.gp\t$r%" PRIu8 ",[#%" PRId32"]", - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 1: /* LHSI.gp */ - nds32_parse_type_1(opcode, &(instruction->info.rt), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 14) >> 13; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, R29, &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLHSI.gp\t$r%" PRIu8 ",[#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 2: /* SHI.gp */ - nds32_parse_type_1(opcode, &(instruction->info.rt), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 14) >> 13; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, R29, &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSHI.gp\t$r%" PRIu8 ",[#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 3: - instruction->type = NDS32_INSN_LOAD_STORE; - if ((opcode >> 17) & 0x1) { /* SWI.gp */ - nds32_parse_type_1(opcode, &(instruction->info.rt), - &(instruction->info.imm)); - /* sign-extend */ - instruction->info.imm = (instruction->info.imm << 15) >> 13; - nds32_get_mapped_reg(nds32, R29, &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSWI.gp\t$r%" PRIu8 ",[#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.imm); - } else { /* LWI.gp */ - nds32_parse_type_1(opcode, &(instruction->info.rt), - &(instruction->info.imm)); - /* sign-extend */ - instruction->info.imm = (instruction->info.imm << 15) >> 13; - nds32_get_mapped_reg(nds32, R29, &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tLWI.gp\t$r%" PRIu8 ",[#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.imm); - } - - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int nds32_parse_sbgp(struct nds32 *nds32, uint32_t opcode, uint32_t address, - struct nds32_instruction *instruction) -{ - switch ((opcode >> 19) & 0x1) { - case 0: /* SBI.gp */ - nds32_parse_type_1(opcode, &(instruction->info.rt), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 13) >> 13; /* sign-extend */ - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, R29, &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSBI.gp\t$r%" PRIu8 ",[#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 1: /* ADDI.gp */ - nds32_parse_type_1(opcode, &(instruction->info.rt), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 13) >> 13; /* sign-extend */ - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tADDI.gp\t$r%" PRIu8 ",#%" PRId32 "", - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int nds32_parse_group_3_insn(struct nds32 *nds32, uint32_t opcode, uint32_t address, - struct nds32_instruction *instruction) -{ - uint8_t opc_6; - - opc_6 = instruction->info.opc_6; - - switch (opc_6 & 0x7) { - case 4: /* MEM */ - nds32_parse_mem(nds32, opcode, address, instruction); - break; - case 5: /* LSMW */ - nds32_parse_lsmw(nds32, opcode, address, instruction); - break; - case 6: /* HWGP */ - nds32_parse_hwgp(nds32, opcode, address, instruction); - break; - case 7: /* SBGP */ - nds32_parse_sbgp(nds32, opcode, address, instruction); - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int nds32_parse_alu_1(uint32_t opcode, uint32_t address, - struct nds32_instruction *instruction) -{ - switch (opcode & 0x1F) { - case 0: /* ADD */ - nds32_parse_type_3(opcode, &(instruction->info.rt), &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - instruction->info.imm = (instruction->info.imm >> 5) & 0x1F; - if (instruction->info.imm) - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tADD_SLLI\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - instruction->info.imm); - else - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tADD\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 1: /* SUB */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - instruction->info.imm = (instruction->info.imm >> 5) & 0x1F; - if (instruction->info.imm) - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSUB_SLLI\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - instruction->info.imm); - else - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSUB\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8 "", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 2: /* AND */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - instruction->info.imm = (instruction->info.imm >> 5) & 0x1F; - if (instruction->info.imm) - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tAND_SLLI\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - instruction->info.imm); - else - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tAND\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8 "", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 3: /* XOR */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - instruction->info.imm = (instruction->info.imm >> 5) & 0x1F; - if (instruction->info.imm) - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tXOR_SLLI\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - instruction->info.imm); - else - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tXOR\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 4: /* OR */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - instruction->info.imm = (instruction->info.imm >> 5) & 0x1F; - if (instruction->info.imm) - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tOR_SLLI\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - instruction->info.imm); - else - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tOR\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 5: /* NOR */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tNOR\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 6: /* SLT */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSLT\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 7: /* SLTS */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSLTS\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 8: { /* SLLI */ - uint8_t imm; - int32_t sub_op; - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &imm, &sub_op); - instruction->info.imm = imm; - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSLLI\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - } - break; - case 9: { /* SRLI */ - uint8_t imm; - int32_t sub_op; - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &imm, &sub_op); - instruction->info.imm = imm; - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSRLI\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - } - break; - case 10: { /* SRAI */ - uint8_t imm; - int32_t sub_op; - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &imm, &sub_op); - instruction->info.imm = imm; - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSRAI\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - } - break; - case 11: { /* ROTRI */ - uint8_t imm; - int32_t sub_op; - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &imm, &sub_op); - instruction->info.imm = imm; - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tROTRI\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - } - break; - case 12: { /* SLL */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSLL\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - } - break; - case 13: { /* SRL */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSRL\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - } - break; - case 14: { /* SRA */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSRA\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - } - break; - case 15: { /* ROTR */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tROTR\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - } - break; - case 16: { /* SEB */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSEB\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - } - break; - case 17: { /* SEH */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSEH\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - } - break; - case 18: /* BITC */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBITC\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 19: { /* ZEH */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tZEH\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - } - break; - case 20: { /* WSBH */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tWSBH\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - } - break; - case 21: /* OR_SRLI */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - instruction->info.imm = (instruction->info.imm >> 5) & 0x1F; - if (instruction->info.imm) - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tOR_SRLI\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - instruction->info.imm); - else - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tOR\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 22: { /* DIVSR */ - nds32_parse_type_4(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.rd), - &(instruction->info.sub_opc)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tDIVSR\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - instruction->info.rd); - } - break; - case 23: { /* DIVR */ - nds32_parse_type_4(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.rd), - &(instruction->info.sub_opc)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tDIVR\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - instruction->info.rd); - } - break; - case 24: { /* SVA */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSVA\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - } - break; - case 25: { /* SVS */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSVS\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - } - break; - case 26: { /* CMOVZ */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tCMOVZ\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - } - break; - case 27: { /* CMOVN */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tCMOVN\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - } - break; - case 28: /* ADD_SRLI */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - instruction->info.imm = (instruction->info.imm >> 5) & 0x1F; - if (instruction->info.imm) - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tADD_SRLI\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - instruction->info.imm); - else - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tADD\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 29: /* SUB_SRLI */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - instruction->info.imm = (instruction->info.imm >> 5) & 0x1F; - if (instruction->info.imm) - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSUB_SRLI\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - instruction->info.imm); - else - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSUB\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 30: /* AND_SRLI */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - instruction->info.imm = (instruction->info.imm >> 5) & 0x1F; - if (instruction->info.imm) - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tAND_SRLI\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - instruction->info.imm); - else - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tAND\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 31: /* XOR_SRLI */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - instruction->info.imm = (instruction->info.imm >> 5) & 0x1F; - if (instruction->info.imm) - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tXOR_SRLI\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8 ",%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb, - instruction->info.imm); - else - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tXOR\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int nds32_parse_alu_2(uint32_t opcode, uint32_t address, - struct nds32_instruction *instruction) -{ - switch (opcode & 0x3F) { - case 0: /* MAX */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMAX\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 1: /* MIN */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMIN\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 2: /* AVE */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tAVE\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 3: /* ABS */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tAVE\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 4: { /* CLIPS */ - uint8_t imm; - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &imm, &(instruction->info.imm)); - instruction->info.imm = imm; - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tCLIPS\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - } - break; - case 5: { /* CLIP */ - uint8_t imm; - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &imm, &(instruction->info.imm)); - instruction->info.imm = imm; - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tCLIP\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - } - break; - case 6: /* CLO */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tCLO\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 7: /* CLZ */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tCLZ\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 8: { /* BSET */ - uint8_t imm; - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &imm, &(instruction->info.imm)); - instruction->info.imm = imm; - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBSET\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - } - break; - case 9: { /* BCLR */ - uint8_t imm; - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &imm, &(instruction->info.imm)); - instruction->info.imm = imm; - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBCLR\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - } - break; - case 10: { /* BTGL */ - uint8_t imm; - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &imm, &(instruction->info.imm)); - instruction->info.imm = imm; - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBTGL\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - } - break; - case 11: { /* BTST */ - uint8_t imm; - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &imm, &(instruction->info.imm)); - instruction->info.imm = imm; - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBTST\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - } - break; - case 12: /* BSE */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBSE\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 13: /* BSP */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBSP\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 14: /* FFB */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tFFB\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 15: /* FFMISM */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tFFMISM\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 23: /* FFZMISM */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tFFZMISM\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 32: /* MFUSR */ - nds32_parse_type_1(opcode, &(instruction->info.rt), - &(instruction->info.imm)); - instruction->type = NDS32_INSN_RESOURCE_ACCESS; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMFUSR\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, - (instruction->info.imm >> 10) & 0x3FF); - break; - case 33: /* MTUSR */ - nds32_parse_type_1(opcode, &(instruction->info.rt), - &(instruction->info.imm)); - instruction->type = NDS32_INSN_RESOURCE_ACCESS; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMTUSR\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, - (instruction->info.imm >> 10) & 0x3FF); - break; - case 36: /* MUL */ - nds32_parse_type_3(opcode, &(instruction->info.rt), - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMUL\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - break; - case 40: { /* MULTS64 */ - uint8_t dt_val; - nds32_parse_type_3(opcode, &dt_val, - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMULTS64\t$D%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, (uint8_t)((dt_val >> 1) & 0x1), instruction->info.ra, - instruction->info.rb); - } - break; - case 41: { /* MULT64 */ - uint8_t dt_val; - nds32_parse_type_3(opcode, &dt_val, - &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMULT64\t$D%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, (uint8_t)((dt_val >> 1) & 0x1), instruction->info.ra, - instruction->info.rb); - } - break; - case 42: { /* MADDS64 */ - uint8_t dt_val; - nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMADDS64\t$D%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, (uint8_t)((dt_val >> 1) & 0x1), instruction->info.ra, - instruction->info.rb); - } - break; - case 43: { /* MADD64 */ - uint8_t dt_val; - nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMADD64\t$D%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, (uint8_t)((dt_val >> 1) & 0x1), instruction->info.ra, - instruction->info.rb); - } - break; - case 44: { /* MSUBS64 */ - uint8_t dt_val; - nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMSUBS64\t$D%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, (uint8_t)((dt_val >> 1) & 0x1), instruction->info.ra, - instruction->info.rb); - } - break; - case 45: { /* MSUB64 */ - uint8_t dt_val; - nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMSUB64\t$D%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, (uint8_t)((dt_val >> 1) & 0x1), instruction->info.ra, - instruction->info.rb); - } - break; - case 46: { /* DIVS */ - uint8_t dt_val; - nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tDIVS\t$D%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, (uint8_t)((dt_val >> 1) & 0x1), instruction->info.ra, - instruction->info.rb); - } - break; - case 47: { /* DIV */ - uint8_t dt_val; - nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tDIV\t$D%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, (uint8_t)((dt_val >> 1) & 0x1), instruction->info.ra, - instruction->info.rb); - } - break; - case 49: { /* MULT32 */ - uint8_t dt_val; - nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMULT32\t$D%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, (uint8_t)((dt_val >> 1) & 0x1), instruction->info.ra, - instruction->info.rb); - } - break; - case 51: { /* MADD32 */ - uint8_t dt_val; - nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMADD32\t$D%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, (uint8_t)((dt_val >> 1) & 0x1), instruction->info.ra, - instruction->info.rb); - } - break; - case 53: { /* MSUB32 */ - uint8_t dt_val; - nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra), - &(instruction->info.rb), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMSUB32\t$D%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, (uint8_t)((dt_val >> 1) & 0x1), instruction->info.ra, - instruction->info.rb); - } - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int nds32_parse_group_4_insn(struct nds32 *nds32, uint32_t opcode, - uint32_t address, struct nds32_instruction *instruction) -{ - uint8_t opc_6; - - opc_6 = instruction->info.opc_6; - - switch (opc_6 & 0x7) { - case 0: /* ALU_1 */ - nds32_parse_alu_1(opcode, address, instruction); - break; - case 1: /* ALU_2 */ - nds32_parse_alu_2(opcode, address, instruction); - break; - case 2: /* MOVI */ - nds32_parse_type_1(opcode, &(instruction->info.rt), - &(instruction->info.imm)); - /* sign-extend */ - instruction->info.imm = (instruction->info.imm << 12) >> 12; - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMOVI\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 3: /* SETHI */ - nds32_parse_type_1(opcode, &(instruction->info.rt), - &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSETHI\t$r%" PRIu8 ",0x%8.8" PRIx32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 4: /* JI */ - nds32_parse_type_0(opcode, &(instruction->info.imm)); - /* sign-extend */ - instruction->info.imm = (instruction->info.imm << 8) >> 8; - instruction->type = NDS32_INSN_JUMP_BRANCH; - if ((instruction->info.imm >> 24) & 0x1) { /* JAL */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tJAL\t#%" PRId32, - address, - opcode, instruction->info.imm); - } else { /* J */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tJ\t#%" PRId32, - address, - opcode, instruction->info.imm); - } - break; - case 5: { /* JREG */ - int32_t imm; - nds32_parse_type_0(opcode, &imm); - instruction->info.rb = (imm >> 10) & 0x1F; - instruction->type = NDS32_INSN_JUMP_BRANCH; - switch (imm & 0x1F) { - /* TODO */ - case 0: /* JR */ - if (imm & 0x20) { /* RET */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tRET\t$r%" PRIu8, - address, - opcode, instruction->info.rb); - } else { /* JR */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tJR\t$r%" PRIu8, - address, - opcode, instruction->info.rb); - } - break; - case 1: /* JRAL */ - instruction->info.rt = (imm >> 20) & 0x1F; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tJRAL\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.rb); - break; - case 2: /* JRNEZ */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tJRNEZ\t$r%" PRIu8, - address, - opcode, instruction->info.rb); - break; - case 3: /* JRALNEZ */ - instruction->info.rt = (imm >> 20) & 0x1F; - if (instruction->info.rt == R30) - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tJRALNEZ\t$r%" PRIu8, - address, - opcode, instruction->info.rb); - else - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tJRALNEZ\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, - instruction->info.rt, - instruction->info.rb); - break; - } - } - break; - case 6: { /* BR1 */ - int32_t imm; - - nds32_parse_type_0(opcode, &imm); - instruction->type = NDS32_INSN_JUMP_BRANCH; - if ((imm >> 14) & 0x1) { /* BNE */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - /* sign-extend */ - instruction->info.imm = (instruction->info.imm << 18) >> 18; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBNE\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - } else { /* BEQ */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - /* sign-extend */ - instruction->info.imm = (instruction->info.imm << 18) >> 18; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBEQ\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, - instruction->info.ra, - instruction->info.imm); - } - } - break; - case 7: { /* BR2 */ - int32_t imm; - - nds32_parse_type_0(opcode, &imm); - instruction->type = NDS32_INSN_JUMP_BRANCH; - switch ((imm >> 16) & 0xF) { - case 2: /* BEQZ */ - nds32_parse_type_1(opcode, &(instruction->info.rt), - &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 16) >> 16; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBEQZ\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 3: /* BNEZ */ - nds32_parse_type_1(opcode, &(instruction->info.rt), - &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 16) >> 16; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBNEZ\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 4: /* BGEZ */ - nds32_parse_type_1(opcode, &(instruction->info.rt), - &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 16) >> 16; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBGEZ\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 5: /* BLTZ */ - nds32_parse_type_1(opcode, &(instruction->info.rt), - &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 16) >> 16; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBLTZ\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 6: /* BGTZ */ - nds32_parse_type_1(opcode, &(instruction->info.rt), - &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 16) >> 16; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBGTZ\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 7: /* BLEZ */ - nds32_parse_type_1(opcode, &(instruction->info.rt), - &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 16) >> 16; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBLEZ\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 12: /* BGEZAL */ - nds32_parse_type_1(opcode, &(instruction->info.rt), - &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 16) >> 16; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBGEZAL\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 13: /* BLTZAL */ - nds32_parse_type_1(opcode, &(instruction->info.rt), - &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 16) >> 16; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBLTZAL\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - } - } - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int nds32_parse_group_5_insn(struct nds32 *nds32, uint32_t opcode, - uint32_t address, struct nds32_instruction *instruction) -{ - uint8_t opc_6; - - opc_6 = instruction->info.opc_6; - - switch (opc_6 & 0x7) { - case 0: /* ADDI */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */ - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tADDI\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 1: /* SUBRI */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */ - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSUBRI\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 2: /* ANDI */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tANDI\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 3: /* XORI */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tXORI\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 4: /* ORI */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tORI\t$r%" PRIu8 ",$r%" PRIu8 ",0x%8.8" PRIx32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 6: /* SLTI */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */ - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSLTI\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 7: /* SLTSI */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */ - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSLTSI\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int nds32_parse_group_6_insn(struct nds32 *nds32, uint32_t opcode, - uint32_t address, struct nds32_instruction *instruction) -{ - uint8_t opc_6; - - opc_6 = instruction->info.opc_6; - - switch (opc_6 & 0x7) { - case 2: { /* MISC */ - int32_t imm; - uint8_t sub_opc; - - nds32_parse_type_0(opcode, &imm); - - sub_opc = imm & 0x1F; - switch (sub_opc) { - case 0: /* STANDBY */ - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSTANDBY\t#%" PRIu32, - address, - opcode, (opcode >> 5) & 0x3); - break; - case 1: /* CCTL */ - /* TODO */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tCCTL", - address, - opcode); - break; - case 2: /* MFSR */ - nds32_parse_type_1(opcode, &(instruction->info.rt), - &(instruction->info.imm)); - instruction->type = NDS32_INSN_RESOURCE_ACCESS; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMFSR\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, - (instruction->info.imm >> 10) & 0x3FF); - break; - case 3: /* MTSR */ - nds32_parse_type_1(opcode, &(instruction->info.ra), - &(instruction->info.imm)); - instruction->type = NDS32_INSN_RESOURCE_ACCESS; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMTSR\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.ra, - (instruction->info.imm >> 10) & 0x3FF); - break; - case 4: /* IRET */ - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tIRET", - address, - opcode); - break; - case 5: /* TRAP */ - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tTRAP\t#%" PRId32, - address, - opcode, (imm >> 5) & 0x7FFF); - break; - case 6: /* TEQZ */ - nds32_parse_type_1(opcode, &(instruction->info.ra), - &(instruction->info.imm)); - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tTEQZ\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.ra, - (instruction->info.imm >> 5) & 0x7FFF); - break; - case 7: /* TNEZ */ - nds32_parse_type_1(opcode, &(instruction->info.ra), - &(instruction->info.imm)); - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tTNEZ\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.ra, - (instruction->info.imm >> 5) & 0x7FFF); - break; - case 8: /* DSB */ - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tDSB", - address, - opcode); - break; - case 9: /* ISB */ - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tISB", - address, - opcode); - break; - case 10: /* BREAK */ - instruction->type = NDS32_INSN_MISC; - instruction->info.sub_opc = imm & 0x1F; - instruction->info.imm = (imm >> 5) & 0x7FFF; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tBREAK\t#%" PRId32, - address, - opcode, instruction->info.imm); - break; - case 11: /* SYSCALL */ - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSYSCALL\t#%" PRId32, - address, - opcode, (imm >> 5) & 0x7FFF); - break; - case 12: /* MSYNC */ - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tMSYNC\t#%" PRId32, - address, - opcode, (imm >> 5) & 0x7); - break; - case 13: /* ISYNC */ - nds32_parse_type_1(opcode, &(instruction->info.ra), - &(instruction->info.imm)); - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tISYNC\t$r%" PRIu8, - address, - opcode, instruction->info.ra); - break; - case 14: /* TLBOP */ - /* TODO */ - nds32_parse_type_2(opcode, &(instruction->info.rt), - &(instruction->info.ra), &(instruction->info.imm)); - instruction->type = NDS32_INSN_RESOURCE_ACCESS; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tTLBOP", - address, - opcode); - break; - } - - break; - } - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static uint32_t field_mask[9] = { - 0x0, - 0x1, - 0x3, - 0x7, - 0xF, - 0x1F, - 0x3F, - 0x7F, - 0xFF, -}; - -static uint8_t nds32_extract_field_8u(uint16_t opcode, uint32_t start, uint32_t length) -{ - if (length > 0 && length < 9) - return (opcode >> start) & field_mask[length]; - - return 0; -} - -static int nds32_parse_group_0_insn_16(struct nds32 *nds32, uint16_t opcode, - uint32_t address, struct nds32_instruction *instruction) -{ - switch ((opcode >> 10) & 0x7) { - case 0: /* MOV55 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 5, 5); - instruction->info.ra = nds32_extract_field_8u(opcode, 0, 5); - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tMOV55\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 1: /* MOVI55 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 5, 5); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5); - instruction->info.imm = (instruction->info.imm << 27) >> 27; - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tMOVI55\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 2: /* ADD45, SUB45 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 5, 4); - instruction->info.rb = nds32_extract_field_8u(opcode, 0, 5); - instruction->type = NDS32_INSN_DATA_PROC; - if (nds32_extract_field_8u(opcode, 9, 1) == 0) { /* ADD45 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tADD45\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.rb); - } else { /* SUB45 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSUB45\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.rb); - } - - break; - case 3: /* ADDI45, SUBI45 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 5, 4); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5); - instruction->type = NDS32_INSN_DATA_PROC; - if (nds32_extract_field_8u(opcode, 9, 1) == 0) { /* ADDI45 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tADDI45\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - } else { /* SUBI45 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSUBI45\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - } - break; - case 4: /* SRAI45, SRLI45 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 5, 4); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5); - instruction->type = NDS32_INSN_DATA_PROC; - if (nds32_extract_field_8u(opcode, 9, 1) == 0) { /* SRAI45 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSRAI45\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - } else { /* SRLI45 */ - if ((instruction->info.rt == 0) && (instruction->info.imm == 0)) { - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 "\t\tNOP", - address, - opcode); - } else { - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSRLI45\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - } - } - break; - case 5: - instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3); - instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3); - instruction->type = NDS32_INSN_DATA_PROC; - if (nds32_extract_field_8u(opcode, 9, 1) == 0) { /* SLLI333 */ - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3); - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSLLI333\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - } else { - instruction->info.sub_opc = nds32_extract_field_8u(opcode, 0, 3); - switch (instruction->info.sub_opc) { - case 0: /* ZEB33 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tZEB33\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 1: /* ZEH33 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tZEH33\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 2: /* SEB33 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSEB33\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 3: /* SEH33 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSEH33\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 4: /* XLSB33 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tXLSB33\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 5: /* XLLB33 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tXLLB33\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 6: /* BMSKI33 */ - instruction->info.ra = 0; - instruction->info.imm = nds32_extract_field_8u(opcode, 3, 3); - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tBMSKI33\t$r%" PRIu8 ",$r%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 7: /* FEXTI33 */ - instruction->info.ra = 0; - instruction->info.imm = nds32_extract_field_8u(opcode, 3, 3); - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tFEXTI33\t$r%" PRIu8 ",$r%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx16 - "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - } - break; - case 6: /* ADD333, SUB333 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3); - instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3); - instruction->info.rb = nds32_extract_field_8u(opcode, 0, 3); - instruction->type = NDS32_INSN_DATA_PROC; - if (nds32_extract_field_8u(opcode, 9, 1) == 0) { /* ADD333 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tADD333\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - } else { /* SUB333 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSUB333\t$r%" PRIu8 ",$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.rb); - } - break; - case 7: /* ADDI333, SUBI333 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3); - instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3); - instruction->type = NDS32_INSN_DATA_PROC; - if (nds32_extract_field_8u(opcode, 9, 1) == 0) { /* ADDI333 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tADDI333\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - } else { /* SUBI333 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSUBI333\t$r%" PRIu8 ",$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - } - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx16 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int nds32_parse_group_1_insn_16(struct nds32 *nds32, uint16_t opcode, - uint32_t address, struct nds32_instruction *instruction) -{ - switch ((opcode >> 9) & 0xF) { - case 0: /* LWI333 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3); - instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3) << 2; - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tLWI333\t$r%" PRIu8 ",[$r%" PRIu8 "+(#%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 1: /* LWI333.BI */ - instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3); - instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tLWI333.BI\t$r%" PRIu8 ",[$r%" PRIu8 "],#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm << 2); - break; - case 2: /* LHI333 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3); - instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3) << 1; - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tLHI333\t$r%" PRIu8 ",[$r%" PRIu8 "+(#%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 3: /* LBI333 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3); - instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tLBI333\t$r%" PRIu8 ",[$r%" PRIu8 "+(#%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 4: /* SWI333 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3); - instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3) << 2; - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSWI333\t$r%" PRIu8 ",[$r%" PRIu8 "+(#%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 5: /* SWI333.BI */ - instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3); - instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3) << 2; - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSWI333.BI\t$r%" PRIu8 ",[$r%" PRIu8 "],#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 6: /* SHI333 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3); - instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3) << 1; - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 2; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSHI333\t$r%" PRIu8 ",[$r%" PRIu8 "+(#%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 7: /* SBI333 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3); - instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 1; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSHI333\t$r%" PRIu8 ",[$r%" PRIu8 "+(#%" PRId32 ")]", - address, - opcode, instruction->info.rt, instruction->info.ra, - instruction->info.imm); - break; - case 8: /* ADDRI36.SP */ - instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 6) << 2; - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tADDRI36.SP\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 9: /* LWI45.FE */ - instruction->info.rt = nds32_extract_field_8u(opcode, 5, 4); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5); - instruction->info.imm -= 32; - instruction->info.imm <<= 2; - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, R8, &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tLWI45.FE\t$r%" PRIu8 ",[#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 10: /* LWI450 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 5, 4); - instruction->info.ra = nds32_extract_field_8u(opcode, 0, 5); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tLWI450\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 11: /* SWI450 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 5, 4); - instruction->info.ra = nds32_extract_field_8u(opcode, 0, 5); - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, instruction->info.ra, - &(instruction->access_start)); - instruction->access_end = instruction->access_start + 4; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSWI450\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 12: - case 13: - case 14: - case 15: /* LWI37, SWI37 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 8, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 7) << 2; - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, R28, &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 4; - if (nds32_extract_field_8u(opcode, 7, 1) == 0) { /* LWI37 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tLWI37\t$r%" PRIu8 ",[fp+#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.imm); - } else { /* SWI37 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSWI37\t$r%" PRIu8 ",[fp+#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.imm); - } - break; - default: /* ERROR */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx16 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int nds32_parse_group_2_insn_16(struct nds32 *nds32, uint16_t opcode, - uint32_t address, struct nds32_instruction *instruction) -{ - switch ((opcode >> 11) & 0x3) { - case 0: /* BEQZ38 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 8, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 8); - instruction->info.imm = (instruction->info.imm << 24) >> 24; - instruction->type = NDS32_INSN_JUMP_BRANCH; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tBEQZ38\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 1: /* BNEZ38 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 8, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 8); - instruction->info.imm = (instruction->info.imm << 24) >> 24; - instruction->type = NDS32_INSN_JUMP_BRANCH; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tBNEZ38\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 2: /* BEQS38,J8 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 8, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 8); - instruction->info.imm = (instruction->info.imm << 24) >> 24; - instruction->type = NDS32_INSN_JUMP_BRANCH; - if (instruction->info.rt == 5) { /* J8 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tJ8\t#%" PRId32, - address, - opcode, instruction->info.imm); - } else { /* BEQS38 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tBEQS38\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - } - break; - case 3: /* BNES38, JR5, RET5, JRAL5 */ - instruction->info.rt = nds32_extract_field_8u(opcode, 8, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 8); - instruction->info.imm = (instruction->info.imm << 24) >> 24; - instruction->type = NDS32_INSN_JUMP_BRANCH; - if (instruction->info.rt == 5) { - instruction->info.imm = 0; - instruction->info.rb = nds32_extract_field_8u(opcode, 0, 5); - switch (nds32_extract_field_8u(opcode, 5, 3)) { - case 0: /* JR5 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tJR5\t$r%" PRIu8, - address, - opcode, instruction->info.rb); - break; - case 1: /* JRAL5 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tJRAL5\t$r%" PRIu8, - address, - opcode, instruction->info.rb); - break; - case 2: /* EX9.IT */ - instruction->info.rb = 0; - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5); - /* TODO: implement real instruction semantics */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tEX9.IT\t#%" PRId32, - address, - opcode, instruction->info.imm); - break; - case 4: /* RET5 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tRET5\t$r%" PRIu8, - address, - opcode, instruction->info.rb); - break; - case 5: /* ADD5.PC */ - instruction->info.rt = 0; - instruction->info.rt = nds32_extract_field_8u(opcode, 0, 5); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tADD5.PC\t$r%" PRIu8, - address, - opcode, instruction->info.rt); - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx16 - "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - } else { /* BNES38 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tBNES38\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rt, instruction->info.imm); - } - break; - } - - return ERROR_OK; -} - -static int nds32_parse_group_3_insn_16(struct nds32 *nds32, uint16_t opcode, - uint32_t address, struct nds32_instruction *instruction) -{ - switch ((opcode >> 11) & 0x3) { - case 0: - switch ((opcode >> 9) & 0x3) { - case 0: /* SLTS45 */ - instruction->info.ra = nds32_extract_field_8u(opcode, 5, 4); - instruction->info.rb = nds32_extract_field_8u(opcode, 0, 5); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSLTS45\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.ra, instruction->info.rb); - break; - case 1: /* SLT45 */ - instruction->info.ra = nds32_extract_field_8u(opcode, 5, 4); - instruction->info.rb = nds32_extract_field_8u(opcode, 0, 5); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSLT45\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.ra, instruction->info.rb); - break; - case 2: /* SLTSI45 */ - instruction->info.ra = nds32_extract_field_8u(opcode, 5, 4); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSLTSI45\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.ra, instruction->info.imm); - break; - case 3: /* SLTI45 */ - instruction->info.ra = nds32_extract_field_8u(opcode, 5, 4); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5); - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSLTI45\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.ra, instruction->info.imm); - break; - } - break; - case 1: - switch ((opcode >> 9) & 0x3) { - case 0: - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 8); - instruction->info.imm = (instruction->info.imm << 24) >> 24; - instruction->type = NDS32_INSN_JUMP_BRANCH; - if (nds32_extract_field_8u(opcode, 8, 1) == 0) { /* BEQZS8 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tBEQZS8\t#%" PRId32, - address, - opcode, instruction->info.imm); - } else { /* BNEZS8 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tBNEZS8\t#%" PRId32, - address, - opcode, instruction->info.imm); - } - break; - case 1: /* BREAK16 */ - if (((opcode >> 5) & 0xF) == 0) { - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tBREAK16\t#%" PRId16, - address, - opcode, (int16_t)(opcode & 0x1F)); - } else { /* EX9.IT */ - instruction->type = NDS32_INSN_MISC; - /* TODO: implement real instruction semantics */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tEX9.IT\t#%" PRId16, - address, - opcode, (int16_t)(opcode & 0x1FF)); - } - break; - case 2: /* ADDI10S */ - case 3: - instruction->info.imm = opcode & 0x3FF; - instruction->info.imm = (instruction->info.imm << 22) >> 22; - instruction->type = NDS32_INSN_DATA_PROC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tADDI10.SP\t#%" PRId32, - address, - opcode, instruction->info.imm); - break; - } - break; - case 2: - instruction->info.rt = nds32_extract_field_8u(opcode, 8, 3); - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 7) << 2; - instruction->type = NDS32_INSN_LOAD_STORE; - nds32_get_mapped_reg(nds32, R31, &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = instruction->access_start + 4; - if (nds32_extract_field_8u(opcode, 7, 1) == 0) { /* LWI37.SP */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tLWI37.SP\t$r%" PRIu8 ",[+#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.imm); - } else { /* SWI37.SP */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tSWI37.SP\t$r%" PRIu8 ",[+#%" PRId32 "]", - address, - opcode, instruction->info.rt, instruction->info.imm); - } - break; - case 3: - switch ((opcode >> 9) & 0x3) { - case 0: /* IFCALL9 */ - instruction->info.imm = opcode & 0x1FF; - instruction->type = NDS32_INSN_JUMP_BRANCH; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tIFCALL9\t#%" PRId32 "", - address, - opcode, instruction->info.imm); - break; - case 1: /* MOVPI45 */ - instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5) + 16; - instruction->info.rt = nds32_extract_field_8u(opcode, 5, 4); - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tMOVPI45\t$r%" PRIu8 ",#%" PRId32 "", - address, - opcode, instruction->info.rt, instruction->info.imm); - break; - case 2: /* PUSH25, POP25, MOVD44 */ - switch ((opcode >> 7) & 0x3) { - case 0: /* PUSH25 */ - { - uint8_t re; - uint8_t gpr_count; - - instruction->type = NDS32_INSN_LOAD_STORE; - instruction->info.imm = - nds32_extract_field_8u(opcode, 0, 5) << 3; - re = nds32_extract_field_8u(opcode, 5, 2); - - if (re == 0) - re = 6; - else if (re == 1) - re = 8; - else if (re == 2) - re = 10; - else if (re == 3) - re = 14; - - instruction->info.rd = re; - /* GPRs list: R6 ~ Re and fp, gp, lp */ - gpr_count = 3 + (re - 5); - - nds32_get_mapped_reg(nds32, R31, - &(instruction->access_end)); - instruction->access_start = - instruction->access_end - (gpr_count * 4); - - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tPUSH25\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rd, - instruction->info.imm); - } - break; - case 1: /* POP25 */ - { - uint8_t re; - uint8_t gpr_count; - - instruction->type = NDS32_INSN_LOAD_STORE; - instruction->info.imm = - nds32_extract_field_8u(opcode, 0, 5) << 3; - re = nds32_extract_field_8u(opcode, 5, 2); - - if (re == 0) - re = 6; - else if (re == 1) - re = 8; - else if (re == 2) - re = 10; - else if (re == 3) - re = 14; - - instruction->info.rd = re; - /* GPRs list: R6 ~ Re and fp, gp, lp */ - gpr_count = 3 + (re - 5); - - nds32_get_mapped_reg(nds32, R31, - &(instruction->access_start)); - instruction->access_start += instruction->info.imm; - instruction->access_end = - instruction->access_start + (gpr_count * 4); - - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tPOP25\t$r%" PRIu8 ",#%" PRId32, - address, - opcode, instruction->info.rd, - instruction->info.imm); - } - break; - case 2: /* MOVD44 */ - case 3: - instruction->info.ra = - nds32_extract_field_8u(opcode, 0, 4) * 2; - instruction->info.rt = - nds32_extract_field_8u(opcode, 4, 4) * 2; - instruction->type = NDS32_INSN_MISC; - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tMOVD44\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - } - break; - case 3: /* NEG33, NOT33, MUL33, XOR33, AND33, OR33 */ - instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3); - instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3); - instruction->type = NDS32_INSN_DATA_PROC; - switch (opcode & 0x7) { - case 2: /* NEG33 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tNEG33\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 3: /* NOT33 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tNOT33\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 4: /* MUL33 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tMUL33\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 5: /* XOR33 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tXOR33\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 6: /* AND33 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tAND33\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - case 7: /* OR33 */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%4.4" PRIx16 - "\t\tOR33\t$r%" PRIu8 ",$r%" PRIu8, - address, - opcode, instruction->info.rt, instruction->info.ra); - break; - } - break; - } - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx16 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -int nds32_evaluate_opcode(struct nds32 *nds32, uint32_t opcode, uint32_t address, - struct nds32_instruction *instruction) -{ - int retval = ERROR_OK; - - /* clear fields, to avoid confusion */ - memset(instruction, 0, sizeof(struct nds32_instruction)); - - if (opcode >> 31) { - /* 16 bits instruction */ - instruction->instruction_size = 2; - opcode = (opcode >> 16) & 0xFFFF; - instruction->opcode = opcode; - - switch ((opcode >> 13) & 0x3) { - case 0: - retval = nds32_parse_group_0_insn_16(nds32, opcode, address, instruction); - break; - case 1: - retval = nds32_parse_group_1_insn_16(nds32, opcode, address, instruction); - break; - case 2: - retval = nds32_parse_group_2_insn_16(nds32, opcode, address, instruction); - break; - case 3: - retval = nds32_parse_group_3_insn_16(nds32, opcode, address, instruction); - break; - default: - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - } else { - /* 32 bits instruction */ - instruction->instruction_size = 4; - instruction->opcode = opcode; - - uint8_t opc_6; - opc_6 = opcode >> 25; - instruction->info.opc_6 = opc_6; - - switch ((opc_6 >> 3) & 0x7) { - case 0: /* LBI, LHI, LWI, LBI.bi, LHI.bi, LWI.bi */ - retval = nds32_parse_group_0_insn(nds32, opcode, address, instruction); - break; - case 1: /* SBI, SHI, SWI, SBI.bi, SHI.bi, SWI.bi */ - retval = nds32_parse_group_1_insn(nds32, opcode, address, instruction); - break; - case 2: /* LBSI, LHSI, DPREFI, LBSI.bi, LHSI.bi, LBGP */ - retval = nds32_parse_group_2_insn(nds32, opcode, address, instruction); - break; - case 3: /* MEM, LSMW, HWGP, SBGP */ - retval = nds32_parse_group_3_insn(nds32, opcode, address, instruction); - break; - case 4: /* ALU_1, ALU_2, MOVI, SETHI, JI, JREG, BR1, BR2 */ - retval = nds32_parse_group_4_insn(nds32, opcode, address, instruction); - break; - case 5: /* ADDI, SUBRI, ANDI, XORI, ORI, SLTI, SLTSI */ - retval = nds32_parse_group_5_insn(nds32, opcode, address, instruction); - break; - case 6: /* MISC */ - retval = nds32_parse_group_6_insn(nds32, opcode, address, instruction); - break; - default: /* ERROR */ - snprintf(instruction->text, - 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", - address, - opcode); - return ERROR_FAIL; - } - } - - return retval; -} diff --git a/src/target/nds32_disassembler.h b/src/target/nds32_disassembler.h deleted file mode 100644 index 9117cbb08a..0000000000 --- a/src/target/nds32_disassembler.h +++ /dev/null @@ -1,56 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_TARGET_NDS32_DISASSEMBLER_H -#define OPENOCD_TARGET_NDS32_DISASSEMBLER_H - -#include <target/nds32.h> - -enum nds32_instruction_type { - NDS32_INSN_DATA_PROC = 0, - NDS32_INSN_LOAD_STORE, - NDS32_INSN_JUMP_BRANCH, - NDS32_INSN_RESOURCE_ACCESS, - NDS32_INSN_MISC, -}; - -struct nds32_instruction { - enum nds32_instruction_type type; - char text[128]; - uint32_t opcode; - uint8_t instruction_size; - uint32_t access_start; - uint32_t access_end; - - struct { - uint8_t opc_6; - uint8_t rt; - uint8_t ra; - uint8_t rb; - uint8_t rd; - uint8_t sub_opc; - int32_t imm; - } info; - -}; - -int nds32_read_opcode(struct nds32 *nds32, uint32_t address, uint32_t *value); -int nds32_evaluate_opcode(struct nds32 *nds32, uint32_t opcode, uint32_t address, - struct nds32_instruction *instruction); - -#endif /* OPENOCD_TARGET_NDS32_DISASSEMBLER_H */ diff --git a/src/target/nds32_edm.h b/src/target/nds32_edm.h deleted file mode 100644 index 2b5067a345..0000000000 --- a/src/target/nds32_edm.h +++ /dev/null @@ -1,117 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_TARGET_NDS32_EDM_H -#define OPENOCD_TARGET_NDS32_EDM_H - -#include "helper/types.h" - -/** - * @file - * This is the interface to the Embedded Debug Module for Andes cores. - */ - -/* EDM misc registers */ -enum nds_edm_misc_reg { - NDS_EDM_MISC_DIMIR = 0x0, - NDS_EDM_MISC_SBAR, - NDS_EDM_MISC_EDM_CMDR, - NDS_EDM_MISC_DBGER, - NDS_EDM_MISC_ACC_CTL, - NDS_EDM_MISC_EDM_PROBE, - NDS_EDM_MISC_GEN_PORT0, - NDS_EDM_MISC_GEN_PORT1, -}; - -/* EDM system registers */ -enum nds_edm_system_reg { - NDS_EDM_SR_BPC0 = 0x00, - NDS_EDM_SR_BPC1, - NDS_EDM_SR_BPC2, - NDS_EDM_SR_BPC3, - NDS_EDM_SR_BPC4, - NDS_EDM_SR_BPC5, - NDS_EDM_SR_BPC6, - NDS_EDM_SR_BPC7, - NDS_EDM_SR_BPA0 = 0x08, - NDS_EDM_SR_BPA1, - NDS_EDM_SR_BPA2, - NDS_EDM_SR_BPA3, - NDS_EDM_SR_BPA4, - NDS_EDM_SR_BPA5, - NDS_EDM_SR_BPA6, - NDS_EDM_SR_BPA7, - NDS_EDM_SR_BPAM0 = 0x10, - NDS_EDM_SR_BPAM1, - NDS_EDM_SR_BPAM2, - NDS_EDM_SR_BPAM3, - NDS_EDM_SR_BPAM4, - NDS_EDM_SR_BPAM5, - NDS_EDM_SR_BPAM6, - NDS_EDM_SR_BPAM7, - NDS_EDM_SR_BPV0 = 0x18, - NDS_EDM_SR_BPV1, - NDS_EDM_SR_BPV2, - NDS_EDM_SR_BPV3, - NDS_EDM_SR_BPV4, - NDS_EDM_SR_BPV5, - NDS_EDM_SR_BPV6, - NDS_EDM_SR_BPV7, - NDS_EDM_SR_BPCID0 = 0x20, - NDS_EDM_SR_BPCID1, - NDS_EDM_SR_BPCID2, - NDS_EDM_SR_BPCID3, - NDS_EDM_SR_BPCID4, - NDS_EDM_SR_BPCID5, - NDS_EDM_SR_BPCID6, - NDS_EDM_SR_BPCID7, - NDS_EDM_SR_EDM_CFG = 0x28, - NDS_EDM_SR_EDMSW = 0x30, - NDS_EDM_SR_EDM_CTL = 0x38, - NDS_EDM_SR_EDM_DTR = 0x40, - NDS_EDM_SR_BPMTV = 0x48, - NDS_EDM_SR_DIMBR = 0x50, - NDS_EDM_SR_TECR0 = 0x70, - NDS_EDM_SR_TECR1 = 0x71, -}; - -enum nds_memory_access { - NDS_MEMORY_ACC_BUS = 0, - NDS_MEMORY_ACC_CPU, -}; - -enum nds_memory_select { - NDS_MEMORY_SELECT_AUTO = 0, - NDS_MEMORY_SELECT_MEM = 1, - NDS_MEMORY_SELECT_ILM = 2, - NDS_MEMORY_SELECT_DLM = 3, -}; - -#define NDS_DBGER_DEX (0x1) -#define NDS_DBGER_DPED (0x2) -#define NDS_DBGER_CRST (0x4) -#define NDS_DBGER_AT_MAX (0x8) -#define NDS_DBGER_ILL_SEC_ACC (0x10) -#define NDS_DBGER_ALL_SUPRS_EX (0x40000000) -#define NDS_DBGER_RESACC (0x80000000) -#define NDS_DBGER_CLEAR_ALL (0x1F) - -#define NDS_EDMSW_WDV (1 << 0) -#define NDS_EDMSW_RDV (1 << 1) - -#endif /* OPENOCD_TARGET_NDS32_EDM_H */ diff --git a/src/target/nds32_insn.h b/src/target/nds32_insn.h deleted file mode 100644 index 4e0b2d53bf..0000000000 --- a/src/target/nds32_insn.h +++ /dev/null @@ -1,78 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_TARGET_NDS32_INSN_H -#define OPENOCD_TARGET_NDS32_INSN_H - -#define NOP (0x40000009) -#define DSB (0x64000008) -#define ISB (0x64000009) -#define BEQ_MINUS_12 (0x4C000000 | 0x3FFA) -#define MTSR_DTR(a) (0x64000003 | (((0x03 << 7) | (0x08 << 3) | (0x00 << 0)) << 10) | (((a) & 0x1F) << 20)) -#define MFSR_DTR(a) (0x64000002 | (((0x03 << 7) | (0x08 << 3) | (0x00 << 0)) << 10) | (((a) & 0x1F) << 20)) -#define SETHI(a, b) (0x46000000 | ((a) << 20) | (b)) -#define ORI(a, b, c) (0x58000000 | ((a) << 20) | ((b) << 15) | (c)) -#define LWI_BI(a, b) (0x0C000001 | (a << 20) | (b << 15)) -#define LHI_BI(a, b) (0x0A000001 | (a << 20) | (b << 15)) -#define LBI_BI(a, b) (0x08000001 | (a << 20) | (b << 15)) -#define SWI_BI(a, b) (0x1C000001 | (a << 20) | (b << 15)) -#define SHI_BI(a, b) (0x1A000001 | (a << 20) | (b << 15)) -#define SBI_BI(a, b) (0x18000001 | (a << 20) | (b << 15)) -#define IRET (0x64000004) -#define L1D_IX_WB(a) (0x64000021 | ((a) << 15)) -#define L1D_IX_INVAL(a) (0x64000001 | ((a) << 15)) -#define L1D_VA_INVAL(a) (0x64000101 | ((a) << 15)) -#define L1D_VA_WB(a) (0x64000121 | ((a) << 15)) -#define L1D_IX_RTAG(a) (0x64000061 | ((a) << 15)) -#define L1D_IX_RWD(a) (0x64000081 | ((a) << 15)) -#define L1I_IX_INVAL(a) (0x64000201 | ((a) << 15)) -#define L1I_VA_INVAL(a) (0x64000301 | ((a) << 15)) -#define L1I_IX_RTAG(a) (0x64000261 | ((a) << 15)) -#define L1I_IX_RWD(a) (0x64000281 | ((a) << 15)) -#define L1I_VA_FILLCK(a) (0x64000361 | ((a) << 15)) -#define ISYNC(a) (0x6400000d | ((a) << 20)) -#define MSYNC_STORE (0x6400002c) -#define MSYNC_ALL (0x6400000c) -#define TLBOP_TARGET_READ(a) (0x6400000e | ((a) << 15)) -#define TLBOP_TARGET_PROBE(a, b) (0x640000AE | ((a) << 20) | ((b) << 15)) -#define MFCPD(a, b, c) (0x6A000041 | (a << 20) | (b << 8) | (c << 4)) -#define MFCPW(a, b, c) (0x6A000001 | (a << 20) | (b << 8) | (c << 4)) -#define MTCPD(a, b, c) (0x6A000049 | (a << 20) | (b << 8) | (c << 4)) -#define MTCPW(a, b, c) (0x6A000009 | (a << 20) | (b << 8) | (c << 4)) -#define MOVI_(a, b) (0x44000000 | (a << 20) | (b & 0xFFFFF)) -#define MFUSR_G0(a, b) (0x42000020 | (a << 20) | (b << 15)) -#define MTUSR_G0(a, b) (0x42000021 | (a << 20) | (b << 15)) -#define MFSR(a, b) (0x64000002 | (b << 10) | (a << 20)) -#define MTSR(a, b) (0x64000003 | (b << 10) | (a << 20)) -#define AMFAR(a, b) (0x60300060 | (a << 15) | b) -#define AMTAR(a, b) (0x60300040 | (a << 15) | b) -#define AMFAR2(a, b) (0x60300260 | (a << 15) | b) -#define AMTAR2(a, b) (0x60300240 | (a << 15) | b) -#define FMFCSR (0x6A000701) -#define FMTCSR (0x6A000709) -#define FMFCFG (0x6A000301) -#define FMFSR(a, b) (0x6A000001 | ((a) << 20) | ((b) << 15)) -#define FMTSR(a, b) (0x6A000009 | ((a) << 20) | ((b) << 15)) -#define FMFDR(a, b) (0x6A000041 | ((a) << 20) | ((b) << 15)) -#define FMTDR(a, b) (0x6A000049 | ((a) << 20) | ((b) << 15)) - -/* break instructions */ -#define NDS32_BREAK_16 (0x00EA) -#define NDS32_BREAK_32 (0x0A000064) - -#endif /* OPENOCD_TARGET_NDS32_INSN_H */ diff --git a/src/target/nds32_reg.c b/src/target/nds32_reg.c deleted file mode 100644 index 034a075841..0000000000 --- a/src/target/nds32_reg.c +++ /dev/null @@ -1,380 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <helper/log.h> -#include "nds32_reg.h" - -static bool nds32_reg_init_done; -static struct nds32_reg_s nds32_regs[TOTAL_REG_NUM]; -static const struct nds32_reg_exception_s nds32_ex_reg_values[] = { - {IR0, 3, 0x3, 2}, - {IR0, 3, 0x3, 3}, - {IR1, 3, 0x3, 2}, - {IR1, 3, 0x3, 3}, - {IR2, 3, 0x3, 2}, - {IR2, 3, 0x3, 3}, - {MR3, 1, 0x7, 0}, - {MR3, 1, 0x7, 4}, - {MR3, 1, 0x7, 6}, - {MR3, 8, 0x7, 3}, - {0, 0, 0, 0}, -}; - -static inline void nds32_reg_set(uint32_t number, const char *simple_mnemonic, - const char *symbolic_mnemonic, uint32_t sr_index, - enum nds32_reg_type_s type, uint8_t size) -{ - nds32_regs[number].simple_mnemonic = simple_mnemonic; - nds32_regs[number].symbolic_mnemonic = symbolic_mnemonic; - nds32_regs[number].sr_index = sr_index; - nds32_regs[number].type = type; - nds32_regs[number].size = size; -} - -void nds32_reg_init(void) -{ - if (nds32_reg_init_done == true) - return; - - nds32_reg_set(R0, "r0", "r0", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R1, "r1", "r1", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R2, "r2", "r2", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R3, "r3", "r3", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R4, "r4", "r4", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R5, "r5", "r5", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R6, "r6", "r6", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R7, "r7", "r7", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R8, "r8", "r8", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R9, "r9", "r9", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R10, "r10", "r10", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R11, "r11", "r11", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R12, "r12", "r12", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R13, "r13", "r13", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R14, "r14", "r14", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R15, "r15", "r15", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R16, "r16", "r16", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R17, "r17", "r17", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R18, "r18", "r18", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R19, "r19", "r19", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R20, "r20", "r20", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R21, "r21", "r21", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R22, "r22", "r22", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R23, "r23", "r23", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R24, "r24", "r24", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R25, "r25", "r25", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R26, "r26", "p0", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R27, "r27", "p1", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R28, "fp", "fp", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R29, "gp", "gp", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R30, "lp", "lp", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(R31, "sp", "sp", 0, NDS32_REG_TYPE_GPR, 32); - nds32_reg_set(PC, "pc", "pc", 31, NDS32_REG_TYPE_SPR, 32); - - nds32_reg_set(D0LO, "d0lo", "d0lo", 0, NDS32_REG_TYPE_SPR, 32); - nds32_reg_set(D0HI, "d0hi", "d0hi", 1, NDS32_REG_TYPE_SPR, 32); - nds32_reg_set(D1LO, "d1lo", "d1lo", 2, NDS32_REG_TYPE_SPR, 32); - nds32_reg_set(D1HI, "d1hi", "d1hi", 3, NDS32_REG_TYPE_SPR, 32); - nds32_reg_set(ITB, "itb", "itb", 28, NDS32_REG_TYPE_SPR, 32); - nds32_reg_set(IFC_LP, "ifc_lp", "ifc_lp", 29, NDS32_REG_TYPE_SPR, 32); - - nds32_reg_set(CR0, "cr0", "CPU_VER", SRIDX(0, 0, 0), NDS32_REG_TYPE_CR, 32); - nds32_reg_set(CR1, "cr1", "ICM_CFG", SRIDX(0, 1, 0), NDS32_REG_TYPE_CR, 32); - nds32_reg_set(CR2, "cr2", "DCM_CFG", SRIDX(0, 2, 0), NDS32_REG_TYPE_CR, 32); - nds32_reg_set(CR3, "cr3", "MMU_CFG", SRIDX(0, 3, 0), NDS32_REG_TYPE_CR, 32); - nds32_reg_set(CR4, "cr4", "MSC_CFG", SRIDX(0, 4, 0), NDS32_REG_TYPE_CR, 32); - nds32_reg_set(CR5, "cr5", "CORE_ID", SRIDX(0, 0, 1), NDS32_REG_TYPE_CR, 32); - nds32_reg_set(CR6, "cr6", "FUCOP_EXIST", SRIDX(0, 5, 0), NDS32_REG_TYPE_CR, 32); - - nds32_reg_set(IR0, "ir0", "PSW", SRIDX(1, 0, 0), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR1, "ir1", "IPSW", SRIDX(1, 0, 1), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR2, "ir2", "P_IPSW", SRIDX(1, 0, 2), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR3, "ir3", "IVB", SRIDX(1, 1, 1), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR4, "ir4", "EVA", SRIDX(1, 2, 1), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR5, "ir5", "P_EVA", SRIDX(1, 2, 2), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR6, "ir6", "ITYPE", SRIDX(1, 3, 1), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR7, "ir7", "P_ITYPE", SRIDX(1, 3, 2), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR8, "ir8", "MERR", SRIDX(1, 4, 1), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR9, "ir9", "IPC", SRIDX(1, 5, 1), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR10, "ir10", "P_IPC", SRIDX(1, 5, 2), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR11, "ir11", "OIPC", SRIDX(1, 5, 3), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR12, "ir12", "P_P0", SRIDX(1, 6, 2), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR13, "ir13", "P_P1", SRIDX(1, 7, 2), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR14, "ir14", "INT_MASK", SRIDX(1, 8, 0), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR15, "ir15", "INT_PEND", SRIDX(1, 9, 0), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR16, "ir16", "", SRIDX(1, 10, 0), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR17, "ir17", "", SRIDX(1, 10, 1), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR18, "ir18", "", SRIDX(1, 11, 0), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR19, "ir19", "", SRIDX(1, 1, 2), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR20, "ir20", "", SRIDX(1, 10, 2), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR21, "ir21", "", SRIDX(1, 10, 3), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR22, "ir22", "", SRIDX(1, 10, 4), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR23, "ir23", "", SRIDX(1, 10, 5), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR24, "ir24", "", SRIDX(1, 10, 6), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR25, "ir25", "", SRIDX(1, 10, 7), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR26, "ir26", "", SRIDX(1, 8, 1), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR27, "ir27", "", SRIDX(1, 9, 1), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR28, "ir28", "", SRIDX(1, 11, 1), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR29, "ir29", "", SRIDX(1, 9, 4), NDS32_REG_TYPE_IR, 32); - nds32_reg_set(IR30, "ir30", "", SRIDX(1, 1, 3), NDS32_REG_TYPE_IR, 32); - - nds32_reg_set(MR0, "mr0", "MMU_CTL", SRIDX(2, 0, 0), NDS32_REG_TYPE_MR, 32); - nds32_reg_set(MR1, "mr1", "L1_PPTB", SRIDX(2, 1, 0), NDS32_REG_TYPE_MR, 32); - nds32_reg_set(MR2, "mr2", "TLB_VPN", SRIDX(2, 2, 0), NDS32_REG_TYPE_MR, 32); - nds32_reg_set(MR3, "mr3", "TLB_DATA", SRIDX(2, 3, 0), NDS32_REG_TYPE_MR, 32); - nds32_reg_set(MR4, "mr4", "TLB_MISC", SRIDX(2, 4, 0), NDS32_REG_TYPE_MR, 32); - nds32_reg_set(MR5, "mr5", "VLPT_IDX", SRIDX(2, 5, 0), NDS32_REG_TYPE_MR, 32); - nds32_reg_set(MR6, "mr6", "ILMB", SRIDX(2, 6, 0), NDS32_REG_TYPE_MR, 32); - nds32_reg_set(MR7, "mr7", "DLMB", SRIDX(2, 7, 0), NDS32_REG_TYPE_MR, 32); - nds32_reg_set(MR8, "mr8", "CACHE_CTL", SRIDX(2, 8, 0), NDS32_REG_TYPE_MR, 32); - nds32_reg_set(MR9, "mr9", "HSMP_SADDR", SRIDX(2, 9, 0), NDS32_REG_TYPE_MR, 32); - nds32_reg_set(MR10, "mr10", "HSMP_EADDR", SRIDX(2, 9, 1), NDS32_REG_TYPE_MR, 32); - nds32_reg_set(MR11, "mr11", "", SRIDX(2, 0, 1), NDS32_REG_TYPE_MR, 32); - - nds32_reg_set(DR0, "dr0", "BPC0", SRIDX(3, 0, 0), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR1, "dr1", "BPA0", SRIDX(3, 1, 0), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR2, "dr2", "BPAM0", SRIDX(3, 2, 0), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR3, "dr3", "BPV0", SRIDX(3, 3, 0), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR4, "dr4", "BPCID0", SRIDX(3, 4, 0), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR5, "dr5", "BPC1", SRIDX(3, 0, 1), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR6, "dr6", "BPA1", SRIDX(3, 1, 1), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR7, "dr7", "BPAM1", SRIDX(3, 2, 1), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR8, "dr8", "BPV1", SRIDX(3, 3, 1), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR9, "dr9", "BPCID1", SRIDX(3, 4, 1), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR10, "dr10", "BPC2", SRIDX(3, 0, 2), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR11, "dr11", "BPA2", SRIDX(3, 1, 2), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR12, "dr12", "BPAM2", SRIDX(3, 2, 2), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR13, "dr13", "BPV2", SRIDX(3, 3, 2), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR14, "dr14", "BPCID2", SRIDX(3, 4, 2), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR15, "dr15", "BPC3", SRIDX(3, 0, 3), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR16, "dr16", "BPA3", SRIDX(3, 1, 3), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR17, "dr17", "BPAM3", SRIDX(3, 2, 3), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR18, "dr18", "BPV3", SRIDX(3, 3, 3), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR19, "dr19", "BPCID3", SRIDX(3, 4, 3), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR20, "dr20", "BPC4", SRIDX(3, 0, 4), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR21, "dr21", "BPA4", SRIDX(3, 1, 4), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR22, "dr22", "BPAM4", SRIDX(3, 2, 4), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR23, "dr23", "BPV4", SRIDX(3, 3, 4), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR24, "dr24", "BPCID4", SRIDX(3, 4, 4), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR25, "dr25", "BPC5", SRIDX(3, 0, 5), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR26, "dr26", "BPA5", SRIDX(3, 1, 5), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR27, "dr27", "BPAM5", SRIDX(3, 2, 5), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR28, "dr28", "BPV5", SRIDX(3, 3, 5), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR29, "dr29", "BPCID5", SRIDX(3, 4, 5), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR30, "dr30", "BPC6", SRIDX(3, 0, 6), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR31, "dr31", "BPA6", SRIDX(3, 1, 6), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR32, "dr32", "BPAM6", SRIDX(3, 2, 6), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR33, "dr33", "BPV6", SRIDX(3, 3, 6), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR34, "dr34", "BPCID6", SRIDX(3, 4, 6), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR35, "dr35", "BPC7", SRIDX(3, 0, 7), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR36, "dr36", "BPA7", SRIDX(3, 1, 7), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR37, "dr37", "BPAM7", SRIDX(3, 2, 7), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR38, "dr38", "BPV7", SRIDX(3, 3, 7), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR39, "dr39", "BPCID7", SRIDX(3, 4, 7), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR40, "dr40", "EDM_CFG", SRIDX(3, 5, 0), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR41, "dr41", "EDMSW", SRIDX(3, 6, 0), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR42, "dr42", "EDM_CTL", SRIDX(3, 7, 0), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR43, "dr43", "EDM_DTR", SRIDX(3, 8, 0), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR44, "dr44", "BPMTC", SRIDX(3, 9, 0), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR45, "dr45", "DIMBR", SRIDX(3, 10, 0), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR46, "dr46", "TECR0", SRIDX(3, 14, 0), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR47, "dr47", "TECR1", SRIDX(3, 14, 1), NDS32_REG_TYPE_DR, 32); - nds32_reg_set(DR48, "dr48", "", SRIDX(3, 11, 0), NDS32_REG_TYPE_DR, 32); - - nds32_reg_set(PFR0, "pfr0", "PFMC0", SRIDX(4, 0, 0), NDS32_REG_TYPE_PFR, 32); - nds32_reg_set(PFR1, "pfr1", "PFMC1", SRIDX(4, 0, 1), NDS32_REG_TYPE_PFR, 32); - nds32_reg_set(PFR2, "pfr2", "PFMC2", SRIDX(4, 0, 2), NDS32_REG_TYPE_PFR, 32); - nds32_reg_set(PFR3, "pfr3", "PFM_CTL", SRIDX(4, 1, 0), NDS32_REG_TYPE_PFR, 32); - - nds32_reg_set(DMAR0, "dmar0", "DMA_CFG", SRIDX(5, 0, 0), NDS32_REG_TYPE_DMAR, 32); - nds32_reg_set(DMAR1, "dmar1", "DMA_GCSW", SRIDX(5, 1, 0), NDS32_REG_TYPE_DMAR, 32); - nds32_reg_set(DMAR2, "dmar2", "DMA_CHNSEL", SRIDX(5, 2, 0), NDS32_REG_TYPE_DMAR, 32); - nds32_reg_set(DMAR3, "dmar3", "DMA_ACT", SRIDX(5, 3, 0), NDS32_REG_TYPE_DMAR, 32); - nds32_reg_set(DMAR4, "dmar4", "DMA_SETUP", SRIDX(5, 4, 0), NDS32_REG_TYPE_DMAR, 32); - nds32_reg_set(DMAR5, "dmar5", "DMA_ISADDR", SRIDX(5, 5, 0), NDS32_REG_TYPE_DMAR, 32); - nds32_reg_set(DMAR6, "dmar6", "DMA_ESADDR", SRIDX(5, 6, 0), NDS32_REG_TYPE_DMAR, 32); - nds32_reg_set(DMAR7, "dmar7", "DMA_TCNT", SRIDX(5, 7, 0), NDS32_REG_TYPE_DMAR, 32); - nds32_reg_set(DMAR8, "dmar8", "DMA_STATUS", SRIDX(5, 8, 0), NDS32_REG_TYPE_DMAR, 32); - nds32_reg_set(DMAR9, "dmar9", "DMA_2DSET", SRIDX(5, 9, 0), NDS32_REG_TYPE_DMAR, 32); - nds32_reg_set(DMAR10, "dmar10", "DMA_2DSCTL", SRIDX(5, 9, 1), NDS32_REG_TYPE_DMAR, 32); - - nds32_reg_set(RACR, "racr", "PRUSR_ACC_CTL", SRIDX(4, 4, 0), NDS32_REG_TYPE_RACR, 32); - nds32_reg_set(FUCPR, "fucpr", "FUCOP_CTL", SRIDX(4, 5, 0), NDS32_REG_TYPE_RACR, 32); - - nds32_reg_set(IDR0, "idr0", "SDZ_CTL", SRIDX(2, 15, 0), NDS32_REG_TYPE_IDR, 32); - nds32_reg_set(IDR1, "idr1", "MISC_CTL", SRIDX(2, 15, 1), NDS32_REG_TYPE_IDR, 32); - - nds32_reg_set(SECUR0, "secur0", "", SRIDX(6, 0, 0), NDS32_REG_TYPE_SECURE, 32); - - nds32_reg_set(D0L24, "D0L24", "D0L24", 0x10, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(D1L24, "D1L24", "D1L24", 0x11, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(I0, "I0", "I0", 0x0, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(I1, "I1", "I1", 0x1, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(I2, "I2", "I2", 0x2, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(I3, "I3", "I3", 0x3, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(I4, "I4", "I4", 0x4, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(I5, "I5", "I5", 0x5, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(I6, "I6", "I6", 0x6, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(I7, "I7", "I7", 0x7, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(M1, "M1", "M1", 0x9, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(M2, "M2", "M2", 0xA, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(M3, "M3", "M3", 0xB, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(M5, "M5", "M5", 0xD, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(M6, "M6", "M6", 0xE, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(M7, "M7", "M7", 0xF, NDS32_REG_TYPE_AUMR, 32); - - nds32_reg_set(MOD, "MOD", "MOD", 0x8, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(LBE, "LBE", "LBE", 0x18, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(LE, "LE", "LE", 0x19, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(LC, "LC", "LC", 0x1A, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(ADM_VBASE, "ADM_VBASE", "ADM_VBASE", 0x1B, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(SHFT_CTL0, "SHFT_CTL0", "SHFT_CTL0", 0x12, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(SHFT_CTL1, "SHFT_CTL1", "SHFT_CTL1", 0x13, NDS32_REG_TYPE_AUMR, 32); - - nds32_reg_set(CB_CTL, "CB_CTL", "CB_CTL", 0x1F, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(CBB0, "CBB0", "CBB0", 0x0, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(CBB1, "CBB1", "CBB1", 0x1, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(CBB2, "CBB2", "CBB2", 0x2, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(CBB3, "CBB3", "CBB3", 0x3, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(CBE0, "CBE0", "CBE0", 0x4, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(CBE1, "CBE1", "CBE1", 0x5, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(CBE2, "CBE2", "CBE2", 0x6, NDS32_REG_TYPE_AUMR, 32); - nds32_reg_set(CBE3, "CBE3", "CBE3", 0x7, NDS32_REG_TYPE_AUMR, 32); - - nds32_reg_set(FPCSR, "fpcsr", "FPCSR", 0x7, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FPCFG, "fpcfg", "FPCFG", 0x7, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS0, "fs0", "FS0", 0, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS1, "fs1", "FS1", 1, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS2, "fs2", "FS2", 2, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS3, "fs3", "FS3", 3, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS4, "fs4", "FS4", 4, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS5, "fs5", "FS5", 5, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS6, "fs6", "FS6", 6, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS7, "fs7", "FS7", 7, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS8, "fs8", "FS8", 8, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS9, "fs9", "FS9", 9, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS10, "fs10", "FS10", 10, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS11, "fs11", "FS11", 11, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS12, "fs12", "FS12", 12, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS13, "fs13", "FS13", 13, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS14, "fs14", "FS14", 14, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS15, "fs15", "FS15", 15, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS16, "fs16", "FS16", 16, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS17, "fs17", "FS17", 17, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS18, "fs18", "FS18", 18, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS19, "fs19", "FS19", 19, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS20, "fs20", "FS20", 20, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS21, "fs21", "FS21", 21, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS22, "fs22", "FS22", 22, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS23, "fs23", "FS23", 23, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS24, "fs24", "FS24", 24, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS25, "fs25", "FS25", 25, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS26, "fs26", "FS26", 26, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS27, "fs27", "FS27", 27, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS28, "fs28", "FS28", 28, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS29, "fs29", "FS29", 29, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS30, "fs30", "FS30", 30, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FS31, "fs31", "FS31", 31, NDS32_REG_TYPE_FPU, 32); - nds32_reg_set(FD0, "fd0", "FD0", 0, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD1, "fd1", "FD1", 1, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD2, "fd2", "FD2", 2, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD3, "fd3", "FD3", 3, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD4, "fd4", "FD4", 4, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD5, "fd5", "FD5", 5, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD6, "fd6", "FD6", 6, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD7, "fd7", "FD7", 7, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD8, "fd8", "FD8", 8, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD9, "fd9", "FD9", 9, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD10, "fd10", "FD10", 10, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD11, "fd11", "FD11", 11, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD12, "fd12", "FD12", 12, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD13, "fd13", "FD13", 13, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD14, "fd14", "FD14", 14, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD15, "fd15", "FD15", 15, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD16, "fd16", "FD16", 16, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD17, "fd17", "FD17", 17, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD18, "fd18", "FD18", 18, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD19, "fd19", "FD19", 19, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD20, "fd20", "FD20", 20, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD21, "fd21", "FD21", 21, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD22, "fd22", "FD22", 22, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD23, "fd23", "FD23", 23, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD24, "fd24", "FD24", 24, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD25, "fd25", "FD25", 25, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD26, "fd26", "FD26", 26, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD27, "fd27", "FD27", 27, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD28, "fd28", "FD28", 28, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD29, "fd29", "FD29", 29, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD30, "fd30", "FD30", 30, NDS32_REG_TYPE_FPU, 64); - nds32_reg_set(FD31, "fd31", "FD31", 31, NDS32_REG_TYPE_FPU, 64); - - nds32_reg_init_done = true; -} - -uint32_t nds32_reg_sr_index(uint32_t number) -{ - return nds32_regs[number].sr_index; -} - -enum nds32_reg_type_s nds32_reg_type(uint32_t number) -{ - return nds32_regs[number].type; -} - -uint8_t nds32_reg_size(uint32_t number) -{ - return nds32_regs[number].size; -} - -const char *nds32_reg_simple_name(uint32_t number) -{ - return nds32_regs[number].simple_mnemonic; -} - -const char *nds32_reg_symbolic_name(uint32_t number) -{ - return nds32_regs[number].symbolic_mnemonic; -} - -bool nds32_reg_exception(uint32_t number, uint32_t value) -{ - int i; - const struct nds32_reg_exception_s *ex_reg_value; - uint32_t field_value; - - i = 0; - while (nds32_ex_reg_values[i].reg_num != 0) { - ex_reg_value = nds32_ex_reg_values + i; - - if (ex_reg_value->reg_num == number) { - field_value = (value >> ex_reg_value->ex_value_bit_pos) & - ex_reg_value->ex_value_mask; - if (field_value == ex_reg_value->ex_value) { - LOG_WARNING("It will generate exceptions as setting %" PRIu32 " to %s", - value, nds32_regs[number].simple_mnemonic); - return true; - } - } - - i++; - } - - return false; -} diff --git a/src/target/nds32_reg.h b/src/target/nds32_reg.h deleted file mode 100644 index 8808cd244c..0000000000 --- a/src/target/nds32_reg.h +++ /dev/null @@ -1,325 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_TARGET_NDS32_REG_H -#define OPENOCD_TARGET_NDS32_REG_H - -#define SRIDX(a, b, c) ((a << 7) | (b << 3) | c) -#define NDS32_REGISTER_DISABLE (0x0) - -enum nds32_reg_number_s { - R0 = 0, /* general registers */ - R1, - R2, - R3, - R4, - R5, - R6, - R7, - R8, - R9, - R10, - R11, - R12, - R13, - R14, - R15, - R16, - R17, - R18, - R19, - R20, - R21, - R22, - R23, - R24, - R25, - R26, - R27, - R28, - R29, - R30, - R31, - PC, - D0LO, - D0HI, - D1LO, - D1HI, - ITB, - IFC_LP, - CR0, /* system registers */ - CR1, - CR2, - CR3, - CR4, - CR5, - CR6, - IR0, - IR1, - IR2, - IR3, - IR4, - IR5, - IR6, - IR7, - IR8, - IR9, - IR10, - IR11, - IR12, - IR13, - IR14, - IR15, - IR16, - IR17, - IR18, - IR19, - IR20, - IR21, - IR22, - IR23, - IR24, - IR25, - IR26, - IR27, - IR28, - IR29, - IR30, - MR0, - MR1, - MR2, - MR3, - MR4, - MR5, - MR6, - MR7, - MR8, - MR9, - MR10, - MR11, - DR0, - DR1, - DR2, - DR3, - DR4, - DR5, - DR6, - DR7, - DR8, - DR9, - DR10, - DR11, - DR12, - DR13, - DR14, - DR15, - DR16, - DR17, - DR18, - DR19, - DR20, - DR21, - DR22, - DR23, - DR24, - DR25, - DR26, - DR27, - DR28, - DR29, - DR30, - DR31, - DR32, - DR33, - DR34, - DR35, - DR36, - DR37, - DR38, - DR39, - DR40, - DR41, - DR42, - DR43, - DR44, - DR45, - DR46, - DR47, - DR48, - PFR0, - PFR1, - PFR2, - PFR3, - DMAR0, - DMAR1, - DMAR2, - DMAR3, - DMAR4, - DMAR5, - DMAR6, - DMAR7, - DMAR8, - DMAR9, - DMAR10, - RACR, - FUCPR, - IDR0, - IDR1, - SECUR0, - D0L24, /* audio registers */ - D1L24, - I0, - I1, - I2, - I3, - I4, - I5, - I6, - I7, - M1, - M2, - M3, - M5, - M6, - M7, - MOD, - LBE, - LE, - LC, - ADM_VBASE, - SHFT_CTL0, - SHFT_CTL1, - CB_CTL, - CBB0, - CBB1, - CBB2, - CBB3, - CBE0, - CBE1, - CBE2, - CBE3, - FPCSR, /* fpu */ - FPCFG, - FS0, - FS1, - FS2, - FS3, - FS4, - FS5, - FS6, - FS7, - FS8, - FS9, - FS10, - FS11, - FS12, - FS13, - FS14, - FS15, - FS16, - FS17, - FS18, - FS19, - FS20, - FS21, - FS22, - FS23, - FS24, - FS25, - FS26, - FS27, - FS28, - FS29, - FS30, - FS31, - FD0, - FD1, - FD2, - FD3, - FD4, - FD5, - FD6, - FD7, - FD8, - FD9, - FD10, - FD11, - FD12, - FD13, - FD14, - FD15, - FD16, - FD17, - FD18, - FD19, - FD20, - FD21, - FD22, - FD23, - FD24, - FD25, - FD26, - FD27, - FD28, - FD29, - FD30, - FD31, - - TOTAL_REG_NUM, -}; - -enum nds32_reg_type_s { - NDS32_REG_TYPE_GPR = 0, - NDS32_REG_TYPE_SPR, - NDS32_REG_TYPE_CR, - NDS32_REG_TYPE_IR, - NDS32_REG_TYPE_MR, - NDS32_REG_TYPE_DR, - NDS32_REG_TYPE_PFR, - NDS32_REG_TYPE_DMAR, - NDS32_REG_TYPE_RACR, - NDS32_REG_TYPE_IDR, - NDS32_REG_TYPE_AUMR, - NDS32_REG_TYPE_SECURE, - NDS32_REG_TYPE_FPU, -}; - -struct nds32_reg_s { - const char *simple_mnemonic; - const char *symbolic_mnemonic; - uint32_t sr_index; - enum nds32_reg_type_s type; - uint8_t size; -}; - -struct nds32_reg_exception_s { - uint32_t reg_num; - uint32_t ex_value_bit_pos; - uint32_t ex_value_mask; - uint32_t ex_value; -}; - -void nds32_reg_init(void); -uint32_t nds32_reg_sr_index(uint32_t number); -enum nds32_reg_type_s nds32_reg_type(uint32_t number); -uint8_t nds32_reg_size(uint32_t number); -const char *nds32_reg_simple_name(uint32_t number); -const char *nds32_reg_symbolic_name(uint32_t number); -bool nds32_reg_exception(uint32_t number, uint32_t value); - -#endif /* OPENOCD_TARGET_NDS32_REG_H */ diff --git a/src/target/nds32_tlb.c b/src/target/nds32_tlb.c deleted file mode 100644 index 81734e0c1d..0000000000 --- a/src/target/nds32_tlb.c +++ /dev/null @@ -1,78 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "nds32_aice.h" -#include "nds32_tlb.h" - -int nds32_probe_tlb(struct nds32 *nds32, const target_addr_t virtual_address, - target_addr_t *physical_address) -{ - struct target *target = nds32->target; - struct aice_port_s *aice = target_to_aice(target); - - return aice_read_tlb(aice, virtual_address, physical_address); -} - -static struct page_table_walker_info_s page_table_info[PAGE_SIZE_NUM] = { - /* 4K page */ - {0xFFC00000, 20, 0x003FF000, 10, 0x00000FFF, 0xFFFFF000, 0xFFFFF000, 0xFFFFF000}, - /* 8K page */ - {0xFF000000, 22, 0x00FFE000, 11, 0x00001FFF, 0xFFFFF000, 0xFFFFE000, 0xFFFFE000}, -}; - -int nds32_walk_page_table(struct nds32 *nds32, const target_addr_t virtual_address, - target_addr_t *physical_address) -{ - struct target *target = nds32->target; - uint32_t value_mr1; - uint32_t load_address; - uint32_t l1_page_table_entry; - uint32_t l2_page_table_entry; - uint32_t page_size_index = nds32->mmu_config.default_min_page_size; - struct page_table_walker_info_s *page_table_info_p = - &(page_table_info[page_size_index]); - - /* Read L1 Physical Page Table */ - nds32_get_mapped_reg(nds32, MR1, &value_mr1); - load_address = (value_mr1 & page_table_info_p->l1_base_mask) | - ((virtual_address & page_table_info_p->l1_offset_mask) >> - page_table_info_p->l1_offset_shift); - /* load_address is physical address */ - nds32_read_buffer(target, load_address, 4, (uint8_t *)&l1_page_table_entry); - - /* Read L2 Physical Page Table */ - if (l1_page_table_entry & 0x1) /* L1_PTE not present */ - return ERROR_FAIL; - - load_address = (l1_page_table_entry & page_table_info_p->l2_base_mask) | - ((virtual_address & page_table_info_p->l2_offset_mask) >> - page_table_info_p->l2_offset_shift); - /* load_address is physical address */ - nds32_read_buffer(target, load_address, 4, (uint8_t *)&l2_page_table_entry); - - if ((l2_page_table_entry & 0x1) != 0x1) /* L2_PTE not valid */ - return ERROR_FAIL; - - *physical_address = (l2_page_table_entry & page_table_info_p->ppn_mask) | - (virtual_address & page_table_info_p->va_offset_mask); - - return ERROR_OK; -} diff --git a/src/target/nds32_tlb.h b/src/target/nds32_tlb.h deleted file mode 100644 index c22ed7335e..0000000000 --- a/src/target/nds32_tlb.h +++ /dev/null @@ -1,47 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_TARGET_NDS32_TLB_H -#define OPENOCD_TARGET_NDS32_TLB_H - -#include "nds32.h" - -enum { - PAGE_SIZE_4K = 0, - PAGE_SIZE_8K, - PAGE_SIZE_NUM, -}; - -struct page_table_walker_info_s { - - uint32_t l1_offset_mask; - uint32_t l1_offset_shift; - uint32_t l2_offset_mask; - uint32_t l2_offset_shift; - uint32_t va_offset_mask; - uint32_t l1_base_mask; - uint32_t l2_base_mask; - uint32_t ppn_mask; -}; - -extern int nds32_probe_tlb(struct nds32 *nds32, const target_addr_t virtual_address, - target_addr_t *physical_address); -extern int nds32_walk_page_table(struct nds32 *nds32, const target_addr_t virtual_address, - target_addr_t *physical_address); - -#endif /* OPENOCD_TARGET_NDS32_TLB_H */ diff --git a/src/target/nds32_v2.c b/src/target/nds32_v2.c deleted file mode 100644 index 49a5758f70..0000000000 --- a/src/target/nds32_v2.c +++ /dev/null @@ -1,785 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <helper/time_support.h> -#include <helper/binarybuffer.h> -#include "breakpoints.h" -#include "nds32_insn.h" -#include "nds32_reg.h" -#include "nds32_edm.h" -#include "nds32_cmd.h" -#include "nds32_v2.h" -#include "nds32_aice.h" -#include "target_type.h" - -static int nds32_v2_register_mapping(struct nds32 *nds32, int reg_no) -{ - uint32_t max_level = nds32->max_interrupt_level; - uint32_t cur_level = nds32->current_interrupt_level; - - if ((cur_level >= 1) && (cur_level < max_level)) { - if (reg_no == IR0) { - LOG_DEBUG("Map PSW to IPSW"); - return IR1; - } else if (reg_no == PC) { - LOG_DEBUG("Map PC to IPC"); - return IR9; - } - } else if ((cur_level >= 2) && (cur_level < max_level)) { - if (reg_no == R26) { - LOG_DEBUG("Mapping P0 to P_P0"); - return IR12; - } else if (reg_no == R27) { - LOG_DEBUG("Mapping P1 to P_P1"); - return IR13; - } else if (reg_no == IR1) { - LOG_DEBUG("Mapping IPSW to P_IPSW"); - return IR2; - } else if (reg_no == IR4) { - LOG_DEBUG("Mapping EVA to P_EVA"); - return IR5; - } else if (reg_no == IR6) { - LOG_DEBUG("Mapping ITYPE to P_ITYPE"); - return IR7; - } else if (reg_no == IR9) { - LOG_DEBUG("Mapping IPC to P_IPC"); - return IR10; - } - } else if (cur_level == max_level) { - if (reg_no == PC) { - LOG_DEBUG("Mapping PC to O_IPC"); - return IR11; - } - } - - return reg_no; -} - -static int nds32_v2_get_debug_reason(struct nds32 *nds32, uint32_t *reason) -{ - uint32_t val_itype; - struct aice_port_s *aice = target_to_aice(nds32->target); - - aice_read_register(aice, IR6, &val_itype); - - *reason = val_itype & 0x0F; - - return ERROR_OK; -} - -static int nds32_v2_activate_hardware_breakpoint(struct target *target) -{ - struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target); - struct aice_port_s *aice = target_to_aice(target); - struct breakpoint *bp; - int32_t hbr_index = 0; - - for (bp = target->breakpoints; bp; bp = bp->next) { - if (bp->type == BKPT_SOFT) { - /* already set at nds32_v2_add_breakpoint() */ - continue; - } else if (bp->type == BKPT_HARD) { - /* set address */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + hbr_index, bp->address); - /* set mask */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + hbr_index, 0); - /* set value */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + hbr_index, 0); - - if (nds32_v2->nds32.memory.address_translation) - /* enable breakpoint (virtual address) */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x2); - else - /* enable breakpoint (physical address) */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0xA); - - LOG_DEBUG("Add hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index, - bp->address); - - hbr_index++; - } else { - return ERROR_FAIL; - } - } - - return ERROR_OK; -} - -static int nds32_v2_deactivate_hardware_breakpoint(struct target *target) -{ - struct aice_port_s *aice = target_to_aice(target); - struct breakpoint *bp; - int32_t hbr_index = 0; - - for (bp = target->breakpoints; bp; bp = bp->next) { - if (bp->type == BKPT_SOFT) - continue; - else if (bp->type == BKPT_HARD) - /* disable breakpoint */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x0); - else - return ERROR_FAIL; - - LOG_DEBUG("Remove hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index, - bp->address); - - hbr_index++; - } - - return ERROR_OK; -} - -static int nds32_v2_activate_hardware_watchpoint(struct target *target) -{ - struct aice_port_s *aice = target_to_aice(target); - struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target); - struct watchpoint *wp; - int32_t wp_num = nds32_v2->next_hbr_index; - uint32_t wp_config = 0; - - for (wp = target->watchpoints; wp; wp = wp->next) { - - wp_num--; - wp->mask = wp->length - 1; - if ((wp->address % wp->length) != 0) - wp->mask = (wp->mask << 1) + 1; - - if (wp->rw == WPT_READ) - wp_config = 0x3; - else if (wp->rw == WPT_WRITE) - wp_config = 0x5; - else if (wp->rw == WPT_ACCESS) - wp_config = 0x7; - - /* set/unset physical address bit of BPCn according to PSW.DT */ - if (nds32_v2->nds32.memory.address_translation == false) - wp_config |= 0x8; - - /* set address */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num, - wp->address - (wp->address % wp->length)); - /* set mask */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask); - /* enable watchpoint */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config); - /* set value */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + wp_num, 0); - - LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR " mask %08" PRIx32, wp_num, - wp->address, wp->mask); - - } - - return ERROR_OK; -} - -static int nds32_v2_deactivate_hardware_watchpoint(struct target *target) -{ - struct aice_port_s *aice = target_to_aice(target); - struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target); - int32_t wp_num = nds32_v2->next_hbr_index; - struct watchpoint *wp; - - for (wp = target->watchpoints; wp; wp = wp->next) { - wp_num--; - /* disable watchpoint */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0); - - LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR " mask %08" PRIx32, - wp_num, wp->address, wp->mask); - } - - return ERROR_OK; -} - -static int nds32_v2_check_interrupt_stack(struct nds32_v2_common *nds32_v2) -{ - struct nds32 *nds32 = &(nds32_v2->nds32); - struct aice_port_s *aice = target_to_aice(nds32->target); - uint32_t val_ir0; - uint32_t val_ir1; - uint32_t val_ir2; - uint32_t modified_psw; - - /* Save interrupt level */ - aice_read_register(aice, IR0, &val_ir0); /* get $IR0 directly */ - - /* backup $IR0 */ - nds32_v2->backup_ir0 = val_ir0; - - nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3; - - if (nds32_reach_max_interrupt_level(nds32)) { - LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32 ". -->", - nds32->current_interrupt_level); - - /* decrease interrupt level */ - modified_psw = val_ir0 - 0x2; - - /* disable GIE, IT, DT, HSS */ - modified_psw &= (~0x8C1); - - aice_write_register(aice, IR0, modified_psw); - - return ERROR_OK; - } - - /* There is a case that single step also trigger another interrupt, - then HSS bit in psw(ir0) will push to ipsw(ir1). - Then hit debug interrupt HSS bit in ipsw(ir1) will push to (p_ipsw)ir2 - Therefore, HSS bit in p_ipsw(ir2) also need clear. - - Only update $ir2 as current interrupt level is 2, because $ir2 will be random - value if the target never reaches interrupt level 2. */ - if ((nds32->max_interrupt_level == 3) && (nds32->current_interrupt_level == 2)) { - aice_read_register(aice, IR2, &val_ir2); /* get $IR2 directly */ - val_ir2 &= ~(0x01 << 11); - aice_write_register(aice, IR2, val_ir2); - } - - /* get original DT bit and set to current state let debugger has same memory view - PSW.IT MUST be turned off. Otherwise, DIM could not operate normally. */ - aice_read_register(aice, IR1, &val_ir1); - modified_psw = val_ir0 | (val_ir1 & 0x80); - aice_write_register(aice, IR0, modified_psw); - - return ERROR_OK; -} - -static int nds32_v2_restore_interrupt_stack(struct nds32_v2_common *nds32_v2) -{ - struct nds32 *nds32 = &(nds32_v2->nds32); - struct aice_port_s *aice = target_to_aice(nds32->target); - - /* restore origin $IR0 */ - aice_write_register(aice, IR0, nds32_v2->backup_ir0); - - return ERROR_OK; -} - -/** - * Save processor state. This is called after a HALT instruction - * succeeds, and on other occasions the processor enters debug mode - * (breakpoint, watchpoint, etc). - */ -static int nds32_v2_debug_entry(struct nds32 *nds32, bool enable_watchpoint) -{ - LOG_DEBUG("nds32_v2_debug_entry"); - - if (nds32->virtual_hosting) - LOG_WARNING("<-- TARGET WARNING! Virtual hosting is not supported " - "under V1/V2 architecture. -->"); - - enum target_state backup_state = nds32->target->state; - nds32->target->state = TARGET_HALTED; - - if (nds32->init_arch_info_after_halted == false) { - /* init architecture info according to config registers */ - CHECK_RETVAL(nds32_config(nds32)); - - nds32->init_arch_info_after_halted = true; - } - - /* REVISIT entire cache should already be invalid !!! */ - register_cache_invalidate(nds32->core_cache); - - /* deactivate all hardware breakpoints */ - CHECK_RETVAL(nds32_v2_deactivate_hardware_breakpoint(nds32->target)); - - if (enable_watchpoint) - CHECK_RETVAL(nds32_v2_deactivate_hardware_watchpoint(nds32->target)); - - if (nds32_examine_debug_reason(nds32) != ERROR_OK) { - nds32->target->state = backup_state; - - /* re-activate all hardware breakpoints & watchpoints */ - CHECK_RETVAL(nds32_v2_activate_hardware_breakpoint(nds32->target)); - - if (enable_watchpoint) { - /* activate all watchpoints */ - CHECK_RETVAL(nds32_v2_activate_hardware_watchpoint(nds32->target)); - } - - return ERROR_FAIL; - } - - /* check interrupt level before .full_context(), because - * get_mapped_reg() in nds32_full_context() needs current_interrupt_level - * information */ - struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(nds32->target); - nds32_v2_check_interrupt_stack(nds32_v2); - - /* Save registers. */ - nds32_full_context(nds32); - - return ERROR_OK; -} - -/* target request support */ -static int nds32_v2_target_request_data(struct target *target, - uint32_t size, uint8_t *buffer) -{ - /* AndesCore could use DTR register to communicate with OpenOCD - * to output messages - * Target data will be put in buffer - * The format of DTR is as follow - * DTR[31:16] => length, DTR[15:8] => size, DTR[7:0] => target_req_cmd - * target_req_cmd has three possible values: - * TARGET_REQ_TRACEMSG - * TARGET_REQ_DEBUGMSG - * TARGET_REQ_DEBUGCHAR - * if size == 0, target will call target_asciimsg(), - * else call target_hexmsg() - */ - LOG_WARNING("Not implemented: %s", __func__); - - return ERROR_OK; -} - -/** - * Restore processor state. - */ -static int nds32_v2_leave_debug_state(struct nds32 *nds32, bool enable_watchpoint) -{ - LOG_DEBUG("nds32_v2_leave_debug_state"); - - struct target *target = nds32->target; - - /* activate all hardware breakpoints */ - CHECK_RETVAL(nds32_v2_activate_hardware_breakpoint(nds32->target)); - - if (enable_watchpoint) { - /* activate all watchpoints */ - CHECK_RETVAL(nds32_v2_activate_hardware_watchpoint(nds32->target)); - } - - /* restore interrupt stack */ - struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(nds32->target); - nds32_v2_restore_interrupt_stack(nds32_v2); - - /* restore PSW, PC, and R0 ... after flushing any modified - * registers. - */ - CHECK_RETVAL(nds32_restore_context(target)); - - register_cache_invalidate(nds32->core_cache); - - return ERROR_OK; -} - -static int nds32_v2_deassert_reset(struct target *target) -{ - int retval; - - CHECK_RETVAL(nds32_poll(target)); - - if (target->state != TARGET_HALTED) { - /* reset only */ - LOG_WARNING("%s: ran after reset and before halt ...", - target_name(target)); - retval = target_halt(target); - if (retval != ERROR_OK) - return retval; - } - - return ERROR_OK; -} - -static int nds32_v2_checksum_memory(struct target *target, - target_addr_t address, uint32_t count, uint32_t *checksum) -{ - LOG_WARNING("Not implemented: %s", __func__); - - return ERROR_FAIL; -} - -static int nds32_v2_add_breakpoint(struct target *target, - struct breakpoint *breakpoint) -{ - struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target); - struct nds32 *nds32 = &(nds32_v2->nds32); - int result; - - if (breakpoint->type == BKPT_HARD) { - /* check hardware resource */ - if (nds32_v2->n_hbr <= nds32_v2->next_hbr_index) { - LOG_WARNING("<-- TARGET WARNING! Insert too many hardware " - "breakpoints/watchpoints! The limit of " - "combined hardware breakpoints/watchpoints " - "is %" PRId32 ". -->", nds32_v2->n_hbr); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - /* update next place to put hardware breakpoint */ - nds32_v2->next_hbr_index++; - - /* hardware breakpoint insertion occurs before 'continue' actually */ - return ERROR_OK; - } else if (breakpoint->type == BKPT_SOFT) { - result = nds32_add_software_breakpoint(target, breakpoint); - if (result != ERROR_OK) { - /* auto convert to hardware breakpoint if failed */ - if (nds32->auto_convert_hw_bp) { - /* convert to hardware breakpoint */ - breakpoint->type = BKPT_HARD; - - return nds32_v2_add_breakpoint(target, breakpoint); - } - } - - return result; - } else /* unrecognized breakpoint type */ - return ERROR_FAIL; - - return ERROR_OK; -} - -static int nds32_v2_remove_breakpoint(struct target *target, - struct breakpoint *breakpoint) -{ - struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target); - - if (breakpoint->type == BKPT_HARD) { - if (nds32_v2->next_hbr_index <= 0) - return ERROR_FAIL; - - /* update next place to put hardware breakpoint */ - nds32_v2->next_hbr_index--; - - /* hardware breakpoint removal occurs after 'halted' actually */ - return ERROR_OK; - } else if (breakpoint->type == BKPT_SOFT) { - return nds32_remove_software_breakpoint(target, breakpoint); - } else /* unrecognized breakpoint type */ - return ERROR_FAIL; - - return ERROR_OK; -} - -static int nds32_v2_add_watchpoint(struct target *target, - struct watchpoint *watchpoint) -{ - struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target); - - /* check hardware resource */ - if (nds32_v2->n_hbr <= nds32_v2->next_hbr_index) { - LOG_WARNING("<-- TARGET WARNING! Insert too many hardware " - "breakpoints/watchpoints! The limit of " - "combined hardware breakpoints/watchpoints is %" PRId32 ". -->", nds32_v2->n_hbr); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - /* update next place to put hardware watchpoint */ - nds32_v2->next_hbr_index++; - - return ERROR_OK; -} - -static int nds32_v2_remove_watchpoint(struct target *target, - struct watchpoint *watchpoint) -{ - struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target); - - if (nds32_v2->next_hbr_index <= 0) - return ERROR_FAIL; - - /* update next place to put hardware breakpoint */ - nds32_v2->next_hbr_index--; - - return ERROR_OK; -} - -static int nds32_v2_get_exception_address(struct nds32 *nds32, - uint32_t *address, uint32_t reason) -{ - struct aice_port_s *aice = target_to_aice(nds32->target); - - aice_read_register(aice, IR4, address); /* read $EVA directly */ - - /* TODO: hit multiple watchpoints */ - - return ERROR_OK; -} - -/** - * find out which watchpoint hits - * get exception address and compare the address to watchpoints - */ -static int nds32_v2_hit_watchpoint(struct target *target, - struct watchpoint **hit_watchpoint) -{ - uint32_t exception_address; - struct watchpoint *wp; - static struct watchpoint scan_all_watchpoint; - struct nds32 *nds32 = target_to_nds32(target); - - scan_all_watchpoint.address = 0; - scan_all_watchpoint.rw = WPT_WRITE; - scan_all_watchpoint.next = 0; - scan_all_watchpoint.unique_id = 0x5CA8; - - exception_address = nds32->watched_address; - - if (exception_address == 0) { - /* send watch:0 to tell GDB to do software scan for hitting multiple watchpoints */ - *hit_watchpoint = &scan_all_watchpoint; - return ERROR_OK; - } - - for (wp = target->watchpoints; wp; wp = wp->next) { - if (((exception_address ^ wp->address) & (~wp->mask)) == 0) { - /* TODO: dispel false match */ - *hit_watchpoint = wp; - return ERROR_OK; - } - } - - return ERROR_FAIL; -} - -static int nds32_v2_run_algorithm(struct target *target, - int num_mem_params, - struct mem_param *mem_params, - int num_reg_params, - struct reg_param *reg_params, - target_addr_t entry_point, - target_addr_t exit_point, - int timeout_ms, - void *arch_info) -{ - LOG_WARNING("Not implemented: %s", __func__); - - return ERROR_FAIL; -} - -static int nds32_v2_target_create(struct target *target, Jim_Interp *interp) -{ - struct nds32_v2_common *nds32_v2; - - nds32_v2 = calloc(1, sizeof(*nds32_v2)); - if (!nds32_v2) - return ERROR_FAIL; - - nds32_v2->nds32.register_map = nds32_v2_register_mapping; - nds32_v2->nds32.get_debug_reason = nds32_v2_get_debug_reason; - nds32_v2->nds32.enter_debug_state = nds32_v2_debug_entry; - nds32_v2->nds32.leave_debug_state = nds32_v2_leave_debug_state; - nds32_v2->nds32.get_watched_address = nds32_v2_get_exception_address; - - nds32_init_arch_info(target, &(nds32_v2->nds32)); - - return ERROR_OK; -} - -static int nds32_v2_init_target(struct command_context *cmd_ctx, - struct target *target) -{ - /* Initialize anything we can set up without talking to the target */ - - struct nds32 *nds32 = target_to_nds32(target); - - nds32_init(nds32); - - return ERROR_OK; -} - -/* talk to the target and set things up */ -static int nds32_v2_examine(struct target *target) -{ - struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target); - struct nds32 *nds32 = &(nds32_v2->nds32); - struct aice_port_s *aice = target_to_aice(target); - - if (!target_was_examined(target)) { - CHECK_RETVAL(nds32_edm_config(nds32)); - - if (nds32->reset_halt_as_examine) - CHECK_RETVAL(nds32_reset_halt(nds32)); - } - - uint32_t edm_cfg; - aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg); - - /* get the number of hardware breakpoints */ - nds32_v2->n_hbr = (edm_cfg & 0x7) + 1; - - nds32_v2->next_hbr_index = 0; - - LOG_INFO("%s: total hardware breakpoint %" PRId32, target_name(target), - nds32_v2->n_hbr); - - nds32->target->state = TARGET_RUNNING; - nds32->target->debug_reason = DBG_REASON_NOTHALTED; - - target_set_examined(target); - - return ERROR_OK; -} - -static int nds32_v2_translate_address(struct target *target, target_addr_t *address) -{ - struct nds32 *nds32 = target_to_nds32(target); - struct nds32_memory *memory = &(nds32->memory); - target_addr_t physical_address; - - /* Following conditions need to do address translation - * 1. BUS mode - * 2. CPU mode under maximum interrupt level */ - if ((memory->access_channel == NDS_MEMORY_ACC_BUS) || - ((memory->access_channel == NDS_MEMORY_ACC_CPU) && - nds32_reach_max_interrupt_level(nds32))) { - if (target->type->virt2phys(target, *address, &physical_address) == ERROR_OK) - *address = physical_address; - else - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int nds32_v2_read_buffer(struct target *target, target_addr_t address, - uint32_t size, uint8_t *buffer) -{ - struct nds32 *nds32 = target_to_nds32(target); - struct nds32_memory *memory = &(nds32->memory); - - if ((memory->access_channel == NDS_MEMORY_ACC_CPU) && - (target->state != TARGET_HALTED)) { - LOG_WARNING("target was not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* BUG: If access range crosses multiple pages, the translation will not correct - * for second page or so. */ - - nds32_v2_translate_address(target, &address); - - return nds32_read_buffer(target, address, size, buffer); -} - -static int nds32_v2_write_buffer(struct target *target, target_addr_t address, - uint32_t size, const uint8_t *buffer) -{ - struct nds32 *nds32 = target_to_nds32(target); - struct nds32_memory *memory = &(nds32->memory); - - if ((memory->access_channel == NDS_MEMORY_ACC_CPU) && - (target->state != TARGET_HALTED)) { - LOG_WARNING("target was not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* BUG: If access range crosses multiple pages, the translation will not correct - * for second page or so. */ - - nds32_v2_translate_address(target, &address); - - return nds32_write_buffer(target, address, size, buffer); -} - -static int nds32_v2_read_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) -{ - struct nds32 *nds32 = target_to_nds32(target); - struct nds32_memory *memory = &(nds32->memory); - - if ((memory->access_channel == NDS_MEMORY_ACC_CPU) && - (target->state != TARGET_HALTED)) { - LOG_WARNING("target was not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* BUG: If access range crosses multiple pages, the translation will not correct - * for second page or so. */ - - nds32_v2_translate_address(target, &address); - - return nds32_read_memory(target, address, size, count, buffer); -} - -static int nds32_v2_write_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer) -{ - struct nds32 *nds32 = target_to_nds32(target); - struct nds32_memory *memory = &(nds32->memory); - - if ((memory->access_channel == NDS_MEMORY_ACC_CPU) && - (target->state != TARGET_HALTED)) { - LOG_WARNING("target was not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* BUG: If access range crosses multiple pages, the translation will not correct - * for second page or so. */ - - nds32_v2_translate_address(target, &address); - - return nds32_write_memory(target, address, size, count, buffer); -} - -/** Holds methods for V2 targets. */ -struct target_type nds32_v2_target = { - .name = "nds32_v2", - - .poll = nds32_poll, - .arch_state = nds32_arch_state, - - .target_request_data = nds32_v2_target_request_data, - - .halt = nds32_halt, - .resume = nds32_resume, - .step = nds32_step, - - .assert_reset = nds32_assert_reset, - .deassert_reset = nds32_v2_deassert_reset, - - /* register access */ - .get_gdb_reg_list = nds32_get_gdb_reg_list, - - /* memory access */ - .read_buffer = nds32_v2_read_buffer, - .write_buffer = nds32_v2_write_buffer, - .read_memory = nds32_v2_read_memory, - .write_memory = nds32_v2_write_memory, - - .checksum_memory = nds32_v2_checksum_memory, - - /* breakpoint/watchpoint */ - .add_breakpoint = nds32_v2_add_breakpoint, - .remove_breakpoint = nds32_v2_remove_breakpoint, - .add_watchpoint = nds32_v2_add_watchpoint, - .remove_watchpoint = nds32_v2_remove_watchpoint, - .hit_watchpoint = nds32_v2_hit_watchpoint, - - /* MMU */ - .mmu = nds32_mmu, - .virt2phys = nds32_virtual_to_physical, - .read_phys_memory = nds32_read_phys_memory, - .write_phys_memory = nds32_write_phys_memory, - - .run_algorithm = nds32_v2_run_algorithm, - - .commands = nds32_command_handlers, - .target_create = nds32_v2_target_create, - .init_target = nds32_v2_init_target, - .examine = nds32_v2_examine, -}; diff --git a/src/target/nds32_v2.h b/src/target/nds32_v2.h deleted file mode 100644 index dcc08c29e3..0000000000 --- a/src/target/nds32_v2.h +++ /dev/null @@ -1,42 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_TARGET_NDS32_V2_H -#define OPENOCD_TARGET_NDS32_V2_H - -#include "nds32.h" - -struct nds32_v2_common { - struct nds32 nds32; - - uint32_t backup_ir0; - - /** number of hardware breakpoints */ - int32_t n_hbr; - - /** next hardware breakpoint index */ - /** increase from low index to high index */ - int32_t next_hbr_index; -}; - -static inline struct nds32_v2_common *target_to_nds32_v2(struct target *target) -{ - return container_of(target->arch_info, struct nds32_v2_common, nds32); -} - -#endif /* OPENOCD_TARGET_NDS32_V2_H */ diff --git a/src/target/nds32_v3.c b/src/target/nds32_v3.c deleted file mode 100644 index fde86d6e83..0000000000 --- a/src/target/nds32_v3.c +++ /dev/null @@ -1,521 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "breakpoints.h" -#include "nds32_cmd.h" -#include "nds32_aice.h" -#include "nds32_v3.h" -#include "nds32_v3_common.h" - -static int nds32_v3_activate_hardware_breakpoint(struct target *target) -{ - struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target); - struct aice_port_s *aice = target_to_aice(target); - struct breakpoint *bp; - int32_t hbr_index = nds32_v3->next_hbr_index; - - for (bp = target->breakpoints; bp; bp = bp->next) { - if (bp->type == BKPT_SOFT) { - /* already set at nds32_v3_add_breakpoint() */ - continue; - } else if (bp->type == BKPT_HARD) { - hbr_index--; - /* set address */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + hbr_index, bp->address); - /* set mask */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + hbr_index, 0); - /* set value */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + hbr_index, 0); - - if (nds32_v3->nds32.memory.address_translation) - /* enable breakpoint (virtual address) */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x2); - else - /* enable breakpoint (physical address) */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0xA); - - LOG_DEBUG("Add hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index, - bp->address); - } else { - return ERROR_FAIL; - } - } - - return ERROR_OK; -} - -static int nds32_v3_deactivate_hardware_breakpoint(struct target *target) -{ - struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target); - struct aice_port_s *aice = target_to_aice(target); - struct breakpoint *bp; - int32_t hbr_index = nds32_v3->next_hbr_index; - - for (bp = target->breakpoints; bp; bp = bp->next) { - if (bp->type == BKPT_SOFT) { - continue; - } else if (bp->type == BKPT_HARD) { - hbr_index--; - /* disable breakpoint */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x0); - } else { - return ERROR_FAIL; - } - - LOG_DEBUG("Remove hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index, - bp->address); - } - - return ERROR_OK; -} - -static int nds32_v3_activate_hardware_watchpoint(struct target *target) -{ - struct aice_port_s *aice = target_to_aice(target); - struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target); - struct watchpoint *wp; - int32_t wp_num = 0; - uint32_t wp_config = 0; - bool ld_stop, st_stop; - - if (nds32_v3->nds32.global_stop) - ld_stop = st_stop = false; - - for (wp = target->watchpoints; wp; wp = wp->next) { - - if (wp_num < nds32_v3->used_n_wp) { - wp->mask = wp->length - 1; - if ((wp->address % wp->length) != 0) - wp->mask = (wp->mask << 1) + 1; - - if (wp->rw == WPT_READ) - wp_config = 0x3; - else if (wp->rw == WPT_WRITE) - wp_config = 0x5; - else if (wp->rw == WPT_ACCESS) - wp_config = 0x7; - - /* set/unset physical address bit of BPCn according to PSW.DT */ - if (nds32_v3->nds32.memory.address_translation == false) - wp_config |= 0x8; - - /* set address */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num, - wp->address - (wp->address % wp->length)); - /* set mask */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask); - /* enable watchpoint */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config); - /* set value */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + wp_num, 0); - - LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR " mask %08" PRIx32, - wp_num, wp->address, wp->mask); - - wp_num++; - } else if (nds32_v3->nds32.global_stop) { - if (wp->rw == WPT_READ) - ld_stop = true; - else if (wp->rw == WPT_WRITE) - st_stop = true; - else if (wp->rw == WPT_ACCESS) - ld_stop = st_stop = true; - } - } - - if (nds32_v3->nds32.global_stop) { - uint32_t edm_ctl; - aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl); - if (ld_stop) - edm_ctl |= 0x10; - if (st_stop) - edm_ctl |= 0x20; - aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl); - } - - return ERROR_OK; -} - -static int nds32_v3_deactivate_hardware_watchpoint(struct target *target) -{ - struct aice_port_s *aice = target_to_aice(target); - struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target); - int32_t wp_num = 0; - struct watchpoint *wp; - bool clean_global_stop = false; - - for (wp = target->watchpoints; wp; wp = wp->next) { - - if (wp_num < nds32_v3->used_n_wp) { - /* disable watchpoint */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0); - - LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR - " mask %08" PRIx32, wp_num, - wp->address, wp->mask); - wp_num++; - } else if (nds32_v3->nds32.global_stop) { - clean_global_stop = true; - } - } - - if (clean_global_stop) { - uint32_t edm_ctl; - aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl); - edm_ctl = edm_ctl & (~0x30); - aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl); - } - - return ERROR_OK; -} - -static int nds32_v3_check_interrupt_stack(struct nds32 *nds32) -{ - uint32_t val_ir0; - uint32_t value; - - /* Save interrupt level */ - nds32_get_mapped_reg(nds32, IR0, &val_ir0); - nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3; - - if (nds32_reach_max_interrupt_level(nds32)) - LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32 ". -->", - nds32->current_interrupt_level); - - /* backup $ir4 & $ir6 to avoid suppressed exception overwrite */ - nds32_get_mapped_reg(nds32, IR4, &value); - nds32_get_mapped_reg(nds32, IR6, &value); - - return ERROR_OK; -} - -static int nds32_v3_restore_interrupt_stack(struct nds32 *nds32) -{ - uint32_t value; - - /* get backup value from cache */ - /* then set back to make the register dirty */ - nds32_get_mapped_reg(nds32, IR0, &value); - nds32_set_mapped_reg(nds32, IR0, value); - - nds32_get_mapped_reg(nds32, IR4, &value); - nds32_set_mapped_reg(nds32, IR4, value); - - nds32_get_mapped_reg(nds32, IR6, &value); - nds32_set_mapped_reg(nds32, IR6, value); - - return ERROR_OK; -} - -static int nds32_v3_deassert_reset(struct target *target) -{ - int retval; - struct aice_port_s *aice = target_to_aice(target); - bool switch_to_v3_stack = false; - uint32_t value_edm_ctl; - - aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &value_edm_ctl); - if (((value_edm_ctl >> 6) & 0x1) == 0) { /* reset to V2 EDM mode */ - aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, value_edm_ctl | (0x1 << 6)); - aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &value_edm_ctl); - if (((value_edm_ctl >> 6) & 0x1) == 1) - switch_to_v3_stack = true; - } else - switch_to_v3_stack = false; - - CHECK_RETVAL(nds32_poll(target)); - - if (target->state != TARGET_HALTED) { - /* reset only */ - LOG_WARNING("%s: ran after reset and before halt ...", - target_name(target)); - retval = target_halt(target); - if (retval != ERROR_OK) - return retval; - - } else { - /* reset-halt */ - struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target); - struct nds32 *nds32 = &(nds32_v3->nds32); - uint32_t value; - uint32_t interrupt_level; - - if (switch_to_v3_stack == true) { - /* PSW.INTL-- */ - nds32_get_mapped_reg(nds32, IR0, &value); - interrupt_level = (value >> 1) & 0x3; - interrupt_level--; - value &= ~(0x6); - value |= (interrupt_level << 1); - value |= 0x400; /* set PSW.DEX */ - nds32_set_mapped_reg(nds32, IR0, value); - - /* copy IPC to OIPC */ - if ((interrupt_level + 1) < nds32->max_interrupt_level) { - nds32_get_mapped_reg(nds32, IR9, &value); - nds32_set_mapped_reg(nds32, IR11, value); - } - } - } - - return ERROR_OK; -} - -static int nds32_v3_add_breakpoint(struct target *target, - struct breakpoint *breakpoint) -{ - struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target); - struct nds32 *nds32 = &(nds32_v3->nds32); - int result; - - if (breakpoint->type == BKPT_HARD) { - /* check hardware resource */ - if (nds32_v3->n_hbr <= nds32_v3->next_hbr_index) { - LOG_WARNING("<-- TARGET WARNING! Insert too many " - "hardware breakpoints/watchpoints! " - "The limit of combined hardware " - "breakpoints/watchpoints is %" PRId32 ". -->", - nds32_v3->n_hbr); - LOG_WARNING("<-- TARGET STATUS: Inserted number of " - "hardware breakpoint: %" PRId32 ", hardware " - "watchpoints: %" PRId32 ". -->", - nds32_v3->next_hbr_index - nds32_v3->used_n_wp, - nds32_v3->used_n_wp); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - /* update next place to put hardware breakpoint */ - nds32_v3->next_hbr_index++; - - /* hardware breakpoint insertion occurs before 'continue' actually */ - return ERROR_OK; - } else if (breakpoint->type == BKPT_SOFT) { - result = nds32_add_software_breakpoint(target, breakpoint); - if (result != ERROR_OK) { - /* auto convert to hardware breakpoint if failed */ - if (nds32->auto_convert_hw_bp) { - /* convert to hardware breakpoint */ - breakpoint->type = BKPT_HARD; - - return nds32_v3_add_breakpoint(target, breakpoint); - } - } - - return result; - } else /* unrecognized breakpoint type */ - return ERROR_FAIL; - - return ERROR_OK; -} - -static int nds32_v3_remove_breakpoint(struct target *target, - struct breakpoint *breakpoint) -{ - struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target); - - if (breakpoint->type == BKPT_HARD) { - if (nds32_v3->next_hbr_index <= 0) - return ERROR_FAIL; - - /* update next place to put hardware breakpoint */ - nds32_v3->next_hbr_index--; - - /* hardware breakpoint removal occurs after 'halted' actually */ - return ERROR_OK; - } else if (breakpoint->type == BKPT_SOFT) { - return nds32_remove_software_breakpoint(target, breakpoint); - } else /* unrecognized breakpoint type */ - return ERROR_FAIL; - - return ERROR_OK; -} - -static int nds32_v3_add_watchpoint(struct target *target, - struct watchpoint *watchpoint) -{ - struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target); - - /* check hardware resource */ - if (nds32_v3->n_hbr <= nds32_v3->next_hbr_index) { - /* No hardware resource */ - if (nds32_v3->nds32.global_stop) { - LOG_WARNING("<-- TARGET WARNING! The number of " - "watchpoints exceeds the hardware " - "resources. Stop at every load/store " - "instruction to check for watchpoint matches. -->"); - return ERROR_OK; - } - - LOG_WARNING("<-- TARGET WARNING! Insert too many hardware " - "breakpoints/watchpoints! The limit of combined " - "hardware breakpoints/watchpoints is %" PRId32 ". -->", - nds32_v3->n_hbr); - LOG_WARNING("<-- TARGET STATUS: Inserted number of " - "hardware breakpoint: %" PRId32 ", hardware " - "watchpoints: %" PRId32 ". -->", - nds32_v3->next_hbr_index - nds32_v3->used_n_wp, - nds32_v3->used_n_wp); - - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - /* update next place to put hardware watchpoint */ - nds32_v3->next_hbr_index++; - nds32_v3->used_n_wp++; - - return ERROR_OK; -} - -static int nds32_v3_remove_watchpoint(struct target *target, - struct watchpoint *watchpoint) -{ - struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target); - - if (nds32_v3->next_hbr_index <= 0) { - if (nds32_v3->nds32.global_stop) - return ERROR_OK; - - return ERROR_FAIL; - } - - /* update next place to put hardware breakpoint */ - nds32_v3->next_hbr_index--; - nds32_v3->used_n_wp--; - - return ERROR_OK; -} - -static struct nds32_v3_common_callback nds32_v3_common_callback = { - .check_interrupt_stack = nds32_v3_check_interrupt_stack, - .restore_interrupt_stack = nds32_v3_restore_interrupt_stack, - .activate_hardware_breakpoint = nds32_v3_activate_hardware_breakpoint, - .activate_hardware_watchpoint = nds32_v3_activate_hardware_watchpoint, - .deactivate_hardware_breakpoint = nds32_v3_deactivate_hardware_breakpoint, - .deactivate_hardware_watchpoint = nds32_v3_deactivate_hardware_watchpoint, -}; - -static int nds32_v3_target_create(struct target *target, Jim_Interp *interp) -{ - struct nds32_v3_common *nds32_v3; - - nds32_v3 = calloc(1, sizeof(*nds32_v3)); - if (!nds32_v3) - return ERROR_FAIL; - - nds32_v3_common_register_callback(&nds32_v3_common_callback); - nds32_v3_target_create_common(target, &(nds32_v3->nds32)); - - return ERROR_OK; -} - -/* talk to the target and set things up */ -static int nds32_v3_examine(struct target *target) -{ - struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target); - struct nds32 *nds32 = &(nds32_v3->nds32); - struct aice_port_s *aice = target_to_aice(target); - - if (!target_was_examined(target)) { - CHECK_RETVAL(nds32_edm_config(nds32)); - - if (nds32->reset_halt_as_examine) - CHECK_RETVAL(nds32_reset_halt(nds32)); - } - - uint32_t edm_cfg; - aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg); - - /* get the number of hardware breakpoints */ - nds32_v3->n_hbr = (edm_cfg & 0x7) + 1; - - /* low interference profiling */ - if (edm_cfg & 0x100) - nds32_v3->low_interference_profile = true; - else - nds32_v3->low_interference_profile = false; - - nds32_v3->next_hbr_index = 0; - nds32_v3->used_n_wp = 0; - - LOG_INFO("%s: total hardware breakpoint %" PRId32, target_name(target), - nds32_v3->n_hbr); - - nds32->target->state = TARGET_RUNNING; - nds32->target->debug_reason = DBG_REASON_NOTHALTED; - - target_set_examined(target); - - return ERROR_OK; -} - -/** Holds methods for Andes1337 targets. */ -struct target_type nds32_v3_target = { - .name = "nds32_v3", - - .poll = nds32_poll, - .arch_state = nds32_arch_state, - - .target_request_data = nds32_v3_target_request_data, - - .halt = nds32_halt, - .resume = nds32_resume, - .step = nds32_step, - - .assert_reset = nds32_assert_reset, - .deassert_reset = nds32_v3_deassert_reset, - - /* register access */ - .get_gdb_reg_list = nds32_get_gdb_reg_list, - - /* memory access */ - .read_buffer = nds32_v3_read_buffer, - .write_buffer = nds32_v3_write_buffer, - .read_memory = nds32_v3_read_memory, - .write_memory = nds32_v3_write_memory, - - .checksum_memory = nds32_v3_checksum_memory, - - /* breakpoint/watchpoint */ - .add_breakpoint = nds32_v3_add_breakpoint, - .remove_breakpoint = nds32_v3_remove_breakpoint, - .add_watchpoint = nds32_v3_add_watchpoint, - .remove_watchpoint = nds32_v3_remove_watchpoint, - .hit_watchpoint = nds32_v3_hit_watchpoint, - - /* MMU */ - .mmu = nds32_mmu, - .virt2phys = nds32_virtual_to_physical, - .read_phys_memory = nds32_read_phys_memory, - .write_phys_memory = nds32_write_phys_memory, - - .run_algorithm = nds32_v3_run_algorithm, - - .commands = nds32_command_handlers, - .target_create = nds32_v3_target_create, - .init_target = nds32_v3_init_target, - .examine = nds32_v3_examine, - - .get_gdb_fileio_info = nds32_get_gdb_fileio_info, - .gdb_fileio_end = nds32_gdb_fileio_end, - - .profiling = nds32_profiling, -}; diff --git a/src/target/nds32_v3.h b/src/target/nds32_v3.h deleted file mode 100644 index a5df8fe52b..0000000000 --- a/src/target/nds32_v3.h +++ /dev/null @@ -1,45 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_TARGET_NDS32_V3_H -#define OPENOCD_TARGET_NDS32_V3_H - -#include "nds32.h" - -struct nds32_v3_common { - struct nds32 nds32; - - /** number of hardware breakpoints */ - int32_t n_hbr; - - /** number of used hardware watchpoints */ - int32_t used_n_wp; - - /** next hardware breakpoint index */ - int32_t next_hbr_index; - - /** low interference profiling */ - bool low_interference_profile; -}; - -static inline struct nds32_v3_common *target_to_nds32_v3(struct target *target) -{ - return container_of(target->arch_info, struct nds32_v3_common, nds32); -} - -#endif /* OPENOCD_TARGET_NDS32_V3_H */ diff --git a/src/target/nds32_v3_common.c b/src/target/nds32_v3_common.c deleted file mode 100644 index 8ff8e30c62..0000000000 --- a/src/target/nds32_v3_common.c +++ /dev/null @@ -1,675 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "breakpoints.h" -#include "nds32_reg.h" -#include "nds32_disassembler.h" -#include "nds32.h" -#include "nds32_aice.h" -#include "nds32_v3_common.h" - -static struct nds32_v3_common_callback *v3_common_callback; - -static int nds32_v3_register_mapping(struct nds32 *nds32, int reg_no) -{ - if (reg_no == PC) - return IR11; - - return reg_no; -} - -static int nds32_v3_get_debug_reason(struct nds32 *nds32, uint32_t *reason) -{ - uint32_t edmsw; - struct aice_port_s *aice = target_to_aice(nds32->target); - aice_read_debug_reg(aice, NDS_EDM_SR_EDMSW, &edmsw); - - *reason = (edmsw >> 12) & 0x0F; - - return ERROR_OK; -} - -/** - * Save processor state. This is called after a HALT instruction - * succeeds, and on other occasions the processor enters debug mode - * (breakpoint, watchpoint, etc). - */ -static int nds32_v3_debug_entry(struct nds32 *nds32, bool enable_watchpoint) -{ - LOG_DEBUG("nds32_v3_debug_entry"); - - enum target_state backup_state = nds32->target->state; - nds32->target->state = TARGET_HALTED; - - if (nds32->init_arch_info_after_halted == false) { - /* init architecture info according to config registers */ - CHECK_RETVAL(nds32_config(nds32)); - - nds32->init_arch_info_after_halted = true; - } - - /* REVISIT entire cache should already be invalid !!! */ - register_cache_invalidate(nds32->core_cache); - - /* deactivate all hardware breakpoints */ - CHECK_RETVAL(v3_common_callback->deactivate_hardware_breakpoint(nds32->target)); - - if (enable_watchpoint) - CHECK_RETVAL(v3_common_callback->deactivate_hardware_watchpoint(nds32->target)); - - struct breakpoint *syscall_break = &(nds32->syscall_break); - if (nds32->virtual_hosting) { - if (syscall_break->is_set) { - /** disable virtual hosting */ - - /* remove breakpoint at syscall entry */ - target_remove_breakpoint(nds32->target, syscall_break); - syscall_break->is_set = false; - - uint32_t value_pc; - nds32_get_mapped_reg(nds32, PC, &value_pc); - if (value_pc == syscall_break->address) - /** process syscall for virtual hosting */ - nds32->hit_syscall = true; - } - } - - if (nds32_examine_debug_reason(nds32) != ERROR_OK) { - nds32->target->state = backup_state; - - /* re-activate all hardware breakpoints & watchpoints */ - CHECK_RETVAL(v3_common_callback->activate_hardware_breakpoint(nds32->target)); - - if (enable_watchpoint) - CHECK_RETVAL(v3_common_callback->activate_hardware_watchpoint(nds32->target)); - - return ERROR_FAIL; - } - - /* Save registers. */ - nds32_full_context(nds32); - - /* check interrupt level */ - v3_common_callback->check_interrupt_stack(nds32); - - return ERROR_OK; -} - -/** - * Restore processor state. - */ -static int nds32_v3_leave_debug_state(struct nds32 *nds32, bool enable_watchpoint) -{ - LOG_DEBUG("nds32_v3_leave_debug_state"); - - struct target *target = nds32->target; - - /* activate all hardware breakpoints */ - CHECK_RETVAL(v3_common_callback->activate_hardware_breakpoint(target)); - - if (enable_watchpoint) { - /* activate all watchpoints */ - CHECK_RETVAL(v3_common_callback->activate_hardware_watchpoint(target)); - } - - /* restore interrupt stack */ - v3_common_callback->restore_interrupt_stack(nds32); - - /* REVISIT once we start caring about MMU and cache state, - * address it here ... - */ - - /* restore PSW, PC, and R0 ... after flushing any modified - * registers. - */ - CHECK_RETVAL(nds32_restore_context(target)); - - if (nds32->virtual_hosting) { - /** enable virtual hosting */ - uint32_t value_ir3; - uint32_t entry_size; - uint32_t syscall_address; - - /* get syscall entry address */ - nds32_get_mapped_reg(nds32, IR3, &value_ir3); - entry_size = 0x4 << (((value_ir3 >> 14) & 0x3) << 1); - syscall_address = (value_ir3 & 0xFFFF0000) + entry_size * 8; /* The index of SYSCALL is 8 */ - - if (nds32->hit_syscall) { - /* single step to skip syscall entry */ - /* use IRET to skip syscall */ - struct aice_port_s *aice = target_to_aice(target); - uint32_t value_ir9; - uint32_t value_ir6; - uint32_t syscall_id; - - nds32_get_mapped_reg(nds32, IR6, &value_ir6); - syscall_id = (value_ir6 >> 16) & 0x7FFF; - - if (syscall_id == NDS32_SYSCALL_EXIT) { - /* If target hits exit syscall, do not use IRET to skip handler. */ - aice_step(aice); - } else { - /* use api->read/write_reg to skip nds32 register cache */ - uint32_t value_dimbr; - aice_read_debug_reg(aice, NDS_EDM_SR_DIMBR, &value_dimbr); - aice_write_register(aice, IR11, value_dimbr + 0xC); - - aice_read_register(aice, IR9, &value_ir9); - value_ir9 += 4; /* syscall is always 4 bytes */ - aice_write_register(aice, IR9, value_ir9); - - /* backup hardware breakpoint 0 */ - uint32_t backup_bpa, backup_bpam, backup_bpc; - aice_read_debug_reg(aice, NDS_EDM_SR_BPA0, &backup_bpa); - aice_read_debug_reg(aice, NDS_EDM_SR_BPAM0, &backup_bpam); - aice_read_debug_reg(aice, NDS_EDM_SR_BPC0, &backup_bpc); - - /* use hardware breakpoint 0 to stop cpu after skipping syscall */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPA0, value_ir9); - aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0, 0); - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0, 0xA); - - /* Execute two IRET. - * First IRET is used to quit debug mode. - * Second IRET is used to quit current syscall. */ - uint32_t dim_inst[4] = {NOP, NOP, IRET, IRET}; - aice_execute(aice, dim_inst, 4); - - /* restore origin hardware breakpoint 0 */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPA0, backup_bpa); - aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0, backup_bpam); - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0, backup_bpc); - } - - nds32->hit_syscall = false; - } - - /* insert breakpoint at syscall entry */ - struct breakpoint *syscall_break = &(nds32->syscall_break); - - syscall_break->address = syscall_address; - syscall_break->type = BKPT_SOFT; - syscall_break->is_set = true; - target_add_breakpoint(target, syscall_break); - } - - return ERROR_OK; -} - -static int nds32_v3_get_exception_address(struct nds32 *nds32, - uint32_t *address, uint32_t reason) -{ - LOG_DEBUG("nds32_v3_get_exception_address"); - - struct aice_port_s *aice = target_to_aice(nds32->target); - struct target *target = nds32->target; - uint32_t edmsw; - uint32_t edm_cfg; - uint32_t match_bits; - uint32_t match_count; - int32_t i; - static int32_t number_of_hard_break; - uint32_t bp_control; - - if (number_of_hard_break == 0) { - aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg); - number_of_hard_break = (edm_cfg & 0x7) + 1; - } - - aice_read_debug_reg(aice, NDS_EDM_SR_EDMSW, &edmsw); - /* clear matching bits (write-one-clear) */ - aice_write_debug_reg(aice, NDS_EDM_SR_EDMSW, edmsw); - match_bits = (edmsw >> 4) & 0xFF; - match_count = 0; - for (i = 0 ; i < number_of_hard_break ; i++) { - if (match_bits & (1 << i)) { - aice_read_debug_reg(aice, NDS_EDM_SR_BPA0 + i, address); - match_count++; - - /* If target hits multiple read/access watchpoint, - * select the first one. */ - aice_read_debug_reg(aice, NDS_EDM_SR_BPC0 + i, &bp_control); - if (0x3 == (bp_control & 0x3)) { - match_count = 1; - break; - } - } - } - - if (match_count > 1) { /* multiple hits */ - *address = 0; - return ERROR_OK; - } else if (match_count == 1) { - uint32_t val_pc; - uint32_t opcode; - struct nds32_instruction instruction; - struct watchpoint *wp; - bool hit; - - nds32_get_mapped_reg(nds32, PC, &val_pc); - - if ((reason == NDS32_DEBUG_DATA_ADDR_WATCHPOINT_NEXT_PRECISE) || - (reason == NDS32_DEBUG_DATA_VALUE_WATCHPOINT_NEXT_PRECISE)) { - if (edmsw & 0x4) /* check EDMSW.IS_16BIT */ - val_pc -= 2; - else - val_pc -= 4; - } - - nds32_read_opcode(nds32, val_pc, &opcode); - nds32_evaluate_opcode(nds32, opcode, val_pc, &instruction); - - LOG_DEBUG("PC: 0x%08" PRIx32 ", access start: 0x%08" PRIx32 ", end: 0x%08" PRIx32, - val_pc, instruction.access_start, instruction.access_end); - - /* check if multiple hits in the access range */ - uint32_t in_range_watch_count = 0; - for (wp = target->watchpoints; wp; wp = wp->next) { - if ((instruction.access_start <= wp->address) && - (wp->address < instruction.access_end)) - in_range_watch_count++; - } - if (in_range_watch_count > 1) { - /* Hit LSMW instruction. */ - *address = 0; - return ERROR_OK; - } - - /* dispel false match */ - hit = false; - for (wp = target->watchpoints; wp; wp = wp->next) { - if (((*address ^ wp->address) & (~wp->mask)) == 0) { - uint32_t watch_start; - uint32_t watch_end; - - watch_start = wp->address; - watch_end = wp->address + wp->length; - - if ((watch_end <= instruction.access_start) || - (instruction.access_end <= watch_start)) - continue; - - hit = true; - break; - } - } - - if (hit) - return ERROR_OK; - else - return ERROR_FAIL; - } else if (match_count == 0) { - /* global stop is precise exception */ - if ((reason == NDS32_DEBUG_LOAD_STORE_GLOBAL_STOP) && nds32->global_stop) { - /* parse instruction to get correct access address */ - uint32_t val_pc; - uint32_t opcode; - struct nds32_instruction instruction; - - nds32_get_mapped_reg(nds32, PC, &val_pc); - nds32_read_opcode(nds32, val_pc, &opcode); - nds32_evaluate_opcode(nds32, opcode, val_pc, &instruction); - - *address = instruction.access_start; - - return ERROR_OK; - } - } - - *address = 0xFFFFFFFF; - return ERROR_FAIL; -} - -void nds32_v3_common_register_callback(struct nds32_v3_common_callback *callback) -{ - v3_common_callback = callback; -} - -/** target_type functions: */ -/* target request support */ -int nds32_v3_target_request_data(struct target *target, - uint32_t size, uint8_t *buffer) -{ - /* AndesCore could use DTR register to communicate with OpenOCD - * to output messages - * Target data will be put in buffer - * The format of DTR is as follow - * DTR[31:16] => length, DTR[15:8] => size, DTR[7:0] => target_req_cmd - * target_req_cmd has three possible values: - * TARGET_REQ_TRACEMSG - * TARGET_REQ_DEBUGMSG - * TARGET_REQ_DEBUGCHAR - * if size == 0, target will call target_asciimsg(), - * else call target_hexmsg() - */ - LOG_WARNING("Not implemented: %s", __func__); - - return ERROR_OK; -} - -int nds32_v3_checksum_memory(struct target *target, - target_addr_t address, uint32_t count, uint32_t *checksum) -{ - LOG_WARNING("Not implemented: %s", __func__); - - return ERROR_FAIL; -} - -/** - * find out which watchpoint hits - * get exception address and compare the address to watchpoints - */ -int nds32_v3_hit_watchpoint(struct target *target, - struct watchpoint **hit_watchpoint) -{ - static struct watchpoint scan_all_watchpoint; - - uint32_t exception_address; - struct watchpoint *wp; - struct nds32 *nds32 = target_to_nds32(target); - - exception_address = nds32->watched_address; - - if (exception_address == 0xFFFFFFFF) - return ERROR_FAIL; - - if (exception_address == 0) { - scan_all_watchpoint.address = 0; - scan_all_watchpoint.rw = WPT_WRITE; - scan_all_watchpoint.next = 0; - scan_all_watchpoint.unique_id = 0x5CA8; - - *hit_watchpoint = &scan_all_watchpoint; - return ERROR_OK; - } - - for (wp = target->watchpoints; wp; wp = wp->next) { - if (((exception_address ^ wp->address) & (~wp->mask)) == 0) { - *hit_watchpoint = wp; - - return ERROR_OK; - } - } - - return ERROR_FAIL; -} - -int nds32_v3_target_create_common(struct target *target, struct nds32 *nds32) -{ - nds32->register_map = nds32_v3_register_mapping; - nds32->get_debug_reason = nds32_v3_get_debug_reason; - nds32->enter_debug_state = nds32_v3_debug_entry; - nds32->leave_debug_state = nds32_v3_leave_debug_state; - nds32->get_watched_address = nds32_v3_get_exception_address; - - /* Init target->arch_info in nds32_init_arch_info(). - * After this, user could use target_to_nds32() to get nds32 object */ - nds32_init_arch_info(target, nds32); - - return ERROR_OK; -} - -int nds32_v3_run_algorithm(struct target *target, - int num_mem_params, - struct mem_param *mem_params, - int num_reg_params, - struct reg_param *reg_params, - target_addr_t entry_point, - target_addr_t exit_point, - int timeout_ms, - void *arch_info) -{ - LOG_WARNING("Not implemented: %s", __func__); - - return ERROR_FAIL; -} - -int nds32_v3_read_buffer(struct target *target, target_addr_t address, - uint32_t size, uint8_t *buffer) -{ - struct nds32 *nds32 = target_to_nds32(target); - struct nds32_memory *memory = &(nds32->memory); - - if ((memory->access_channel == NDS_MEMORY_ACC_CPU) && - (target->state != TARGET_HALTED)) { - LOG_WARNING("target was not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - target_addr_t physical_address; - /* BUG: If access range crosses multiple pages, the translation will not correct - * for second page or so. */ - - /* When DEX is set to one, hardware will enforce the following behavior without - * modifying the corresponding control bits in PSW. - * - * Disable all interrupts - * Become superuser mode - * Turn off IT/DT - * Use MMU_CFG.DE as the data access endian - * Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted - * Disable audio special features - * Disable inline function call - * - * Because hardware will turn off IT/DT by default, it MUST translate virtual address - * to physical address. - */ - if (target->type->virt2phys(target, address, &physical_address) == ERROR_OK) - address = physical_address; - else - return ERROR_FAIL; - - int result; - struct aice_port_s *aice = target_to_aice(target); - /* give arbitrary initial value to avoid warning messages */ - enum nds_memory_access origin_access_channel = NDS_MEMORY_ACC_CPU; - - if (nds32->hit_syscall) { - /* Use bus mode to access memory during virtual hosting */ - origin_access_channel = memory->access_channel; - memory->access_channel = NDS_MEMORY_ACC_BUS; - aice_memory_access(aice, NDS_MEMORY_ACC_BUS); - } - - result = nds32_read_buffer(target, address, size, buffer); - - if (nds32->hit_syscall) { - /* Restore access_channel after virtual hosting */ - memory->access_channel = origin_access_channel; - aice_memory_access(aice, origin_access_channel); - } - - return result; -} - -int nds32_v3_write_buffer(struct target *target, target_addr_t address, - uint32_t size, const uint8_t *buffer) -{ - struct nds32 *nds32 = target_to_nds32(target); - struct nds32_memory *memory = &(nds32->memory); - - if ((memory->access_channel == NDS_MEMORY_ACC_CPU) && - (target->state != TARGET_HALTED)) { - LOG_WARNING("target was not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - target_addr_t physical_address; - /* BUG: If access range crosses multiple pages, the translation will not correct - * for second page or so. */ - - /* When DEX is set to one, hardware will enforce the following behavior without - * modifying the corresponding control bits in PSW. - * - * Disable all interrupts - * Become superuser mode - * Turn off IT/DT - * Use MMU_CFG.DE as the data access endian - * Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted - * Disable audio special features - * Disable inline function call - * - * Because hardware will turn off IT/DT by default, it MUST translate virtual address - * to physical address. - */ - if (target->type->virt2phys(target, address, &physical_address) == ERROR_OK) - address = physical_address; - else - return ERROR_FAIL; - - if (nds32->hit_syscall) { - struct aice_port_s *aice = target_to_aice(target); - enum nds_memory_access origin_access_channel; - origin_access_channel = memory->access_channel; - - /* If target has no cache, use BUS mode to access memory. */ - if ((memory->dcache.line_size == 0) - || (memory->dcache.enable == false)) { - /* There is no Dcache or Dcache is disabled. */ - memory->access_channel = NDS_MEMORY_ACC_BUS; - aice_memory_access(aice, NDS_MEMORY_ACC_BUS); - } - - int result; - result = nds32_gdb_fileio_write_memory(nds32, address, size, buffer); - - if (origin_access_channel == NDS_MEMORY_ACC_CPU) { - memory->access_channel = NDS_MEMORY_ACC_CPU; - aice_memory_access(aice, NDS_MEMORY_ACC_CPU); - } - - return result; - } - - return nds32_write_buffer(target, address, size, buffer); -} - -int nds32_v3_read_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) -{ - struct nds32 *nds32 = target_to_nds32(target); - struct nds32_memory *memory = &(nds32->memory); - - if ((memory->access_channel == NDS_MEMORY_ACC_CPU) && - (target->state != TARGET_HALTED)) { - LOG_WARNING("target was not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - target_addr_t physical_address; - /* BUG: If access range crosses multiple pages, the translation will not correct - * for second page or so. */ - - /* When DEX is set to one, hardware will enforce the following behavior without - * modifying the corresponding control bits in PSW. - * - * Disable all interrupts - * Become superuser mode - * Turn off IT/DT - * Use MMU_CFG.DE as the data access endian - * Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted - * Disable audio special features - * Disable inline function call - * - * Because hardware will turn off IT/DT by default, it MUST translate virtual address - * to physical address. - */ - if (target->type->virt2phys(target, address, &physical_address) == ERROR_OK) - address = physical_address; - else - return ERROR_FAIL; - - struct aice_port_s *aice = target_to_aice(target); - /* give arbitrary initial value to avoid warning messages */ - enum nds_memory_access origin_access_channel = NDS_MEMORY_ACC_CPU; - int result; - - if (nds32->hit_syscall) { - /* Use bus mode to access memory during virtual hosting */ - origin_access_channel = memory->access_channel; - memory->access_channel = NDS_MEMORY_ACC_BUS; - aice_memory_access(aice, NDS_MEMORY_ACC_BUS); - } - - result = nds32_read_memory(target, address, size, count, buffer); - - if (nds32->hit_syscall) { - /* Restore access_channel after virtual hosting */ - memory->access_channel = origin_access_channel; - aice_memory_access(aice, origin_access_channel); - } - - return result; -} - -int nds32_v3_write_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer) -{ - struct nds32 *nds32 = target_to_nds32(target); - struct nds32_memory *memory = &(nds32->memory); - - if ((memory->access_channel == NDS_MEMORY_ACC_CPU) && - (target->state != TARGET_HALTED)) { - LOG_WARNING("target was not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - target_addr_t physical_address; - /* BUG: If access range crosses multiple pages, the translation will not correct - * for second page or so. */ - - /* When DEX is set to one, hardware will enforce the following behavior without - * modifying the corresponding control bits in PSW. - * - * Disable all interrupts - * Become superuser mode - * Turn off IT/DT - * Use MMU_CFG.DE as the data access endian - * Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted - * Disable audio special features - * Disable inline function call - * - * Because hardware will turn off IT/DT by default, it MUST translate virtual address - * to physical address. - */ - if (target->type->virt2phys(target, address, &physical_address) == ERROR_OK) - address = physical_address; - else - return ERROR_FAIL; - - return nds32_write_memory(target, address, size, count, buffer); -} - -int nds32_v3_init_target(struct command_context *cmd_ctx, - struct target *target) -{ - /* Initialize anything we can set up without talking to the target */ - struct nds32 *nds32 = target_to_nds32(target); - - nds32_init(nds32); - - target->fileio_info = malloc(sizeof(struct gdb_fileio_info)); - target->fileio_info->identifier = NULL; - - return ERROR_OK; -} diff --git a/src/target/nds32_v3_common.h b/src/target/nds32_v3_common.h deleted file mode 100644 index 23393e55d2..0000000000 --- a/src/target/nds32_v3_common.h +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_TARGET_NDS32_V3_COMMON_H -#define OPENOCD_TARGET_NDS32_V3_COMMON_H - -#include "target.h" - -struct nds32_v3_common_callback { - int (*check_interrupt_stack)(struct nds32 *nds32); - int (*restore_interrupt_stack)(struct nds32 *nds32); - int (*activate_hardware_breakpoint)(struct target *target); - int (*activate_hardware_watchpoint)(struct target *target); - int (*deactivate_hardware_breakpoint)(struct target *target); - int (*deactivate_hardware_watchpoint)(struct target *target); -}; - -void nds32_v3_common_register_callback(struct nds32_v3_common_callback *callback); -int nds32_v3_target_request_data(struct target *target, - uint32_t size, uint8_t *buffer); -int nds32_v3_checksum_memory(struct target *target, - target_addr_t address, uint32_t count, uint32_t *checksum); -int nds32_v3_hit_watchpoint(struct target *target, - struct watchpoint **hit_watchpoint); -int nds32_v3_target_create_common(struct target *target, struct nds32 *nds32); -int nds32_v3_run_algorithm(struct target *target, - int num_mem_params, - struct mem_param *mem_params, - int num_reg_params, - struct reg_param *reg_params, - target_addr_t entry_point, - target_addr_t exit_point, - int timeout_ms, - void *arch_info); -int nds32_v3_read_buffer(struct target *target, target_addr_t address, - uint32_t size, uint8_t *buffer); -int nds32_v3_write_buffer(struct target *target, target_addr_t address, - uint32_t size, const uint8_t *buffer); -int nds32_v3_read_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer); -int nds32_v3_write_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer); -int nds32_v3_init_target(struct command_context *cmd_ctx, - struct target *target); - -#endif /* OPENOCD_TARGET_NDS32_V3_COMMON_H */ diff --git a/src/target/nds32_v3m.c b/src/target/nds32_v3m.c deleted file mode 100644 index ffd646f33e..0000000000 --- a/src/target/nds32_v3m.c +++ /dev/null @@ -1,506 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "breakpoints.h" -#include "nds32_cmd.h" -#include "nds32_aice.h" -#include "nds32_v3m.h" -#include "nds32_v3_common.h" - -static int nds32_v3m_activate_hardware_breakpoint(struct target *target) -{ - struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target); - struct aice_port_s *aice = target_to_aice(target); - struct breakpoint *bp; - unsigned brp_num = nds32_v3m->n_hbr - 1; - - for (bp = target->breakpoints; bp; bp = bp->next) { - if (bp->type == BKPT_SOFT) { - /* already set at nds32_v3m_add_breakpoint() */ - continue; - } else if (bp->type == BKPT_HARD) { - /* set address */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + brp_num, bp->address); - /* set mask */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + brp_num, 0); - - if (nds32_v3m->nds32.memory.address_translation) - /* enable breakpoint (virtual address) */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x2); - else - /* enable breakpoint (physical address) */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0xA); - - LOG_DEBUG("Add hardware BP %u at %08" TARGET_PRIxADDR, brp_num, - bp->address); - - brp_num--; - } else { - return ERROR_FAIL; - } - } - - return ERROR_OK; -} - -static int nds32_v3m_deactivate_hardware_breakpoint(struct target *target) -{ - struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target); - struct aice_port_s *aice = target_to_aice(target); - struct breakpoint *bp; - unsigned brp_num = nds32_v3m->n_hbr - 1; - - for (bp = target->breakpoints; bp; bp = bp->next) { - if (bp->type == BKPT_SOFT) - continue; - else if (bp->type == BKPT_HARD) - /* disable breakpoint */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x0); - else - return ERROR_FAIL; - - LOG_DEBUG("Remove hardware BP %u at %08" TARGET_PRIxADDR, brp_num, - bp->address); - - brp_num--; - } - - return ERROR_OK; -} - -static int nds32_v3m_activate_hardware_watchpoint(struct target *target) -{ - struct aice_port_s *aice = target_to_aice(target); - struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target); - struct watchpoint *wp; - int32_t wp_num = 0; - uint32_t wp_config = 0; - bool ld_stop, st_stop; - - if (nds32_v3m->nds32.global_stop) - ld_stop = st_stop = false; - - for (wp = target->watchpoints; wp; wp = wp->next) { - - if (wp_num < nds32_v3m->used_n_wp) { - wp->mask = wp->length - 1; - if ((wp->address % wp->length) != 0) - wp->mask = (wp->mask << 1) + 1; - - if (wp->rw == WPT_READ) - wp_config = 0x3; - else if (wp->rw == WPT_WRITE) - wp_config = 0x5; - else if (wp->rw == WPT_ACCESS) - wp_config = 0x7; - - /* set/unset physical address bit of BPCn according to PSW.DT */ - if (nds32_v3m->nds32.memory.address_translation == false) - wp_config |= 0x8; - - /* set address */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num, - wp->address - (wp->address % wp->length)); - /* set mask */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask); - /* enable watchpoint */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config); - - LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR - " mask %08" PRIx32, wp_num, wp->address, wp->mask); - - wp_num++; - } else if (nds32_v3m->nds32.global_stop) { - if (wp->rw == WPT_READ) - ld_stop = true; - else if (wp->rw == WPT_WRITE) - st_stop = true; - else if (wp->rw == WPT_ACCESS) - ld_stop = st_stop = true; - } - } - - if (nds32_v3m->nds32.global_stop) { - uint32_t edm_ctl; - aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl); - if (ld_stop) - edm_ctl |= 0x10; - if (st_stop) - edm_ctl |= 0x20; - aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl); - } - - return ERROR_OK; -} - -static int nds32_v3m_deactivate_hardware_watchpoint(struct target *target) -{ - struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target); - struct aice_port_s *aice = target_to_aice(target); - struct watchpoint *wp; - int32_t wp_num = 0; - bool clean_global_stop = false; - - for (wp = target->watchpoints; wp; wp = wp->next) { - - if (wp_num < nds32_v3m->used_n_wp) { - /* disable watchpoint */ - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0); - - LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR - " mask %08" PRIx32, wp_num, wp->address, wp->mask); - wp_num++; - } else if (nds32_v3m->nds32.global_stop) { - clean_global_stop = true; - } - } - - if (clean_global_stop) { - uint32_t edm_ctl; - aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl); - edm_ctl = edm_ctl & (~0x30); - aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl); - } - - return ERROR_OK; -} - -static int nds32_v3m_check_interrupt_stack(struct nds32 *nds32) -{ - uint32_t val_ir0; - uint32_t value; - - /* Save interrupt level */ - nds32_get_mapped_reg(nds32, IR0, &val_ir0); - nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3; - - if (nds32_reach_max_interrupt_level(nds32)) - LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32 ". -->", - nds32->current_interrupt_level); - - /* backup $ir6 to avoid suppressed exception overwrite */ - nds32_get_mapped_reg(nds32, IR6, &value); - - return ERROR_OK; -} - -static int nds32_v3m_restore_interrupt_stack(struct nds32 *nds32) -{ - uint32_t value; - - /* get backup value from cache */ - /* then set back to make the register dirty */ - nds32_get_mapped_reg(nds32, IR0, &value); - nds32_set_mapped_reg(nds32, IR0, value); - - nds32_get_mapped_reg(nds32, IR6, &value); - nds32_set_mapped_reg(nds32, IR6, value); - - return ERROR_OK; -} - -static int nds32_v3m_deassert_reset(struct target *target) -{ - int retval; - - CHECK_RETVAL(nds32_poll(target)); - - if (target->state != TARGET_HALTED) { - /* reset only */ - LOG_WARNING("%s: ran after reset and before halt ...", - target_name(target)); - retval = target_halt(target); - if (retval != ERROR_OK) - return retval; - - } - - return ERROR_OK; -} - -static int nds32_v3m_add_breakpoint(struct target *target, - struct breakpoint *breakpoint) -{ - struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target); - struct nds32 *nds32 = &(nds32_v3m->nds32); - int result; - - if (breakpoint->type == BKPT_HARD) { - /* check hardware resource */ - if (nds32_v3m->next_hbr_index < nds32_v3m->next_hwp_index) { - LOG_WARNING("<-- TARGET WARNING! Insert too many " - "hardware breakpoints/watchpoints! " - "The limit of combined hardware " - "breakpoints/watchpoints is %" PRId32 ". -->", - nds32_v3m->n_hbr); - LOG_WARNING("<-- TARGET STATUS: Inserted number of " - "hardware breakpoint: %" PRId32 ", hardware " - "watchpoints: %" PRId32 ". -->", - nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1, - nds32_v3m->used_n_wp); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - /* update next place to put hardware breakpoint */ - nds32_v3m->next_hbr_index--; - - /* hardware breakpoint insertion occurs before 'continue' actually */ - return ERROR_OK; - } else if (breakpoint->type == BKPT_SOFT) { - result = nds32_add_software_breakpoint(target, breakpoint); - if (result != ERROR_OK) { - /* auto convert to hardware breakpoint if failed */ - if (nds32->auto_convert_hw_bp) { - /* convert to hardware breakpoint */ - breakpoint->type = BKPT_HARD; - - return nds32_v3m_add_breakpoint(target, breakpoint); - } - } - - return result; - } else /* unrecognized breakpoint type */ - return ERROR_FAIL; - - return ERROR_OK; -} - -static int nds32_v3m_remove_breakpoint(struct target *target, - struct breakpoint *breakpoint) -{ - struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target); - - if (breakpoint->type == BKPT_HARD) { - if (nds32_v3m->next_hbr_index >= nds32_v3m->n_hbr - 1) - return ERROR_FAIL; - - /* update next place to put hardware breakpoint */ - nds32_v3m->next_hbr_index++; - - /* hardware breakpoint removal occurs after 'halted' actually */ - return ERROR_OK; - } else if (breakpoint->type == BKPT_SOFT) { - return nds32_remove_software_breakpoint(target, breakpoint); - } else /* unrecognized breakpoint type */ - return ERROR_FAIL; - - return ERROR_OK; -} - -static int nds32_v3m_add_watchpoint(struct target *target, - struct watchpoint *watchpoint) -{ - struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target); - - /* check hardware resource */ - if (nds32_v3m->next_hwp_index >= nds32_v3m->n_hwp) { - /* No hardware resource */ - if (nds32_v3m->nds32.global_stop) { - LOG_WARNING("<-- TARGET WARNING! The number of " - "watchpoints exceeds the hardware " - "resources. Stop at every load/store " - "instruction to check for watchpoint matches. -->"); - return ERROR_OK; - } - - LOG_WARNING("<-- TARGET WARNING! Insert too many hardware " - "watchpoints! The limit of hardware watchpoints " - "is %" PRId32 ". -->", nds32_v3m->n_hwp); - LOG_WARNING("<-- TARGET STATUS: Inserted number of " - "hardware watchpoint: %" PRId32 ". -->", - nds32_v3m->used_n_wp); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - if (nds32_v3m->next_hwp_index > nds32_v3m->next_hbr_index) { - /* No hardware resource */ - if (nds32_v3m->nds32.global_stop) { - LOG_WARNING("<-- TARGET WARNING! The number of " - "watchpoints exceeds the hardware " - "resources. Stop at every load/store " - "instruction to check for watchpoint matches. -->"); - return ERROR_OK; - } - - LOG_WARNING("<-- TARGET WARNING! Insert too many hardware " - "breakpoints/watchpoints! The limit of combined " - "hardware breakpoints/watchpoints is %" PRId32 ". -->", - nds32_v3m->n_hbr); - LOG_WARNING("<-- TARGET STATUS: Inserted number of " - "hardware breakpoint: %" PRId32 ", hardware " - "watchpoints: %" PRId32 ". -->", - nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1, - nds32_v3m->used_n_wp); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - /* update next place to put hardware watchpoint */ - nds32_v3m->next_hwp_index++; - nds32_v3m->used_n_wp++; - - return ERROR_OK; -} - -static int nds32_v3m_remove_watchpoint(struct target *target, - struct watchpoint *watchpoint) -{ - struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target); - - if (nds32_v3m->next_hwp_index <= 0) { - if (nds32_v3m->nds32.global_stop) - return ERROR_OK; - - return ERROR_FAIL; - } - - /* update next place to put hardware watchpoint */ - nds32_v3m->next_hwp_index--; - nds32_v3m->used_n_wp--; - - return ERROR_OK; -} - -static struct nds32_v3_common_callback nds32_v3m_common_callback = { - .check_interrupt_stack = nds32_v3m_check_interrupt_stack, - .restore_interrupt_stack = nds32_v3m_restore_interrupt_stack, - .activate_hardware_breakpoint = nds32_v3m_activate_hardware_breakpoint, - .activate_hardware_watchpoint = nds32_v3m_activate_hardware_watchpoint, - .deactivate_hardware_breakpoint = nds32_v3m_deactivate_hardware_breakpoint, - .deactivate_hardware_watchpoint = nds32_v3m_deactivate_hardware_watchpoint, -}; - -static int nds32_v3m_target_create(struct target *target, Jim_Interp *interp) -{ - struct nds32_v3m_common *nds32_v3m; - - nds32_v3m = calloc(1, sizeof(*nds32_v3m)); - if (!nds32_v3m) - return ERROR_FAIL; - - nds32_v3_common_register_callback(&nds32_v3m_common_callback); - nds32_v3_target_create_common(target, &(nds32_v3m->nds32)); - - return ERROR_OK; -} - -/* talk to the target and set things up */ -static int nds32_v3m_examine(struct target *target) -{ - struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target); - struct nds32 *nds32 = &(nds32_v3m->nds32); - struct aice_port_s *aice = target_to_aice(target); - - if (!target_was_examined(target)) { - CHECK_RETVAL(nds32_edm_config(nds32)); - - if (nds32->reset_halt_as_examine) - CHECK_RETVAL(nds32_reset_halt(nds32)); - } - - uint32_t edm_cfg; - aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg); - - /* get the number of hardware breakpoints */ - nds32_v3m->n_hbr = (edm_cfg & 0x7) + 1; - nds32_v3m->used_n_wp = 0; - - /* get the number of hardware watchpoints */ - /* If the WP field is hardwired to zero, it means this is a - * simple breakpoint. Otherwise, if the WP field is writable - * then it means this is a regular watchpoints. */ - nds32_v3m->n_hwp = 0; - for (int32_t i = 0 ; i < nds32_v3m->n_hbr ; i++) { - /** check the hardware breakpoint is simple or not */ - uint32_t tmp_value; - aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + i, 0x1); - aice_read_debug_reg(aice, NDS_EDM_SR_BPC0 + i, &tmp_value); - - if (tmp_value) - nds32_v3m->n_hwp++; - } - /* hardware breakpoint is inserted from high index to low index */ - nds32_v3m->next_hbr_index = nds32_v3m->n_hbr - 1; - /* hardware watchpoint is inserted from low index to high index */ - nds32_v3m->next_hwp_index = 0; - - LOG_INFO("%s: total hardware breakpoint %" PRId32 " (simple breakpoint %" PRId32 ")", - target_name(target), nds32_v3m->n_hbr, nds32_v3m->n_hbr - nds32_v3m->n_hwp); - LOG_INFO("%s: total hardware watchpoint %" PRId32, target_name(target), nds32_v3m->n_hwp); - - nds32->target->state = TARGET_RUNNING; - nds32->target->debug_reason = DBG_REASON_NOTHALTED; - - target_set_examined(target); - - return ERROR_OK; -} - -/** Holds methods for NDS32 V3m targets. */ -struct target_type nds32_v3m_target = { - .name = "nds32_v3m", - - .poll = nds32_poll, - .arch_state = nds32_arch_state, - - .target_request_data = nds32_v3_target_request_data, - - .halt = nds32_halt, - .resume = nds32_resume, - .step = nds32_step, - - .assert_reset = nds32_assert_reset, - .deassert_reset = nds32_v3m_deassert_reset, - - /* register access */ - .get_gdb_reg_list = nds32_get_gdb_reg_list, - - /* memory access */ - .read_buffer = nds32_v3_read_buffer, - .write_buffer = nds32_v3_write_buffer, - .read_memory = nds32_v3_read_memory, - .write_memory = nds32_v3_write_memory, - - .checksum_memory = nds32_v3_checksum_memory, - - /* breakpoint/watchpoint */ - .add_breakpoint = nds32_v3m_add_breakpoint, - .remove_breakpoint = nds32_v3m_remove_breakpoint, - .add_watchpoint = nds32_v3m_add_watchpoint, - .remove_watchpoint = nds32_v3m_remove_watchpoint, - .hit_watchpoint = nds32_v3_hit_watchpoint, - - /* MMU */ - .mmu = nds32_mmu, - .virt2phys = nds32_virtual_to_physical, - .read_phys_memory = nds32_read_phys_memory, - .write_phys_memory = nds32_write_phys_memory, - - .run_algorithm = nds32_v3_run_algorithm, - - .commands = nds32_command_handlers, - .target_create = nds32_v3m_target_create, - .init_target = nds32_v3_init_target, - .examine = nds32_v3m_examine, - - .get_gdb_fileio_info = nds32_get_gdb_fileio_info, - .gdb_fileio_end = nds32_gdb_fileio_end, -}; diff --git a/src/target/nds32_v3m.h b/src/target/nds32_v3m.h deleted file mode 100644 index 1e7427c48b..0000000000 --- a/src/target/nds32_v3m.h +++ /dev/null @@ -1,51 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Andes Technology * - * Hsiangkai Wang <hkwang@andestech.com> * - * * - * 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/>. * - ***************************************************************************/ - -#ifndef OPENOCD_TARGET_NDS32_V3M_H -#define OPENOCD_TARGET_NDS32_V3M_H - -#include "nds32.h" - -struct nds32_v3m_common { - struct nds32 nds32; - - /** number of hardware breakpoints */ - int32_t n_hbr; - - /** number of hardware watchpoints */ - int32_t n_hwp; - - /** number of used hardware watchpoints */ - int32_t used_n_wp; - - /** next hardware breakpoint index */ - /** for simple breakpoints, hardware breakpoints are inserted - * from high index to low index */ - int32_t next_hbr_index; - - /** next hardware watchpoint index */ - /** increase from low index to high index */ - int32_t next_hwp_index; -}; - -static inline struct nds32_v3m_common *target_to_nds32_v3m(struct target *target) -{ - return container_of(target->arch_info, struct nds32_v3m_common, nds32); -} - -#endif /* OPENOCD_TARGET_NDS32_V3M_H */ diff --git a/src/target/openrisc/Makefile.am b/src/target/openrisc/Makefile.am index 5a2549a51d..b9c0f83ea8 100644 --- a/src/target/openrisc/Makefile.am +++ b/src/target/openrisc/Makefile.am @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libopenrisc.la %C%_libopenrisc_la_SOURCES = \ %D%/or1k.c \ diff --git a/src/target/openrisc/jsp_server.c b/src/target/openrisc/jsp_server.c index 54c9694243..185a506c45 100644 --- a/src/target/openrisc/jsp_server.c +++ b/src/target/openrisc/jsp_server.c @@ -1,21 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2014 by Franck Jullien * * franck.jullien@gmail.com * * * * Based on ./src/server/telnet_server.c * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/openrisc/jsp_server.h b/src/target/openrisc/jsp_server.h index e5cfaa8b46..a522fa8da3 100644 --- a/src/target/openrisc/jsp_server.h +++ b/src/target/openrisc/jsp_server.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + #ifndef OPENOCD_TARGET_OPENRISC_JSP_SERVER_H #define OPENOCD_TARGET_OPENRISC_JSP_SERVER_H diff --git a/src/target/openrisc/or1k.c b/src/target/openrisc/or1k.c index 77fa15d50c..8c38610805 100644 --- a/src/target/openrisc/or1k.c +++ b/src/target/openrisc/or1k.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2011 by Julius Baxter * * julius@opencores.org * @@ -8,19 +10,6 @@ * Copyright (C) 2013 by Franck Jullien * * elec4fun@gmail.com * * * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -800,7 +789,7 @@ static int or1k_resume_or_step(struct target *target, int current, address, step ? "yes" : "no", handle_breakpoints ? "yes" : "no"); if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1037,7 +1026,7 @@ static int or1k_read_memory(struct target *target, target_addr_t address, LOG_DEBUG("Read memory at 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: 0x%08" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1064,7 +1053,7 @@ static int or1k_write_memory(struct target *target, target_addr_t address, LOG_DEBUG("Write memory at 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: 0x%08" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("Target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } diff --git a/src/target/openrisc/or1k.h b/src/target/openrisc/or1k.h index c456ccbe29..8f76a0612e 100644 --- a/src/target/openrisc/or1k.h +++ b/src/target/openrisc/or1k.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2011 by Julius Baxter * * julius@opencores.org * @@ -8,19 +10,6 @@ * Copyright (C) 2013 by Franck Jullien * * elec4fun@gmail.com * * * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_OPENRISC_OR1K_H diff --git a/src/target/openrisc/or1k_du.h b/src/target/openrisc/or1k_du.h index 9828b0d223..ae95376fa5 100644 --- a/src/target/openrisc/or1k_du.h +++ b/src/target/openrisc/or1k_du.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2013 Franck Jullien * * elec4fun@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_OPENRISC_OR1K_DU_H diff --git a/src/target/openrisc/or1k_du_adv.c b/src/target/openrisc/or1k_du_adv.c index 885fcb9c10..e4003a213d 100644 --- a/src/target/openrisc/or1k_du_adv.c +++ b/src/target/openrisc/or1k_du_adv.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2013-2014 by Franck Jullien * * elec4fun@gmail.com * @@ -9,19 +11,6 @@ * And the Mohor interface version of this file which is: * * Copyright (C) 2011 by Julius Baxter * * julius@opencores.org * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -33,8 +22,9 @@ #include "or1k_du.h" #include "jsp_server.h" -#include <target/target.h> +#include <helper/crc32.h> #include <jtag/jtag.h> +#include <target/target.h> #define JSP_BANNER "\n\r" \ "******************************\n\r" \ @@ -78,13 +68,6 @@ #define DBG_CPU_CR_STALL 0x01 #define DBG_CPU_CR_RESET 0x02 -/* Polynomial for the CRC calculation - * Yes, it's backwards. Yes, this is on purpose. - * The hardware is designed this way to save on logic and routing, - * and it's really all the same to us here. - */ -#define ADBG_CRC_POLY 0xedb88320 - /* These are for the internal registers in the Wishbone module * The first is the length of the index register, * the indexes of the various registers are defined after that. @@ -144,20 +127,6 @@ static struct or1k_du or1k_du_adv; static const char * const chain_name[] = {"WISHBONE", "CPU0", "CPU1", "JSP"}; -static uint32_t adbg_compute_crc(uint32_t crc, uint32_t data_in, - int length_bits) -{ - for (int i = 0; i < length_bits; i++) { - uint32_t d, c; - d = ((data_in >> i) & 0x1) ? 0xffffffff : 0; - c = (crc & 0x1) ? 0xffffffff : 0; - crc = crc >> 1; - crc = crc ^ ((d ^ c) & ADBG_CRC_POLY); - } - - return crc; -} - static int find_status_bit(void *_buf, int len) { int i = 0; @@ -533,9 +502,8 @@ static int adbg_wb_burst_read(struct or1k_jtag *jtag_info, int size, memcpy(data, in_buffer, total_size_bytes); memcpy(&crc_read, &in_buffer[total_size_bytes], 4); - uint32_t crc_calc = 0xffffffff; - for (int i = 0; i < total_size_bytes; i++) - crc_calc = adbg_compute_crc(crc_calc, data[i], 8); + uint32_t crc_calc = crc32_le(CRC32_POLY_LE, 0xffffffff, data, + total_size_bytes); if (crc_calc != crc_read) { LOG_WARNING("CRC ERROR! Computed 0x%08" PRIx32 ", read CRC 0x%08" PRIx32, crc_calc, crc_read); @@ -661,9 +629,8 @@ static int adbg_wb_burst_write(struct or1k_jtag *jtag_info, const uint8_t *data, field[0].out_value = &value; field[0].in_value = NULL; - uint32_t crc_calc = 0xffffffff; - for (int i = 0; i < (count * size); i++) - crc_calc = adbg_compute_crc(crc_calc, data[i], 8); + uint32_t crc_calc = crc32_le(CRC32_POLY_LE, 0xffffffff, data, + count * size); field[1].num_bits = count * size * 8; field[1].out_value = data; @@ -945,7 +912,7 @@ static int or1k_adv_jtag_write_memory(struct or1k_jtag *jtag_info, void *t = NULL; struct target *target = jtag_info->target; if ((target->endianness == TARGET_BIG_ENDIAN) && (size != 1)) { - t = malloc(count * size * sizeof(uint8_t)); + t = calloc(count * size, sizeof(uint8_t)); if (!t) { LOG_ERROR("Out of memory"); return ERROR_FAIL; @@ -958,6 +925,9 @@ static int or1k_adv_jtag_write_memory(struct or1k_jtag *jtag_info, case 2: buf_bswap16(t, buffer, size * count); break; + default: + free(t); + return ERROR_TARGET_FAILURE; } buffer = t; } diff --git a/src/target/openrisc/or1k_tap.h b/src/target/openrisc/or1k_tap.h index 2cf7da804a..e06a5e07ae 100644 --- a/src/target/openrisc/or1k_tap.h +++ b/src/target/openrisc/or1k_tap.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2012 by Franck Jullien * * elec4fun@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_OPENRISC_OR1K_TAP_H diff --git a/src/target/openrisc/or1k_tap_mohor.c b/src/target/openrisc/or1k_tap_mohor.c index 1415e321c4..0dedb3e754 100644 --- a/src/target/openrisc/or1k_tap_mohor.c +++ b/src/target/openrisc/or1k_tap_mohor.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2013 by Franck Jullien * * elec4fun@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/openrisc/or1k_tap_vjtag.c b/src/target/openrisc/or1k_tap_vjtag.c index 28366cf53d..783b4dbd1e 100644 --- a/src/target/openrisc/or1k_tap_vjtag.c +++ b/src/target/openrisc/or1k_tap_vjtag.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2013 by Franck Jullien * * elec4fun@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/openrisc/or1k_tap_xilinx_bscan.c b/src/target/openrisc/or1k_tap_xilinx_bscan.c index a77c65ef82..6b3df0e1e9 100644 --- a/src/target/openrisc/or1k_tap_xilinx_bscan.c +++ b/src/target/openrisc/or1k_tap_xilinx_bscan.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2013 by Sergio Chico * * sergio.chico@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/quark_d20xx.c b/src/target/quark_d20xx.c index 211245d7db..d63a42a6c0 100644 --- a/src/target/quark_d20xx.c +++ b/src/target/quark_d20xx.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright(c) 2015-2016 Intel Corporation. * * Jessica Gomez (jessica.gomez.hernandez@intel.com) * Ivan De Cesaris (ivan.de.cesaris@intel.com) * - * 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/>. - * * Contact Information: * Intel Corporation */ diff --git a/src/target/quark_x10xx.c b/src/target/quark_x10xx.c index 525d39a025..0daa642b85 100644 --- a/src/target/quark_x10xx.c +++ b/src/target/quark_x10xx.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright(c) 2013-2016 Intel Corporation. * @@ -7,19 +9,6 @@ * Julien Carreno (julien.carreno@intel.com) * Jeffrey Maxwell (jeffrey.r.maxwell@intel.com) * - * 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/>. - * * Contact Information: * Intel Corporation */ diff --git a/src/target/register.c b/src/target/register.c index 638747560c..e4f22f8e93 100644 --- a/src/target/register.c +++ b/src/target/register.c @@ -1,22 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -104,9 +93,8 @@ void register_unlink_cache(struct reg_cache **cache_p, const struct reg_cache *c /** Marks the contents of the register cache as invalid (and clean). */ void register_cache_invalidate(struct reg_cache *cache) { - struct reg *reg = cache->reg_list; - - for (unsigned int n = cache->num_regs; n != 0; n--, reg++) { + for (unsigned int n = 0; n < cache->num_regs; n++) { + struct reg *reg = &cache->reg_list[n]; if (!reg->exist) continue; reg->valid = false; diff --git a/src/target/register.h b/src/target/register.h index a7705f76e0..1e4f2e0889 100644 --- a/src/target/register.h +++ b/src/target/register.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_REGISTER_H diff --git a/src/target/riscv/Makefile.am b/src/target/riscv/Makefile.am index 83f1a8ca3e..7f25eca7bd 100644 --- a/src/target/riscv/Makefile.am +++ b/src/target/riscv/Makefile.am @@ -1,8 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libriscv.la %C%_libriscv_la_SOURCES = \ %D%/asm.h \ %D%/batch.h \ %D%/debug_defines.h \ + %D%/debug_reg_printer.h \ %D%/encoding.h \ %D%/gdb_regs.h \ %D%/opcodes.h \ @@ -13,4 +16,6 @@ noinst_LTLIBRARIES += %D%/libriscv.la %D%/riscv-011.c \ %D%/riscv-013.c \ %D%/riscv.c \ - %D%/riscv_semihosting.c + %D%/riscv_semihosting.c \ + %D%/debug_defines.c \ + %D%/debug_reg_printer.c diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index a3d68a91f3..faa92568b6 100644 --- a/src/target/riscv/batch.c +++ b/src/target/riscv/batch.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later #ifdef HAVE_CONFIG_H #include "config.h" @@ -7,66 +7,72 @@ #include "batch.h" #include "debug_defines.h" #include "riscv.h" - -#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) -#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) +#include "field_helpers.h" #define DTM_DMI_MAX_ADDRESS_LENGTH ((1<<DTM_DTMCS_ABITS_LENGTH)-1) #define DMI_SCAN_MAX_BIT_LENGTH (DTM_DMI_MAX_ADDRESS_LENGTH + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH) #define DMI_SCAN_BUF_SIZE (DIV_ROUND_UP(DMI_SCAN_MAX_BIT_LENGTH, 8)) +/* Reserve extra room in the batch (needed for the last NOP operation) */ +#define BATCH_RESERVED_SCANS 1 + static void dump_field(int idle, const struct scan_field *field); struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_t idle) { - scans += 4; + scans += BATCH_RESERVED_SCANS; struct riscv_batch *out = calloc(1, sizeof(*out)); - if (!out) - goto error0; + if (!out) { + LOG_ERROR("Failed to allocate struct riscv_batch"); + return NULL; + } + out->target = target; out->allocated_scans = scans; out->idle_count = idle; - out->data_out = malloc(sizeof(*out->data_out) * (scans) * DMI_SCAN_BUF_SIZE); + out->last_scan = RISCV_SCAN_TYPE_INVALID; + + out->data_out = NULL; + out->data_in = NULL; + out->fields = NULL; + out->bscan_ctxt = NULL; + out->read_keys = NULL; + + /* FIXME: There is potential for memory usage reduction. We could allocate + * smaller buffers than DMI_SCAN_BUF_SIZE (that is, buffers that correspond to + * the real DR scan length on the given target) */ + out->data_out = malloc(sizeof(*out->data_out) * scans * DMI_SCAN_BUF_SIZE); if (!out->data_out) { LOG_ERROR("Failed to allocate data_out in RISC-V batch."); - goto error1; + goto alloc_error; }; - out->data_in = malloc(sizeof(*out->data_in) * (scans) * DMI_SCAN_BUF_SIZE); + out->data_in = malloc(sizeof(*out->data_in) * scans * DMI_SCAN_BUF_SIZE); if (!out->data_in) { LOG_ERROR("Failed to allocate data_in in RISC-V batch."); - goto error2; + goto alloc_error; } - out->fields = malloc(sizeof(*out->fields) * (scans)); + out->fields = malloc(sizeof(*out->fields) * scans); if (!out->fields) { LOG_ERROR("Failed to allocate fields in RISC-V batch."); - goto error3; + goto alloc_error; } if (bscan_tunnel_ir_width != 0) { - out->bscan_ctxt = malloc(sizeof(*out->bscan_ctxt) * (scans)); + out->bscan_ctxt = malloc(sizeof(*out->bscan_ctxt) * scans); if (!out->bscan_ctxt) { LOG_ERROR("Failed to allocate bscan_ctxt in RISC-V batch."); - goto error4; + goto alloc_error; } } - out->last_scan = RISCV_SCAN_TYPE_INVALID; - out->read_keys = malloc(sizeof(*out->read_keys) * (scans)); + out->read_keys = malloc(sizeof(*out->read_keys) * scans); if (!out->read_keys) { LOG_ERROR("Failed to allocate read_keys in RISC-V batch."); - goto error5; + goto alloc_error; } + return out; -error5: - free(out->bscan_ctxt); -error4: - free(out->fields); -error3: - free(out->data_in); -error2: - free(out->data_out); -error1: - free(out); -error0: +alloc_error: + riscv_batch_free(out); return NULL; } @@ -82,13 +88,13 @@ void riscv_batch_free(struct riscv_batch *batch) bool riscv_batch_full(struct riscv_batch *batch) { - return batch->used_scans > (batch->allocated_scans - 4); + return riscv_batch_available_scans(batch) == 0; } int riscv_batch_run(struct riscv_batch *batch) { if (batch->used_scans == 0) { - LOG_DEBUG("Ignoring empty batch."); + LOG_TARGET_DEBUG(batch->target, "Ignoring empty batch."); return ERROR_OK; } @@ -96,7 +102,7 @@ int riscv_batch_run(struct riscv_batch *batch) for (size_t i = 0; i < batch->used_scans; ++i) { if (bscan_tunnel_ir_width != 0) - riscv_add_bscan_tunneled_scan(batch->target, batch->fields+i, batch->bscan_ctxt+i); + riscv_add_bscan_tunneled_scan(batch->target, batch->fields + i, batch->bscan_ctxt + i); else jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE); @@ -107,7 +113,7 @@ int riscv_batch_run(struct riscv_batch *batch) keep_alive(); if (jtag_execute_queue() != ERROR_OK) { - LOG_ERROR("Unable to execute JTAG queue"); + LOG_TARGET_ERROR(batch->target, "Unable to execute JTAG queue"); return ERROR_FAIL; } @@ -115,8 +121,10 @@ int riscv_batch_run(struct riscv_batch *batch) if (bscan_tunnel_ir_width != 0) { /* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */ - for (size_t i = 0; i < batch->used_scans; ++i) - buffer_shr((batch->fields + i)->in_value, DMI_SCAN_BUF_SIZE, 1); + for (size_t i = 0; i < batch->used_scans; ++i) { + if ((batch->fields + i)->in_value) + buffer_shr((batch->fields + i)->in_value, DMI_SCAN_BUF_SIZE, 1); + } } for (size_t i = 0; i < batch->used_scans; ++i) @@ -125,28 +133,33 @@ int riscv_batch_run(struct riscv_batch *batch) return ERROR_OK; } -void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data) +void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data, + bool read_back) { assert(batch->used_scans < batch->allocated_scans); struct scan_field *field = batch->fields + batch->used_scans; - field->num_bits = riscv_dmi_write_u64_bits(batch->target); + field->num_bits = riscv_get_dmi_scan_length(batch->target); field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE); - field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); - riscv_fill_dmi_write_u64(batch->target, (char *)field->out_value, address, data); - riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value); + riscv_fill_dm_write(batch->target, (char *)field->out_value, address, data); + if (read_back) { + field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); + riscv_fill_dm_nop(batch->target, (char *)field->in_value); + } else { + field->in_value = NULL; + } batch->last_scan = RISCV_SCAN_TYPE_WRITE; batch->used_scans++; } -size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address) +size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address) { assert(batch->used_scans < batch->allocated_scans); struct scan_field *field = batch->fields + batch->used_scans; - field->num_bits = riscv_dmi_write_u64_bits(batch->target); + field->num_bits = riscv_get_dmi_scan_length(batch->target); field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE); field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); - riscv_fill_dmi_read_u64(batch->target, (char *)field->out_value, address); - riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value); + riscv_fill_dm_read(batch->target, (char *)field->out_value, address); + riscv_fill_dm_nop(batch->target, (char *)field->in_value); batch->last_scan = RISCV_SCAN_TYPE_READ; batch->used_scans++; @@ -154,21 +167,21 @@ size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address) return batch->read_keys_used++; } -unsigned riscv_batch_get_dmi_read_op(struct riscv_batch *batch, size_t key) +unsigned int riscv_batch_get_dmi_read_op(const struct riscv_batch *batch, size_t key) { assert(key < batch->read_keys_used); size_t index = batch->read_keys[key]; - assert(index <= batch->used_scans); + assert(index < batch->used_scans); uint8_t *base = batch->data_in + DMI_SCAN_BUF_SIZE * index; /* extract "op" field from the DMI read result */ - return (unsigned)buf_get_u32(base, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); + return (unsigned int)buf_get_u32(base, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); } -uint32_t riscv_batch_get_dmi_read_data(struct riscv_batch *batch, size_t key) +uint32_t riscv_batch_get_dmi_read_data(const struct riscv_batch *batch, size_t key) { assert(key < batch->read_keys_used); size_t index = batch->read_keys[key]; - assert(index <= batch->used_scans); + assert(index < batch->used_scans); uint8_t *base = batch->data_in + DMI_SCAN_BUF_SIZE * index; /* extract "data" field from the DMI read result */ return buf_get_u32(base, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); @@ -178,16 +191,16 @@ void riscv_batch_add_nop(struct riscv_batch *batch) { assert(batch->used_scans < batch->allocated_scans); struct scan_field *field = batch->fields + batch->used_scans; - field->num_bits = riscv_dmi_write_u64_bits(batch->target); + field->num_bits = riscv_get_dmi_scan_length(batch->target); field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE); field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); - riscv_fill_dmi_nop_u64(batch->target, (char *)field->out_value); - riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value); + riscv_fill_dm_nop(batch->target, (char *)field->out_value); + riscv_fill_dm_nop(batch->target, (char *)field->in_value); batch->last_scan = RISCV_SCAN_TYPE_NOP; batch->used_scans++; } -void dump_field(int idle, const struct scan_field *field) +static void dump_field(int idle, const struct scan_field *field) { static const char * const op_string[] = {"-", "r", "w", "?"}; static const char * const status_string[] = {"+", "?", "F", "b"}; @@ -208,18 +221,31 @@ void dump_field(int idle, const struct scan_field *field) unsigned int in_address = in >> DTM_DMI_ADDRESS_OFFSET; log_printf_lf(LOG_LVL_DEBUG, - __FILE__, __LINE__, __PRETTY_FUNCTION__, + __FILE__, __LINE__, __func__, "%db %s %08x @%02x -> %s %08x @%02x; %di", field->num_bits, op_string[out_op], out_data, out_address, status_string[in_op], in_data, in_address, idle); } else { log_printf_lf(LOG_LVL_DEBUG, - __FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %s %08x @%02x -> ?; %di", + __FILE__, __LINE__, __func__, "%db %s %08x @%02x -> ?; %di", field->num_bits, op_string[out_op], out_data, out_address, idle); } } size_t riscv_batch_available_scans(struct riscv_batch *batch) { - return batch->allocated_scans - batch->used_scans - 4; + assert(batch->allocated_scans >= (batch->used_scans + BATCH_RESERVED_SCANS)); + return batch->allocated_scans - batch->used_scans - BATCH_RESERVED_SCANS; +} + +bool riscv_batch_dmi_busy_encountered(const struct riscv_batch *batch) +{ + if (batch->used_scans == 0) + /* Empty batch */ + return false; + + assert(batch->last_scan == RISCV_SCAN_TYPE_NOP); + const struct scan_field *field = batch->fields + batch->used_scans - 1; + const uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits); + return get_field(in, DTM_DMI_OP) == DTM_DMI_OP_BUSY; } diff --git a/src/target/riscv/batch.h b/src/target/riscv/batch.h index 9c42ba81ea..839e13e827 100644 --- a/src/target/riscv/batch.h +++ b/src/target/riscv/batch.h @@ -58,15 +58,16 @@ bool riscv_batch_full(struct riscv_batch *batch); /* Executes this scan batch. */ int riscv_batch_run(struct riscv_batch *batch); -/* Adds a DMI write to this batch. */ -void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data); +/* Adds a DM register write to this batch. */ +void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data, + bool read_back); -/* DMI reads must be handled in two parts: the first one schedules a read and +/* DM register reads must be handled in two parts: the first one schedules a read and * provides a key, the second one actually obtains the result of the read - * status (op) and the actual data. */ -size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address); -unsigned riscv_batch_get_dmi_read_op(struct riscv_batch *batch, size_t key); -uint32_t riscv_batch_get_dmi_read_data(struct riscv_batch *batch, size_t key); +size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address); +unsigned int riscv_batch_get_dmi_read_op(const struct riscv_batch *batch, size_t key); +uint32_t riscv_batch_get_dmi_read_data(const struct riscv_batch *batch, size_t key); /* Scans in a NOP. */ void riscv_batch_add_nop(struct riscv_batch *batch); @@ -74,4 +75,7 @@ void riscv_batch_add_nop(struct riscv_batch *batch); /* Returns the number of available scans. */ size_t riscv_batch_available_scans(struct riscv_batch *batch); +/* Return true iff the last scan in the batch returned DMI_OP_BUSY. */ +bool riscv_batch_dmi_busy_encountered(const struct riscv_batch *batch); + #endif diff --git a/src/target/riscv/debug_defines.c b/src/target/riscv/debug_defines.c new file mode 100644 index 0000000000..d514c6e033 --- /dev/null +++ b/src/target/riscv/debug_defines.c @@ -0,0 +1,3852 @@ +/* + * This file is auto-generated by running 'make debug_defines' in + * https://github.com/riscv/riscv-debug-spec/ (40b9a05) + */ + +#include "debug_defines.h" +#include <stddef.h> +#include <assert.h> +static riscv_debug_reg_field_list_t dtm_idcode_get_version(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "Version", + .lsb = 0x1c, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dtm_idcode_get_partnumber(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "PartNumber", + .lsb = 0xc, + .msb = 0x1b, + .values = NULL + }, + .get_next = dtm_idcode_get_version + }; + return result; +} + +static riscv_debug_reg_field_list_t dtm_idcode_get_manufid(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "ManufId", + .lsb = 1, + .msb = 0xb, + .values = NULL + }, + .get_next = dtm_idcode_get_partnumber + }; + return result; +} + +static riscv_debug_reg_field_list_t dtm_idcode_get_1(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "1", + .lsb = 0, + .msb = 0, + .values = NULL + }, + .get_next = dtm_idcode_get_manufid + }; + return result; +} + +static const char *dtm_dtmcs_errinfo_values[8] = { + [0] = "not_implemented", + [1] = "dmi_error", + [2] = "communication_error", + [3] = "device_error", + [4] = "unknown" +}; +static const char *dtm_dtmcs_version_values[16] = { + [0] = "0_11", + [1] = "1_0", + [15] = "custom" +}; +static riscv_debug_reg_field_list_t dtm_dtmcs_get_abits(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "abits", + .lsb = 4, + .msb = 9, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dtm_dtmcs_get_errinfo(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "errinfo", + .lsb = 0x12, + .msb = 0x14, + .values = dtm_dtmcs_errinfo_values + }, + .get_next = dtm_dtmcs_get_abits + }; + return result; +} + +static riscv_debug_reg_field_list_t dtm_dtmcs_get_dtmhardreset(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dtmhardreset", + .lsb = 0x11, + .msb = 0x11, + .values = NULL + }, + .get_next = dtm_dtmcs_get_errinfo + }; + return result; +} + +static riscv_debug_reg_field_list_t dtm_dtmcs_get_dmireset(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dmireset", + .lsb = 0x10, + .msb = 0x10, + .values = NULL + }, + .get_next = dtm_dtmcs_get_dtmhardreset + }; + return result; +} + +static riscv_debug_reg_field_list_t dtm_dtmcs_get_idle(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "idle", + .lsb = 0xc, + .msb = 0xe, + .values = NULL + }, + .get_next = dtm_dtmcs_get_dmireset + }; + return result; +} + +static riscv_debug_reg_field_list_t dtm_dtmcs_get_dmistat(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dmistat", + .lsb = 0xa, + .msb = 0xb, + .values = NULL + }, + .get_next = dtm_dtmcs_get_idle + }; + return result; +} + +static riscv_debug_reg_field_list_t dtm_dtmcs_get_version(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "version", + .lsb = 0, + .msb = 3, + .values = dtm_dtmcs_version_values + }, + .get_next = dtm_dtmcs_get_dmistat + }; + return result; +} + +static const char *dtm_dmi_op_values[4] = {}; +static riscv_debug_reg_field_list_t dtm_dmi_get_address(riscv_debug_reg_ctx_t context) +{ + assert(context.abits.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "address", + .lsb = 0x22, + .msb = (context.abits.value + 0x21), + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dtm_dmi_get_data(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "data", + .lsb = 2, + .msb = 0x21, + .values = NULL + }, + .get_next = dtm_dmi_get_address + }; + return result; +} + +static riscv_debug_reg_field_list_t dtm_dmi_get_op(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "op", + .lsb = 0, + .msb = 1, + .values = dtm_dmi_op_values + }, + .get_next = dtm_dmi_get_data + }; + return result; +} + + +static const char *csr_dcsr_debugver_values[16] = { + [0] = "none", + [4] = "1_0", + [15] = "custom" +}; +static const char *csr_dcsr_ebreakvs_values[2] = { + [0] = "exception", + [1] = "debug_mode" +}; +static const char *csr_dcsr_ebreakvu_values[2] = { + [0] = "exception", + [1] = "debug_mode" +}; +static const char *csr_dcsr_ebreakm_values[2] = { + [0] = "exception", + [1] = "debug_mode" +}; +static const char *csr_dcsr_ebreaks_values[2] = { + [0] = "exception", + [1] = "debug_mode" +}; +static const char *csr_dcsr_ebreaku_values[2] = { + [0] = "exception", + [1] = "debug_mode" +}; +static const char *csr_dcsr_stepie_values[2] = { + [0] = "interrupts_disabled", + [1] = "interrupts_enabled" +}; +static const char *csr_dcsr_stopcount_values[2] = { + [0] = "normal", + [1] = "freeze" +}; +static const char *csr_dcsr_stoptime_values[2] = { + [0] = "normal", + [1] = "freeze" +}; +static const char *csr_dcsr_cause_values[8] = { + [1] = "ebreak", + [2] = "trigger", + [3] = "haltreq", + [4] = "step", + [5] = "resethaltreq", + [6] = "group" +}; +static const char *csr_dcsr_mprven_values[2] = { + [0] = "disabled", + [1] = "enabled" +}; +static riscv_debug_reg_field_list_t csr_dcsr_get_stoptime(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "stoptime", + .lsb = 9, + .msb = 9, + .values = csr_dcsr_stoptime_values + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dcsr_get_cause(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "cause", + .lsb = 6, + .msb = 8, + .values = csr_dcsr_cause_values + }, + .get_next = csr_dcsr_get_stoptime + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dcsr_get_v(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "v", + .lsb = 5, + .msb = 5, + .values = NULL + }, + .get_next = csr_dcsr_get_cause + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dcsr_get_mprven(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "mprven", + .lsb = 4, + .msb = 4, + .values = csr_dcsr_mprven_values + }, + .get_next = csr_dcsr_get_v + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dcsr_get_nmip(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "nmip", + .lsb = 3, + .msb = 3, + .values = NULL + }, + .get_next = csr_dcsr_get_mprven + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dcsr_get_debugver(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "debugver", + .lsb = 0x1c, + .msb = 0x1f, + .values = csr_dcsr_debugver_values + }, + .get_next = csr_dcsr_get_nmip + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dcsr_get_step(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "step", + .lsb = 2, + .msb = 2, + .values = NULL + }, + .get_next = csr_dcsr_get_debugver + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dcsr_get_ebreakvs(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "ebreakvs", + .lsb = 0x11, + .msb = 0x11, + .values = csr_dcsr_ebreakvs_values + }, + .get_next = csr_dcsr_get_step + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dcsr_get_ebreakvu(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "ebreakvu", + .lsb = 0x10, + .msb = 0x10, + .values = csr_dcsr_ebreakvu_values + }, + .get_next = csr_dcsr_get_ebreakvs + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dcsr_get_ebreakm(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "ebreakm", + .lsb = 0xf, + .msb = 0xf, + .values = csr_dcsr_ebreakm_values + }, + .get_next = csr_dcsr_get_ebreakvu + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dcsr_get_ebreaks(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "ebreaks", + .lsb = 0xd, + .msb = 0xd, + .values = csr_dcsr_ebreaks_values + }, + .get_next = csr_dcsr_get_ebreakm + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dcsr_get_ebreaku(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "ebreaku", + .lsb = 0xc, + .msb = 0xc, + .values = csr_dcsr_ebreaku_values + }, + .get_next = csr_dcsr_get_ebreaks + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dcsr_get_stepie(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "stepie", + .lsb = 0xb, + .msb = 0xb, + .values = csr_dcsr_stepie_values + }, + .get_next = csr_dcsr_get_ebreaku + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dcsr_get_stopcount(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "stopcount", + .lsb = 0xa, + .msb = 0xa, + .values = csr_dcsr_stopcount_values + }, + .get_next = csr_dcsr_get_stepie + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dcsr_get_prv(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "prv", + .lsb = 0, + .msb = 1, + .values = NULL + }, + .get_next = csr_dcsr_get_stopcount + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dpc_get_dpc(riscv_debug_reg_ctx_t context) +{ + assert(context.DXLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dpc", + .lsb = 0, + .msb = (context.DXLEN.value + -1), + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dscratch0_get_dscratch0(riscv_debug_reg_ctx_t context) +{ + assert(context.DXLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dscratch0", + .lsb = 0, + .msb = (context.DXLEN.value + -1), + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_dscratch1_get_dscratch1(riscv_debug_reg_ctx_t context) +{ + assert(context.DXLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dscratch1", + .lsb = 0, + .msb = (context.DXLEN.value + -1), + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_tselect_get_index(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "index", + .lsb = 0, + .msb = (context.XLEN.value + -1), + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static const char *csr_tdata1_type_values[16] = { + [0] = "none", + [1] = "legacy", + [2] = "mcontrol", + [3] = "icount", + [4] = "itrigger", + [5] = "etrigger", + [6] = "mcontrol6", + [7] = "tmexttrigger", + [15] = "disabled" +}; +static const char *csr_tdata1_dmode_values[2] = { + [0] = "both", + [1] = "dmode" +}; +static riscv_debug_reg_field_list_t csr_tdata1_get_dmode(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dmode", + .lsb = (context.XLEN.value + -5), + .msb = (context.XLEN.value + -5), + .values = csr_tdata1_dmode_values + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_tdata1_get_type(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "type", + .lsb = (context.XLEN.value + -4), + .msb = (context.XLEN.value + -1), + .values = csr_tdata1_type_values + }, + .get_next = csr_tdata1_get_dmode + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_tdata1_get_data(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "data", + .lsb = 0, + .msb = (context.XLEN.value + -6), + .values = NULL + }, + .get_next = csr_tdata1_get_type + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_tdata2_get_data(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "data", + .lsb = 0, + .msb = (context.XLEN.value + -1), + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_tdata3_get_data(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "data", + .lsb = 0, + .msb = (context.XLEN.value + -1), + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static const char *csr_tinfo_version_values[256] = { + [0] = "0", + [1] = "1" +}; +static riscv_debug_reg_field_list_t csr_tinfo_get_version(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "version", + .lsb = 0x18, + .msb = 0x1f, + .values = csr_tinfo_version_values + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_tinfo_get_info(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "info", + .lsb = 0, + .msb = 0xf, + .values = NULL + }, + .get_next = csr_tinfo_get_version + }; + return result; +} + +static const char *csr_tcontrol_mte_values[2] = { + [0] = "disabled", + [1] = "enabled" +}; +static riscv_debug_reg_field_list_t csr_tcontrol_get_mpte(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "mpte", + .lsb = 7, + .msb = 7, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_tcontrol_get_mte(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "mte", + .lsb = 3, + .msb = 3, + .values = csr_tcontrol_mte_values + }, + .get_next = csr_tcontrol_get_mpte + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_scontext_get_data(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "data", + .lsb = 0, + .msb = (context.XLEN.value + -1), + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontext_get_hcontext(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hcontext", + .lsb = 0, + .msb = (context.XLEN.value + -1), + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static const char *csr_mcontrol_select_values[2] = { + [0] = "address", + [1] = "data" +}; +static const char *csr_mcontrol_timing_values[2] = { + [0] = "before", + [1] = "after" +}; +static const char *csr_mcontrol_sizelo_values[4] = {}; +static const char *csr_mcontrol_action_values[16] = { + [0] = "breakpoint", + [1] = "debug_mode", + [2] = "trace_on", + [3] = "trace_off", + [4] = "trace_notify", + [8] = "external0", + [9] = "external1" +}; +static const char *csr_mcontrol_chain_values[2] = { + [0] = "disabled", + [1] = "enabled" +}; +static const char *csr_mcontrol_match_values[16] = { + [0] = "equal", + [1] = "napot", + [2] = "ge", + [3] = "lt", + [4] = "mask_low", + [5] = "mask_high", + [8] = "not_equal", + [9] = "not_napot", + [12] = "not_mask_low", + [13] = "not_mask_high" +}; +static riscv_debug_reg_field_list_t csr_mcontrol_get_dmode(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dmode", + .lsb = (context.XLEN.value + -5), + .msb = (context.XLEN.value + -5), + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_type(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "type", + .lsb = (context.XLEN.value + -4), + .msb = (context.XLEN.value + -1), + .values = NULL + }, + .get_next = csr_mcontrol_get_dmode + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_maskmax(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "maskmax", + .lsb = (context.XLEN.value + -0xb), + .msb = (context.XLEN.value + -6), + .values = NULL + }, + .get_next = csr_mcontrol_get_type + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_match(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "match", + .lsb = 7, + .msb = 0xa, + .values = csr_mcontrol_match_values + }, + .get_next = csr_mcontrol_get_maskmax + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_m(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "m", + .lsb = 6, + .msb = 6, + .values = NULL + }, + .get_next = csr_mcontrol_get_match + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_s(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "s", + .lsb = 4, + .msb = 4, + .values = NULL + }, + .get_next = csr_mcontrol_get_m + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_u(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "u", + .lsb = 3, + .msb = 3, + .values = NULL + }, + .get_next = csr_mcontrol_get_s + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_sizehi(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sizehi", + .lsb = 0x15, + .msb = 0x16, + .values = NULL + }, + .get_next = csr_mcontrol_get_u + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_hit(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hit", + .lsb = 0x14, + .msb = 0x14, + .values = NULL + }, + .get_next = csr_mcontrol_get_sizehi + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_execute(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "execute", + .lsb = 2, + .msb = 2, + .values = NULL + }, + .get_next = csr_mcontrol_get_hit + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_select(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "select", + .lsb = 0x13, + .msb = 0x13, + .values = csr_mcontrol_select_values + }, + .get_next = csr_mcontrol_get_execute + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_timing(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "timing", + .lsb = 0x12, + .msb = 0x12, + .values = csr_mcontrol_timing_values + }, + .get_next = csr_mcontrol_get_select + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_sizelo(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sizelo", + .lsb = 0x10, + .msb = 0x11, + .values = csr_mcontrol_sizelo_values + }, + .get_next = csr_mcontrol_get_timing + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_action(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "action", + .lsb = 0xc, + .msb = 0xf, + .values = csr_mcontrol_action_values + }, + .get_next = csr_mcontrol_get_sizelo + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_chain(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "chain", + .lsb = 0xb, + .msb = 0xb, + .values = csr_mcontrol_chain_values + }, + .get_next = csr_mcontrol_get_action + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_store(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "store", + .lsb = 1, + .msb = 1, + .values = NULL + }, + .get_next = csr_mcontrol_get_chain + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol_get_load(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "load", + .lsb = 0, + .msb = 0, + .values = NULL + }, + .get_next = csr_mcontrol_get_store + }; + return result; +} + +static const char *csr_mcontrol6_uncertain_values[2] = { + [0] = "certain", + [1] = "uncertain" +}; +static const char *csr_mcontrol6_hit0_values[2] = {}; +static const char *csr_mcontrol6_select_values[2] = { + [0] = "address", + [1] = "data" +}; +static const char *csr_mcontrol6_size_values[8] = { + [0] = "any", + [1] = "8bit", + [2] = "16bit", + [3] = "32bit", + [4] = "48bit", + [5] = "64bit", + [6] = "128bit" +}; +static const char *csr_mcontrol6_action_values[16] = { + [0] = "breakpoint", + [1] = "debug_mode", + [2] = "trace_on", + [3] = "trace_off", + [4] = "trace_notify", + [8] = "external0", + [9] = "external1" +}; +static const char *csr_mcontrol6_chain_values[2] = { + [0] = "disabled", + [1] = "enabled" +}; +static const char *csr_mcontrol6_match_values[16] = { + [0] = "equal", + [1] = "napot", + [2] = "ge", + [3] = "lt", + [4] = "mask_low", + [5] = "mask_high", + [8] = "not_equal", + [9] = "not_napot", + [12] = "not_mask_low", + [13] = "not_mask_high" +}; +static const char *csr_mcontrol6_uncertainen_values[2] = { + [0] = "disabled", + [1] = "enabled" +}; +static riscv_debug_reg_field_list_t csr_mcontrol6_get_dmode(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dmode", + .lsb = (context.XLEN.value + -5), + .msb = (context.XLEN.value + -5), + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_type(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "type", + .lsb = (context.XLEN.value + -4), + .msb = (context.XLEN.value + -1), + .values = NULL + }, + .get_next = csr_mcontrol6_get_dmode + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_match(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "match", + .lsb = 7, + .msb = 0xa, + .values = csr_mcontrol6_match_values + }, + .get_next = csr_mcontrol6_get_type + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_m(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "m", + .lsb = 6, + .msb = 6, + .values = NULL + }, + .get_next = csr_mcontrol6_get_match + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_uncertainen(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "uncertainen", + .lsb = 5, + .msb = 5, + .values = csr_mcontrol6_uncertainen_values + }, + .get_next = csr_mcontrol6_get_m + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_s(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "s", + .lsb = 4, + .msb = 4, + .values = NULL + }, + .get_next = csr_mcontrol6_get_uncertainen + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_u(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "u", + .lsb = 3, + .msb = 3, + .values = NULL + }, + .get_next = csr_mcontrol6_get_s + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_uncertain(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "uncertain", + .lsb = 0x1a, + .msb = 0x1a, + .values = csr_mcontrol6_uncertain_values + }, + .get_next = csr_mcontrol6_get_u + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_hit1(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hit1", + .lsb = 0x19, + .msb = 0x19, + .values = NULL + }, + .get_next = csr_mcontrol6_get_uncertain + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_vs(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "vs", + .lsb = 0x18, + .msb = 0x18, + .values = NULL + }, + .get_next = csr_mcontrol6_get_hit1 + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_vu(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "vu", + .lsb = 0x17, + .msb = 0x17, + .values = NULL + }, + .get_next = csr_mcontrol6_get_vs + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_hit0(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hit0", + .lsb = 0x16, + .msb = 0x16, + .values = csr_mcontrol6_hit0_values + }, + .get_next = csr_mcontrol6_get_vu + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_select(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "select", + .lsb = 0x15, + .msb = 0x15, + .values = csr_mcontrol6_select_values + }, + .get_next = csr_mcontrol6_get_hit0 + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_execute(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "execute", + .lsb = 2, + .msb = 2, + .values = NULL + }, + .get_next = csr_mcontrol6_get_select + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_size(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "size", + .lsb = 0x10, + .msb = 0x12, + .values = csr_mcontrol6_size_values + }, + .get_next = csr_mcontrol6_get_execute + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_action(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "action", + .lsb = 0xc, + .msb = 0xf, + .values = csr_mcontrol6_action_values + }, + .get_next = csr_mcontrol6_get_size + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_chain(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "chain", + .lsb = 0xb, + .msb = 0xb, + .values = csr_mcontrol6_chain_values + }, + .get_next = csr_mcontrol6_get_action + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_store(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "store", + .lsb = 1, + .msb = 1, + .values = NULL + }, + .get_next = csr_mcontrol6_get_chain + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_mcontrol6_get_load(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "load", + .lsb = 0, + .msb = 0, + .values = NULL + }, + .get_next = csr_mcontrol6_get_store + }; + return result; +} + +static const char *csr_icount_action_values[64] = { + [0] = "breakpoint", + [1] = "debug_mode", + [2] = "trace_on", + [3] = "trace_off", + [4] = "trace_notify", + [8] = "external0", + [9] = "external1" +}; +static riscv_debug_reg_field_list_t csr_icount_get_dmode(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dmode", + .lsb = (context.XLEN.value + -5), + .msb = (context.XLEN.value + -5), + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_icount_get_type(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "type", + .lsb = (context.XLEN.value + -4), + .msb = (context.XLEN.value + -1), + .values = NULL + }, + .get_next = csr_icount_get_dmode + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_icount_get_m(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "m", + .lsb = 9, + .msb = 9, + .values = NULL + }, + .get_next = csr_icount_get_type + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_icount_get_pending(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "pending", + .lsb = 8, + .msb = 8, + .values = NULL + }, + .get_next = csr_icount_get_m + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_icount_get_s(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "s", + .lsb = 7, + .msb = 7, + .values = NULL + }, + .get_next = csr_icount_get_pending + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_icount_get_u(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "u", + .lsb = 6, + .msb = 6, + .values = NULL + }, + .get_next = csr_icount_get_s + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_icount_get_vs(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "vs", + .lsb = 0x1a, + .msb = 0x1a, + .values = NULL + }, + .get_next = csr_icount_get_u + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_icount_get_vu(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "vu", + .lsb = 0x19, + .msb = 0x19, + .values = NULL + }, + .get_next = csr_icount_get_vs + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_icount_get_hit(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hit", + .lsb = 0x18, + .msb = 0x18, + .values = NULL + }, + .get_next = csr_icount_get_vu + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_icount_get_count(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "count", + .lsb = 0xa, + .msb = 0x17, + .values = NULL + }, + .get_next = csr_icount_get_hit + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_icount_get_action(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "action", + .lsb = 0, + .msb = 5, + .values = csr_icount_action_values + }, + .get_next = csr_icount_get_count + }; + return result; +} + +static const char *csr_itrigger_action_values[64] = { + [0] = "breakpoint", + [1] = "debug_mode", + [2] = "trace_on", + [3] = "trace_off", + [4] = "trace_notify", + [8] = "external0", + [9] = "external1" +}; +static riscv_debug_reg_field_list_t csr_itrigger_get_hit(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hit", + .lsb = (context.XLEN.value + -6), + .msb = (context.XLEN.value + -6), + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_itrigger_get_dmode(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dmode", + .lsb = (context.XLEN.value + -5), + .msb = (context.XLEN.value + -5), + .values = NULL + }, + .get_next = csr_itrigger_get_hit + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_itrigger_get_type(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "type", + .lsb = (context.XLEN.value + -4), + .msb = (context.XLEN.value + -1), + .values = NULL + }, + .get_next = csr_itrigger_get_dmode + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_itrigger_get_m(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "m", + .lsb = 9, + .msb = 9, + .values = NULL + }, + .get_next = csr_itrigger_get_type + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_itrigger_get_s(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "s", + .lsb = 7, + .msb = 7, + .values = NULL + }, + .get_next = csr_itrigger_get_m + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_itrigger_get_u(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "u", + .lsb = 6, + .msb = 6, + .values = NULL + }, + .get_next = csr_itrigger_get_s + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_itrigger_get_vs(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "vs", + .lsb = 0xc, + .msb = 0xc, + .values = NULL + }, + .get_next = csr_itrigger_get_u + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_itrigger_get_vu(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "vu", + .lsb = 0xb, + .msb = 0xb, + .values = NULL + }, + .get_next = csr_itrigger_get_vs + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_itrigger_get_nmi(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "nmi", + .lsb = 0xa, + .msb = 0xa, + .values = NULL + }, + .get_next = csr_itrigger_get_vu + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_itrigger_get_action(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "action", + .lsb = 0, + .msb = 5, + .values = csr_itrigger_action_values + }, + .get_next = csr_itrigger_get_nmi + }; + return result; +} + +static const char *csr_etrigger_action_values[64] = { + [0] = "breakpoint", + [1] = "debug_mode", + [2] = "trace_on", + [3] = "trace_off", + [4] = "trace_notify", + [8] = "external0", + [9] = "external1" +}; +static riscv_debug_reg_field_list_t csr_etrigger_get_hit(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hit", + .lsb = (context.XLEN.value + -6), + .msb = (context.XLEN.value + -6), + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_etrigger_get_dmode(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dmode", + .lsb = (context.XLEN.value + -5), + .msb = (context.XLEN.value + -5), + .values = NULL + }, + .get_next = csr_etrigger_get_hit + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_etrigger_get_type(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "type", + .lsb = (context.XLEN.value + -4), + .msb = (context.XLEN.value + -1), + .values = NULL + }, + .get_next = csr_etrigger_get_dmode + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_etrigger_get_m(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "m", + .lsb = 9, + .msb = 9, + .values = NULL + }, + .get_next = csr_etrigger_get_type + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_etrigger_get_s(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "s", + .lsb = 7, + .msb = 7, + .values = NULL + }, + .get_next = csr_etrigger_get_m + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_etrigger_get_u(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "u", + .lsb = 6, + .msb = 6, + .values = NULL + }, + .get_next = csr_etrigger_get_s + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_etrigger_get_vs(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "vs", + .lsb = 0xc, + .msb = 0xc, + .values = NULL + }, + .get_next = csr_etrigger_get_u + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_etrigger_get_vu(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "vu", + .lsb = 0xb, + .msb = 0xb, + .values = NULL + }, + .get_next = csr_etrigger_get_vs + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_etrigger_get_action(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "action", + .lsb = 0, + .msb = 5, + .values = csr_etrigger_action_values + }, + .get_next = csr_etrigger_get_vu + }; + return result; +} + +static const char *csr_tmexttrigger_action_values[64] = { + [0] = "breakpoint", + [1] = "debug_mode", + [2] = "trace_on", + [3] = "trace_off", + [4] = "trace_notify", + [8] = "external0", + [9] = "external1" +}; +static riscv_debug_reg_field_list_t csr_tmexttrigger_get_hit(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hit", + .lsb = (context.XLEN.value + -6), + .msb = (context.XLEN.value + -6), + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_tmexttrigger_get_dmode(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dmode", + .lsb = (context.XLEN.value + -5), + .msb = (context.XLEN.value + -5), + .values = NULL + }, + .get_next = csr_tmexttrigger_get_hit + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_tmexttrigger_get_type(riscv_debug_reg_ctx_t context) +{ + assert(context.XLEN.is_set); + riscv_debug_reg_field_list_t result = { + .field = { + .name = "type", + .lsb = (context.XLEN.value + -4), + .msb = (context.XLEN.value + -1), + .values = NULL + }, + .get_next = csr_tmexttrigger_get_dmode + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_tmexttrigger_get_select(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "select", + .lsb = 6, + .msb = 0x15, + .values = NULL + }, + .get_next = csr_tmexttrigger_get_type + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_tmexttrigger_get_intctl(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "intctl", + .lsb = 0x16, + .msb = 0x16, + .values = NULL + }, + .get_next = csr_tmexttrigger_get_select + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_tmexttrigger_get_action(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "action", + .lsb = 0, + .msb = 5, + .values = csr_tmexttrigger_action_values + }, + .get_next = csr_tmexttrigger_get_intctl + }; + return result; +} + +static const char *csr_textra32_mhselect_values[8] = { + [0] = "ignore", + [4] = "mcontext" +}; +static const char *csr_textra32_sselect_values[4] = { + [0] = "ignore", + [1] = "scontext", + [2] = "asid" +}; +static riscv_debug_reg_field_list_t csr_textra32_get_mhvalue(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "mhvalue", + .lsb = 0x1a, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_textra32_get_mhselect(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "mhselect", + .lsb = 0x17, + .msb = 0x19, + .values = csr_textra32_mhselect_values + }, + .get_next = csr_textra32_get_mhvalue + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_textra32_get_svalue(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "svalue", + .lsb = 2, + .msb = 0x11, + .values = NULL + }, + .get_next = csr_textra32_get_mhselect + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_textra32_get_sbytemask(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sbytemask", + .lsb = 0x12, + .msb = 0x13, + .values = NULL + }, + .get_next = csr_textra32_get_svalue + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_textra32_get_sselect(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sselect", + .lsb = 0, + .msb = 1, + .values = csr_textra32_sselect_values + }, + .get_next = csr_textra32_get_sbytemask + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_textra64_get_mhvalue(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "mhvalue", + .lsb = 0x33, + .msb = 0x3f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_textra64_get_mhselect(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "mhselect", + .lsb = 0x30, + .msb = 0x32, + .values = NULL + }, + .get_next = csr_textra64_get_mhvalue + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_textra64_get_sbytemask(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sbytemask", + .lsb = 0x24, + .msb = 0x28, + .values = NULL + }, + .get_next = csr_textra64_get_mhselect + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_textra64_get_svalue(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "svalue", + .lsb = 2, + .msb = 0x23, + .values = NULL + }, + .get_next = csr_textra64_get_sbytemask + }; + return result; +} + +static riscv_debug_reg_field_list_t csr_textra64_get_sselect(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sselect", + .lsb = 0, + .msb = 1, + .values = NULL + }, + .get_next = csr_textra64_get_svalue + }; + return result; +} + +static const char *dm_dmstatus_ndmresetpending_values[2] = { + [0] = "false", + [1] = "true" +}; +static const char *dm_dmstatus_stickyunavail_values[2] = { + [0] = "current", + [1] = "sticky" +}; +static const char *dm_dmstatus_authenticated_values[2] = { + [0] = "false", + [1] = "true" +}; +static const char *dm_dmstatus_authbusy_values[2] = { + [0] = "ready", + [1] = "busy" +}; +static const char *dm_dmstatus_confstrptrvalid_values[2] = { + [0] = "invalid", + [1] = "valid" +}; +static const char *dm_dmstatus_version_values[16] = { + [0] = "none", + [1] = "0_11", + [2] = "0_13", + [3] = "1_0", + [15] = "custom" +}; +static riscv_debug_reg_field_list_t dm_dmstatus_get_allhalted(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "allhalted", + .lsb = 9, + .msb = 9, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_anyhalted(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "anyhalted", + .lsb = 8, + .msb = 8, + .values = NULL + }, + .get_next = dm_dmstatus_get_allhalted + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_authenticated(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "authenticated", + .lsb = 7, + .msb = 7, + .values = dm_dmstatus_authenticated_values + }, + .get_next = dm_dmstatus_get_anyhalted + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_authbusy(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "authbusy", + .lsb = 6, + .msb = 6, + .values = dm_dmstatus_authbusy_values + }, + .get_next = dm_dmstatus_get_authenticated + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_hasresethaltreq(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hasresethaltreq", + .lsb = 5, + .msb = 5, + .values = NULL + }, + .get_next = dm_dmstatus_get_authbusy + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_confstrptrvalid(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "confstrptrvalid", + .lsb = 4, + .msb = 4, + .values = dm_dmstatus_confstrptrvalid_values + }, + .get_next = dm_dmstatus_get_hasresethaltreq + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_ndmresetpending(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "ndmresetpending", + .lsb = 0x18, + .msb = 0x18, + .values = dm_dmstatus_ndmresetpending_values + }, + .get_next = dm_dmstatus_get_confstrptrvalid + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_stickyunavail(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "stickyunavail", + .lsb = 0x17, + .msb = 0x17, + .values = dm_dmstatus_stickyunavail_values + }, + .get_next = dm_dmstatus_get_ndmresetpending + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_impebreak(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "impebreak", + .lsb = 0x16, + .msb = 0x16, + .values = NULL + }, + .get_next = dm_dmstatus_get_stickyunavail + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_allhavereset(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "allhavereset", + .lsb = 0x13, + .msb = 0x13, + .values = NULL + }, + .get_next = dm_dmstatus_get_impebreak + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_anyhavereset(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "anyhavereset", + .lsb = 0x12, + .msb = 0x12, + .values = NULL + }, + .get_next = dm_dmstatus_get_allhavereset + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_allresumeack(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "allresumeack", + .lsb = 0x11, + .msb = 0x11, + .values = NULL + }, + .get_next = dm_dmstatus_get_anyhavereset + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_anyresumeack(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "anyresumeack", + .lsb = 0x10, + .msb = 0x10, + .values = NULL + }, + .get_next = dm_dmstatus_get_allresumeack + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_allnonexistent(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "allnonexistent", + .lsb = 0xf, + .msb = 0xf, + .values = NULL + }, + .get_next = dm_dmstatus_get_anyresumeack + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_anynonexistent(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "anynonexistent", + .lsb = 0xe, + .msb = 0xe, + .values = NULL + }, + .get_next = dm_dmstatus_get_allnonexistent + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_allunavail(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "allunavail", + .lsb = 0xd, + .msb = 0xd, + .values = NULL + }, + .get_next = dm_dmstatus_get_anynonexistent + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_anyunavail(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "anyunavail", + .lsb = 0xc, + .msb = 0xc, + .values = NULL + }, + .get_next = dm_dmstatus_get_allunavail + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_allrunning(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "allrunning", + .lsb = 0xb, + .msb = 0xb, + .values = NULL + }, + .get_next = dm_dmstatus_get_anyunavail + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_anyrunning(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "anyrunning", + .lsb = 0xa, + .msb = 0xa, + .values = NULL + }, + .get_next = dm_dmstatus_get_allrunning + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmstatus_get_version(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "version", + .lsb = 0, + .msb = 3, + .values = dm_dmstatus_version_values + }, + .get_next = dm_dmstatus_get_anyrunning + }; + return result; +} + +static const char *dm_dmcontrol_ackhavereset_values[2] = { + [0] = "nop", + [1] = "ack" +}; +static const char *dm_dmcontrol_ackunavail_values[2] = { + [0] = "nop", + [1] = "ack" +}; +static const char *dm_dmcontrol_hasel_values[2] = { + [0] = "single", + [1] = "multiple" +}; +static const char *dm_dmcontrol_dmactive_values[2] = { + [0] = "inactive", + [1] = "active" +}; +static riscv_debug_reg_field_list_t dm_dmcontrol_get_hartselhi(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hartselhi", + .lsb = 6, + .msb = 0xf, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcontrol_get_setkeepalive(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "setkeepalive", + .lsb = 5, + .msb = 5, + .values = NULL + }, + .get_next = dm_dmcontrol_get_hartselhi + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcontrol_get_clrkeepalive(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "clrkeepalive", + .lsb = 4, + .msb = 4, + .values = NULL + }, + .get_next = dm_dmcontrol_get_setkeepalive + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcontrol_get_haltreq(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "haltreq", + .lsb = 0x1f, + .msb = 0x1f, + .values = NULL + }, + .get_next = dm_dmcontrol_get_clrkeepalive + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcontrol_get_resumereq(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "resumereq", + .lsb = 0x1e, + .msb = 0x1e, + .values = NULL + }, + .get_next = dm_dmcontrol_get_haltreq + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcontrol_get_setresethaltreq(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "setresethaltreq", + .lsb = 3, + .msb = 3, + .values = NULL + }, + .get_next = dm_dmcontrol_get_resumereq + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcontrol_get_hartreset(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hartreset", + .lsb = 0x1d, + .msb = 0x1d, + .values = NULL + }, + .get_next = dm_dmcontrol_get_setresethaltreq + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcontrol_get_ackhavereset(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "ackhavereset", + .lsb = 0x1c, + .msb = 0x1c, + .values = dm_dmcontrol_ackhavereset_values + }, + .get_next = dm_dmcontrol_get_hartreset + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcontrol_get_ackunavail(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "ackunavail", + .lsb = 0x1b, + .msb = 0x1b, + .values = dm_dmcontrol_ackunavail_values + }, + .get_next = dm_dmcontrol_get_ackhavereset + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcontrol_get_hasel(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hasel", + .lsb = 0x1a, + .msb = 0x1a, + .values = dm_dmcontrol_hasel_values + }, + .get_next = dm_dmcontrol_get_ackunavail + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcontrol_get_clrresethaltreq(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "clrresethaltreq", + .lsb = 2, + .msb = 2, + .values = NULL + }, + .get_next = dm_dmcontrol_get_hasel + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcontrol_get_hartsello(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hartsello", + .lsb = 0x10, + .msb = 0x19, + .values = NULL + }, + .get_next = dm_dmcontrol_get_clrresethaltreq + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcontrol_get_ndmreset(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "ndmreset", + .lsb = 1, + .msb = 1, + .values = NULL + }, + .get_next = dm_dmcontrol_get_hartsello + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcontrol_get_dmactive(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dmactive", + .lsb = 0, + .msb = 0, + .values = dm_dmcontrol_dmactive_values + }, + .get_next = dm_dmcontrol_get_ndmreset + }; + return result; +} + +static const char *dm_hartinfo_dataaccess_values[2] = { + [0] = "csr", + [1] = "memory" +}; +static riscv_debug_reg_field_list_t dm_hartinfo_get_nscratch(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "nscratch", + .lsb = 0x14, + .msb = 0x17, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_hartinfo_get_dataaccess(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dataaccess", + .lsb = 0x10, + .msb = 0x10, + .values = dm_hartinfo_dataaccess_values + }, + .get_next = dm_hartinfo_get_nscratch + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_hartinfo_get_datasize(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "datasize", + .lsb = 0xc, + .msb = 0xf, + .values = NULL + }, + .get_next = dm_hartinfo_get_dataaccess + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_hartinfo_get_dataaddr(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dataaddr", + .lsb = 0, + .msb = 0xb, + .values = NULL + }, + .get_next = dm_hartinfo_get_datasize + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_hawindowsel_get_hawindowsel(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hawindowsel", + .lsb = 0, + .msb = 0xe, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_hawindow_get_maskdata(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "maskdata", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static const char *dm_abstractcs_busy_values[2] = { + [0] = "ready", + [1] = "busy" +}; +static const char *dm_abstractcs_relaxedpriv_values[2] = { + [0] = "full_checks", + [1] = "relaxed_checks" +}; +static const char *dm_abstractcs_cmderr_values[8] = { + [0] = "none", + [1] = "busy", + [2] = "not_supported", + [3] = "exception", + [4] = "halt_resume", + [5] = "bus", + [6] = "reserved", + [7] = "other" +}; +static riscv_debug_reg_field_list_t dm_abstractcs_get_cmderr(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "cmderr", + .lsb = 8, + .msb = 0xa, + .values = dm_abstractcs_cmderr_values + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_abstractcs_get_progbufsize(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "progbufsize", + .lsb = 0x18, + .msb = 0x1c, + .values = NULL + }, + .get_next = dm_abstractcs_get_cmderr + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_abstractcs_get_busy(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "busy", + .lsb = 0xc, + .msb = 0xc, + .values = dm_abstractcs_busy_values + }, + .get_next = dm_abstractcs_get_progbufsize + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_abstractcs_get_relaxedpriv(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "relaxedpriv", + .lsb = 0xb, + .msb = 0xb, + .values = dm_abstractcs_relaxedpriv_values + }, + .get_next = dm_abstractcs_get_busy + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_abstractcs_get_datacount(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "datacount", + .lsb = 0, + .msb = 3, + .values = NULL + }, + .get_next = dm_abstractcs_get_relaxedpriv + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_command_get_cmdtype(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "cmdtype", + .lsb = 0x18, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_command_get_control(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "control", + .lsb = 0, + .msb = 0x17, + .values = NULL + }, + .get_next = dm_command_get_cmdtype + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_abstractauto_get_autoexecprogbuf(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "autoexecprogbuf", + .lsb = 0x10, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_abstractauto_get_autoexecdata(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "autoexecdata", + .lsb = 0, + .msb = 0xb, + .values = NULL + }, + .get_next = dm_abstractauto_get_autoexecprogbuf + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_confstrptr0_get_addr(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "addr", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_confstrptr1_get_addr(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "addr", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_confstrptr2_get_addr(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "addr", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_confstrptr3_get_addr(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "addr", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_nextdm_get_addr(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "addr", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_data0_get_data(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "data", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_progbuf0_get_data(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "data", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_authdata_get_data(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "data", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static const char *dm_dmcs2_grouptype_values[2] = { + [0] = "halt", + [1] = "resume" +}; +static const char *dm_dmcs2_hgselect_values[2] = { + [0] = "harts", + [1] = "triggers" +}; +static riscv_debug_reg_field_list_t dm_dmcs2_get_dmexttrigger(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "dmexttrigger", + .lsb = 7, + .msb = 0xa, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcs2_get_group(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "group", + .lsb = 2, + .msb = 6, + .values = NULL + }, + .get_next = dm_dmcs2_get_dmexttrigger + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcs2_get_grouptype(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "grouptype", + .lsb = 0xb, + .msb = 0xb, + .values = dm_dmcs2_grouptype_values + }, + .get_next = dm_dmcs2_get_group + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcs2_get_hgwrite(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hgwrite", + .lsb = 1, + .msb = 1, + .values = NULL + }, + .get_next = dm_dmcs2_get_grouptype + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_dmcs2_get_hgselect(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "hgselect", + .lsb = 0, + .msb = 0, + .values = dm_dmcs2_hgselect_values + }, + .get_next = dm_dmcs2_get_hgwrite + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_haltsum0_get_haltsum0(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "haltsum0", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_haltsum1_get_haltsum1(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "haltsum1", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_haltsum2_get_haltsum2(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "haltsum2", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_haltsum3_get_haltsum3(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "haltsum3", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static const char *dm_sbcs_sbversion_values[8] = { + [0] = "legacy", + [1] = "1_0" +}; +static const char *dm_sbcs_sbaccess_values[8] = { + [0] = "8bit", + [1] = "16bit", + [2] = "32bit", + [3] = "64bit", + [4] = "128bit" +}; +static const char *dm_sbcs_sberror_values[8] = { + [0] = "none", + [1] = "timeout", + [2] = "address", + [3] = "alignment", + [4] = "size", + [7] = "other" +}; +static riscv_debug_reg_field_list_t dm_sbcs_get_sbasize(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sbasize", + .lsb = 5, + .msb = 0xb, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess128(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sbaccess128", + .lsb = 4, + .msb = 4, + .values = NULL + }, + .get_next = dm_sbcs_get_sbasize + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess64(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sbaccess64", + .lsb = 3, + .msb = 3, + .values = NULL + }, + .get_next = dm_sbcs_get_sbaccess128 + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbcs_get_sbversion(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sbversion", + .lsb = 0x1d, + .msb = 0x1f, + .values = dm_sbcs_sbversion_values + }, + .get_next = dm_sbcs_get_sbaccess64 + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbcs_get_sbbusyerror(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sbbusyerror", + .lsb = 0x16, + .msb = 0x16, + .values = NULL + }, + .get_next = dm_sbcs_get_sbversion + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbcs_get_sbbusy(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sbbusy", + .lsb = 0x15, + .msb = 0x15, + .values = NULL + }, + .get_next = dm_sbcs_get_sbbusyerror + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbcs_get_sbreadonaddr(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sbreadonaddr", + .lsb = 0x14, + .msb = 0x14, + .values = NULL + }, + .get_next = dm_sbcs_get_sbbusy + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess32(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sbaccess32", + .lsb = 2, + .msb = 2, + .values = NULL + }, + .get_next = dm_sbcs_get_sbreadonaddr + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sbaccess", + .lsb = 0x11, + .msb = 0x13, + .values = dm_sbcs_sbaccess_values + }, + .get_next = dm_sbcs_get_sbaccess32 + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbcs_get_sbautoincrement(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sbautoincrement", + .lsb = 0x10, + .msb = 0x10, + .values = NULL + }, + .get_next = dm_sbcs_get_sbaccess + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbcs_get_sbreadondata(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sbreadondata", + .lsb = 0xf, + .msb = 0xf, + .values = NULL + }, + .get_next = dm_sbcs_get_sbautoincrement + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbcs_get_sberror(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sberror", + .lsb = 0xc, + .msb = 0xe, + .values = dm_sbcs_sberror_values + }, + .get_next = dm_sbcs_get_sbreadondata + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess16(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sbaccess16", + .lsb = 1, + .msb = 1, + .values = NULL + }, + .get_next = dm_sbcs_get_sberror + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbcs_get_sbaccess8(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "sbaccess8", + .lsb = 0, + .msb = 0, + .values = NULL + }, + .get_next = dm_sbcs_get_sbaccess16 + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbaddress0_get_address(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "address", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbaddress1_get_address(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "address", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbaddress2_get_address(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "address", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbaddress3_get_address(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "address", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbdata0_get_data(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "data", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbdata1_get_data(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "data", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbdata2_get_data(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "data", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t dm_sbdata3_get_data(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "data", + .lsb = 0, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t shortname_get_field(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "field", + .lsb = 0, + .msb = 7, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static const char *ac_access_register_aarsize_values[8] = { + [2] = "32bit", + [3] = "64bit", + [4] = "128bit" +}; +static const char *ac_access_register_aarpostincrement_values[2] = { + [0] = "disabled", + [1] = "enabled" +}; +static const char *ac_access_register_postexec_values[2] = { + [0] = "disabled", + [1] = "enabled" +}; +static const char *ac_access_register_transfer_values[2] = { + [0] = "disabled", + [1] = "enabled" +}; +static const char *ac_access_register_write_values[2] = { + [0] = "arg0", + [1] = "register" +}; +static riscv_debug_reg_field_list_t ac_access_register_get_cmdtype(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "cmdtype", + .lsb = 0x18, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t ac_access_register_get_aarsize(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "aarsize", + .lsb = 0x14, + .msb = 0x16, + .values = ac_access_register_aarsize_values + }, + .get_next = ac_access_register_get_cmdtype + }; + return result; +} + +static riscv_debug_reg_field_list_t ac_access_register_get_aarpostincrement(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "aarpostincrement", + .lsb = 0x13, + .msb = 0x13, + .values = ac_access_register_aarpostincrement_values + }, + .get_next = ac_access_register_get_aarsize + }; + return result; +} + +static riscv_debug_reg_field_list_t ac_access_register_get_postexec(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "postexec", + .lsb = 0x12, + .msb = 0x12, + .values = ac_access_register_postexec_values + }, + .get_next = ac_access_register_get_aarpostincrement + }; + return result; +} + +static riscv_debug_reg_field_list_t ac_access_register_get_transfer(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "transfer", + .lsb = 0x11, + .msb = 0x11, + .values = ac_access_register_transfer_values + }, + .get_next = ac_access_register_get_postexec + }; + return result; +} + +static riscv_debug_reg_field_list_t ac_access_register_get_write(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "write", + .lsb = 0x10, + .msb = 0x10, + .values = ac_access_register_write_values + }, + .get_next = ac_access_register_get_transfer + }; + return result; +} + +static riscv_debug_reg_field_list_t ac_access_register_get_regno(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "regno", + .lsb = 0, + .msb = 0xf, + .values = NULL + }, + .get_next = ac_access_register_get_write + }; + return result; +} + +static riscv_debug_reg_field_list_t ac_quick_access_get_cmdtype(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "cmdtype", + .lsb = 0x18, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static const char *ac_access_memory_aamvirtual_values[2] = { + [0] = "physical", + [1] = "virtual" +}; +static const char *ac_access_memory_aamsize_values[8] = { + [0] = "8bit", + [1] = "16bit", + [2] = "32bit", + [3] = "64bit", + [4] = "128bit" +}; +static const char *ac_access_memory_write_values[2] = { + [0] = "arg0", + [1] = "memory" +}; +static riscv_debug_reg_field_list_t ac_access_memory_get_cmdtype(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "cmdtype", + .lsb = 0x18, + .msb = 0x1f, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t ac_access_memory_get_aamvirtual(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "aamvirtual", + .lsb = 0x17, + .msb = 0x17, + .values = ac_access_memory_aamvirtual_values + }, + .get_next = ac_access_memory_get_cmdtype + }; + return result; +} + +static riscv_debug_reg_field_list_t ac_access_memory_get_aamsize(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "aamsize", + .lsb = 0x14, + .msb = 0x16, + .values = ac_access_memory_aamsize_values + }, + .get_next = ac_access_memory_get_aamvirtual + }; + return result; +} + +static riscv_debug_reg_field_list_t ac_access_memory_get_aampostincrement(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "aampostincrement", + .lsb = 0x13, + .msb = 0x13, + .values = NULL + }, + .get_next = ac_access_memory_get_aamsize + }; + return result; +} + +static riscv_debug_reg_field_list_t ac_access_memory_get_write(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "write", + .lsb = 0x10, + .msb = 0x10, + .values = ac_access_memory_write_values + }, + .get_next = ac_access_memory_get_aampostincrement + }; + return result; +} + +static riscv_debug_reg_field_list_t ac_access_memory_get_target_specific(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "target-specific", + .lsb = 0xe, + .msb = 0xf, + .values = NULL + }, + .get_next = ac_access_memory_get_write + }; + return result; +} + +static riscv_debug_reg_field_list_t virt_priv_get_v(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "v", + .lsb = 2, + .msb = 2, + .values = NULL + }, + .get_next = NULL + }; + return result; +} + +static riscv_debug_reg_field_list_t virt_priv_get_prv(riscv_debug_reg_ctx_t context) +{ + riscv_debug_reg_field_list_t result = { + .field = { + .name = "prv", + .lsb = 0, + .msb = 1, + .values = NULL + }, + .get_next = virt_priv_get_v + }; + return result; +} + +riscv_debug_reg_info_t get_riscv_debug_reg_info(enum riscv_debug_reg_ordinal reg_ordinal) +{ + static const riscv_debug_reg_info_t debug_reg_info[] = { + [DTM_IDCODE_ORDINAL] = { + .name = "idcode", + .get_fields_head = dtm_idcode_get_1 + }, + [DTM_DTMCS_ORDINAL] = { + .name = "dtmcs", + .get_fields_head = dtm_dtmcs_get_version + }, + [DTM_DMI_ORDINAL] = { + .name = "dmi", + .get_fields_head = dtm_dmi_get_op + }, + [DTM_BYPASS_ORDINAL] = { + .name = "bypass", + .get_fields_head = NULL + }, + [CSR_DCSR_ORDINAL] = { + .name = "dcsr", + .get_fields_head = csr_dcsr_get_prv + }, + [CSR_DPC_ORDINAL] = { + .name = "dpc", + .get_fields_head = csr_dpc_get_dpc + }, + [CSR_DSCRATCH0_ORDINAL] = { + .name = "dscratch0", + .get_fields_head = csr_dscratch0_get_dscratch0 + }, + [CSR_DSCRATCH1_ORDINAL] = { + .name = "dscratch1", + .get_fields_head = csr_dscratch1_get_dscratch1 + }, + [CSR_TSELECT_ORDINAL] = { + .name = "tselect", + .get_fields_head = csr_tselect_get_index + }, + [CSR_TDATA1_ORDINAL] = { + .name = "tdata1", + .get_fields_head = csr_tdata1_get_data + }, + [CSR_TDATA2_ORDINAL] = { + .name = "tdata2", + .get_fields_head = csr_tdata2_get_data + }, + [CSR_TDATA3_ORDINAL] = { + .name = "tdata3", + .get_fields_head = csr_tdata3_get_data + }, + [CSR_TINFO_ORDINAL] = { + .name = "tinfo", + .get_fields_head = csr_tinfo_get_info + }, + [CSR_TCONTROL_ORDINAL] = { + .name = "tcontrol", + .get_fields_head = csr_tcontrol_get_mte + }, + [CSR_SCONTEXT_ORDINAL] = { + .name = "scontext", + .get_fields_head = csr_scontext_get_data + }, + [CSR_MCONTEXT_ORDINAL] = { + .name = "mcontext", + .get_fields_head = csr_mcontext_get_hcontext + }, + [CSR_MCONTROL_ORDINAL] = { + .name = "mcontrol", + .get_fields_head = csr_mcontrol_get_load + }, + [CSR_MCONTROL6_ORDINAL] = { + .name = "mcontrol6", + .get_fields_head = csr_mcontrol6_get_load + }, + [CSR_ICOUNT_ORDINAL] = { + .name = "icount", + .get_fields_head = csr_icount_get_action + }, + [CSR_ITRIGGER_ORDINAL] = { + .name = "itrigger", + .get_fields_head = csr_itrigger_get_action + }, + [CSR_ETRIGGER_ORDINAL] = { + .name = "etrigger", + .get_fields_head = csr_etrigger_get_action + }, + [CSR_TMEXTTRIGGER_ORDINAL] = { + .name = "tmexttrigger", + .get_fields_head = csr_tmexttrigger_get_action + }, + [CSR_TEXTRA32_ORDINAL] = { + .name = "textra32", + .get_fields_head = csr_textra32_get_sselect + }, + [CSR_TEXTRA64_ORDINAL] = { + .name = "textra64", + .get_fields_head = csr_textra64_get_sselect + }, + [DM_DMSTATUS_ORDINAL] = { + .name = "dmstatus", + .get_fields_head = dm_dmstatus_get_version + }, + [DM_DMCONTROL_ORDINAL] = { + .name = "dmcontrol", + .get_fields_head = dm_dmcontrol_get_dmactive + }, + [DM_HARTINFO_ORDINAL] = { + .name = "hartinfo", + .get_fields_head = dm_hartinfo_get_dataaddr + }, + [DM_HAWINDOWSEL_ORDINAL] = { + .name = "hawindowsel", + .get_fields_head = dm_hawindowsel_get_hawindowsel + }, + [DM_HAWINDOW_ORDINAL] = { + .name = "hawindow", + .get_fields_head = dm_hawindow_get_maskdata + }, + [DM_ABSTRACTCS_ORDINAL] = { + .name = "abstractcs", + .get_fields_head = dm_abstractcs_get_datacount + }, + [DM_COMMAND_ORDINAL] = { + .name = "command", + .get_fields_head = dm_command_get_control + }, + [DM_ABSTRACTAUTO_ORDINAL] = { + .name = "abstractauto", + .get_fields_head = dm_abstractauto_get_autoexecdata + }, + [DM_CONFSTRPTR0_ORDINAL] = { + .name = "confstrptr0", + .get_fields_head = dm_confstrptr0_get_addr + }, + [DM_CONFSTRPTR1_ORDINAL] = { + .name = "confstrptr1", + .get_fields_head = dm_confstrptr1_get_addr + }, + [DM_CONFSTRPTR2_ORDINAL] = { + .name = "confstrptr2", + .get_fields_head = dm_confstrptr2_get_addr + }, + [DM_CONFSTRPTR3_ORDINAL] = { + .name = "confstrptr3", + .get_fields_head = dm_confstrptr3_get_addr + }, + [DM_NEXTDM_ORDINAL] = { + .name = "nextdm", + .get_fields_head = dm_nextdm_get_addr + }, + [DM_DATA0_ORDINAL] = { + .name = "data0", + .get_fields_head = dm_data0_get_data + }, + [DM_PROGBUF0_ORDINAL] = { + .name = "progbuf0", + .get_fields_head = dm_progbuf0_get_data + }, + [DM_AUTHDATA_ORDINAL] = { + .name = "authdata", + .get_fields_head = dm_authdata_get_data + }, + [DM_DMCS2_ORDINAL] = { + .name = "dmcs2", + .get_fields_head = dm_dmcs2_get_hgselect + }, + [DM_HALTSUM0_ORDINAL] = { + .name = "haltsum0", + .get_fields_head = dm_haltsum0_get_haltsum0 + }, + [DM_HALTSUM1_ORDINAL] = { + .name = "haltsum1", + .get_fields_head = dm_haltsum1_get_haltsum1 + }, + [DM_HALTSUM2_ORDINAL] = { + .name = "haltsum2", + .get_fields_head = dm_haltsum2_get_haltsum2 + }, + [DM_HALTSUM3_ORDINAL] = { + .name = "haltsum3", + .get_fields_head = dm_haltsum3_get_haltsum3 + }, + [DM_SBCS_ORDINAL] = { + .name = "sbcs", + .get_fields_head = dm_sbcs_get_sbaccess8 + }, + [DM_SBADDRESS0_ORDINAL] = { + .name = "sbaddress0", + .get_fields_head = dm_sbaddress0_get_address + }, + [DM_SBADDRESS1_ORDINAL] = { + .name = "sbaddress1", + .get_fields_head = dm_sbaddress1_get_address + }, + [DM_SBADDRESS2_ORDINAL] = { + .name = "sbaddress2", + .get_fields_head = dm_sbaddress2_get_address + }, + [DM_SBADDRESS3_ORDINAL] = { + .name = "sbaddress3", + .get_fields_head = dm_sbaddress3_get_address + }, + [DM_SBDATA0_ORDINAL] = { + .name = "sbdata0", + .get_fields_head = dm_sbdata0_get_data + }, + [DM_SBDATA1_ORDINAL] = { + .name = "sbdata1", + .get_fields_head = dm_sbdata1_get_data + }, + [DM_SBDATA2_ORDINAL] = { + .name = "sbdata2", + .get_fields_head = dm_sbdata2_get_data + }, + [DM_SBDATA3_ORDINAL] = { + .name = "sbdata3", + .get_fields_head = dm_sbdata3_get_data + }, + [SHORTNAME_ORDINAL] = { + .name = "shortname", + .get_fields_head = shortname_get_field + }, + [AC_ACCESS_REGISTER_ORDINAL] = { + .name = "access register", + .get_fields_head = ac_access_register_get_regno + }, + [AC_QUICK_ACCESS_ORDINAL] = { + .name = "quick access", + .get_fields_head = ac_quick_access_get_cmdtype + }, + [AC_ACCESS_MEMORY_ORDINAL] = { + .name = "access memory", + .get_fields_head = ac_access_memory_get_target_specific + }, + [VIRT_PRIV_ORDINAL] = { + .name = "priv", + .get_fields_head = virt_priv_get_prv + }, + }; + return debug_reg_info[reg_ordinal]; +} diff --git a/src/target/riscv/debug_defines.h b/src/target/riscv/debug_defines.h index 8113d47664..dbe5142a8e 100644 --- a/src/target/riscv/debug_defines.h +++ b/src/target/riscv/debug_defines.h @@ -1,21 +1,23 @@ /* - * This file is auto-generated by running 'make debug_defines.h' in - * https://github.com/riscv/riscv-debug-spec/ (d749752) + * This file is auto-generated by running 'make debug_defines' in + * https://github.com/riscv/riscv-debug-spec/ (40b9a05) */ +#ifndef DEBUG_DEFINES_H +#define DEBUG_DEFINES_H #define DTM_IDCODE 0x01 /* * Identifies the release version of this part. */ -#define DTM_IDCODE_VERSION_OFFSET 0x1c -#define DTM_IDCODE_VERSION_LENGTH 4 -#define DTM_IDCODE_VERSION 0xf0000000U +#define DTM_IDCODE_VERSION_OFFSET 0x1cULL +#define DTM_IDCODE_VERSION_LENGTH 4ULL +#define DTM_IDCODE_VERSION 0xf0000000ULL /* * Identifies the designer's part number of this part. */ -#define DTM_IDCODE_PARTNUMBER_OFFSET 0xc -#define DTM_IDCODE_PARTNUMBER_LENGTH 0x10 -#define DTM_IDCODE_PARTNUMBER 0xffff000 +#define DTM_IDCODE_PARTNUMBER_OFFSET 0xcULL +#define DTM_IDCODE_PARTNUMBER_LENGTH 0x10ULL +#define DTM_IDCODE_PARTNUMBER 0xffff000ULL /* * Identifies the designer/manufacturer of this part. Bits 6:0 must be * bits 6:0 of the designer/manufacturer's Identification Code as @@ -23,13 +25,46 @@ * count of the number of continuation characters (0x7f) in that same * Identification Code. */ -#define DTM_IDCODE_MANUFID_OFFSET 1 -#define DTM_IDCODE_MANUFID_LENGTH 0xb -#define DTM_IDCODE_MANUFID 0xffe -#define DTM_IDCODE_1_OFFSET 0 -#define DTM_IDCODE_1_LENGTH 1 -#define DTM_IDCODE_1 1 +#define DTM_IDCODE_MANUFID_OFFSET 1ULL +#define DTM_IDCODE_MANUFID_LENGTH 0xbULL +#define DTM_IDCODE_MANUFID 0xffeULL +#define DTM_IDCODE_1_OFFSET 0ULL +#define DTM_IDCODE_1_LENGTH 1ULL +#define DTM_IDCODE_1 1ULL #define DTM_DTMCS 0x10 +/* + * This optional field may provide additional detail about an error + * that occurred when communicating with a DM. It is updated whenever + * \FdtmDmiOp is updated by the hardware or when 1 is written to + * \FdtmDtmcsDmireset. + */ +#define DTM_DTMCS_ERRINFO_OFFSET 0x12ULL +#define DTM_DTMCS_ERRINFO_LENGTH 3ULL +#define DTM_DTMCS_ERRINFO 0x1c0000ULL +/* + * not implemented: This field is not implemented. + */ +#define DTM_DTMCS_ERRINFO_NOT_IMPLEMENTED 0 +/* + * dmi error: There was an error between the DTM and DMI. + */ +#define DTM_DTMCS_ERRINFO_DMI_ERROR 1 +/* + * communication error: There was an error between the DMI and a DMI subordinate. + */ +#define DTM_DTMCS_ERRINFO_COMMUNICATION_ERROR 2 +/* + * device error: The DMI subordinate reported an error. + */ +#define DTM_DTMCS_ERRINFO_DEVICE_ERROR 3 +/* + * unknown: There is no error to report, or no further information available + * about the error. This is the reset value if the field is implemented. + */ +#define DTM_DTMCS_ERRINFO_UNKNOWN 4 +/* + * Other values are reserved for future use by this specification. + */ /* * Writing 1 to this bit does a hard reset of the DTM, * causing the DTM to forget about any outstanding DMI transactions, and @@ -39,16 +74,16 @@ * complete (e.g. a reset condition caused an inflight DMI transaction to * be cancelled). */ -#define DTM_DTMCS_DMIHARDRESET_OFFSET 0x11 -#define DTM_DTMCS_DMIHARDRESET_LENGTH 1 -#define DTM_DTMCS_DMIHARDRESET 0x20000 +#define DTM_DTMCS_DTMHARDRESET_OFFSET 0x11ULL +#define DTM_DTMCS_DTMHARDRESET_LENGTH 1ULL +#define DTM_DTMCS_DTMHARDRESET 0x20000ULL /* - * Writing 1 to this bit clears the sticky error state, but does - * not affect outstanding DMI transactions. + * Writing 1 to this bit clears the sticky error state and resets + * \FdtmDtmcsErrinfo, but does not affect outstanding DMI transactions. */ -#define DTM_DTMCS_DMIRESET_OFFSET 0x10 -#define DTM_DTMCS_DMIRESET_LENGTH 1 -#define DTM_DTMCS_DMIRESET 0x10000 +#define DTM_DTMCS_DMIRESET_OFFSET 0x10ULL +#define DTM_DTMCS_DMIRESET_LENGTH 1ULL +#define DTM_DTMCS_DMIRESET 0x10000ULL /* * This is a hint to the debugger of the minimum number of * cycles a debugger should spend in @@ -64,24 +99,24 @@ * * And so on. */ -#define DTM_DTMCS_IDLE_OFFSET 0xc -#define DTM_DTMCS_IDLE_LENGTH 3 -#define DTM_DTMCS_IDLE 0x7000 +#define DTM_DTMCS_IDLE_OFFSET 0xcULL +#define DTM_DTMCS_IDLE_LENGTH 3ULL +#define DTM_DTMCS_IDLE 0x7000ULL /* * Read-only alias of \FdtmDmiOp. */ -#define DTM_DTMCS_DMISTAT_OFFSET 0xa -#define DTM_DTMCS_DMISTAT_LENGTH 2 -#define DTM_DTMCS_DMISTAT 0xc00 +#define DTM_DTMCS_DMISTAT_OFFSET 0xaULL +#define DTM_DTMCS_DMISTAT_LENGTH 2ULL +#define DTM_DTMCS_DMISTAT 0xc00ULL /* * The size of \FdmSbaddressZeroAddress in \RdtmDmi. */ -#define DTM_DTMCS_ABITS_OFFSET 4 -#define DTM_DTMCS_ABITS_LENGTH 6 -#define DTM_DTMCS_ABITS 0x3f0 -#define DTM_DTMCS_VERSION_OFFSET 0 -#define DTM_DTMCS_VERSION_LENGTH 4 -#define DTM_DTMCS_VERSION 0xf +#define DTM_DTMCS_ABITS_OFFSET 4ULL +#define DTM_DTMCS_ABITS_LENGTH 6ULL +#define DTM_DTMCS_ABITS 0x3f0ULL +#define DTM_DTMCS_VERSION_OFFSET 0ULL +#define DTM_DTMCS_VERSION_LENGTH 4ULL +#define DTM_DTMCS_VERSION 0xfULL /* * 0.11: Version described in spec version 0.11. */ @@ -98,23 +133,25 @@ /* * Address used for DMI access. In Update-DR this value is used * to access the DM over the DMI. + * \FdtmDmiOp defines what this register contains after every possible + * operation. */ -#define DTM_DMI_ADDRESS_OFFSET 0x22 -#define DTM_DMI_ADDRESS_LENGTH(abits) abits -#define DTM_DMI_ADDRESS(abits) ((0x400000000ULL * (1ULL<<abits)) + -0x400000000ULL) +#define DTM_DMI_ADDRESS_OFFSET 0x22ULL +#define DTM_DMI_ADDRESS_LENGTH(abits) (abits) +#define DTM_DMI_ADDRESS(abits) ((0x400000000ULL * (1ULL << (abits))) + -0x400000000ULL) /* * The data to send to the DM over the DMI during Update-DR, and * the data returned from the DM as a result of the previous operation. */ -#define DTM_DMI_DATA_OFFSET 2 -#define DTM_DMI_DATA_LENGTH 0x20 +#define DTM_DMI_DATA_OFFSET 2ULL +#define DTM_DMI_DATA_LENGTH 0x20ULL #define DTM_DMI_DATA 0x3fffffffcULL /* * When the debugger writes this field, it has the following meaning: */ -#define DTM_DMI_OP_OFFSET 0 -#define DTM_DMI_OP_LENGTH 2 -#define DTM_DMI_OP 3 +#define DTM_DMI_OP_OFFSET 0ULL +#define DTM_DMI_OP_LENGTH 2ULL +#define DTM_DMI_OP 3ULL /* * nop: Ignore \FdmSbdataZeroData and \FdmSbaddressZeroAddress. * @@ -122,14 +159,24 @@ * This operation should never result in a busy or error response. * The address and data reported in the following Capture-DR * are undefined. + * + * This operation leaves the values in \FdtmDmiAddress and \FdtmDmiData + * \unspecified. */ #define DTM_DMI_OP_NOP 0 /* - * read: Read from \FdmSbaddressZeroAddress. + * read: Read from \FdtmDmiAddress. + * + * When this operation succeeds, \FdtmDmiAddress contains the address + * that was read from, and \FdtmDmiData contains the value that was + * read. */ #define DTM_DMI_OP_READ 1 /* - * write: Write \FdmSbdataZeroData to \FdmSbaddressZeroAddress. + * write: Write \FdtmDmiData to \FdtmDmiAddress. + * + * This operation leaves the values in \FdtmDmiAddress and \FdtmDmiData + * \unspecified. */ #define DTM_DMI_OP_WRITE 2 /* @@ -150,10 +197,13 @@ * this access will be ignored. This status is sticky and can be * cleared by writing \FdtmDtmcsDmireset in \RdtmDtmcs. * - * This indicates that the DM itself responded with an error. + * This indicates that the DM itself or the DMI responded with an error. * There are no specified cases in which the DM would * respond with an error, and DMI is not required to support * returning errors. + * + * If a debugger sees this status, there might be additional + * information in \FdtmDtmcsErrinfo. */ #define DTM_DMI_OP_FAILED 2 /* @@ -167,9 +217,9 @@ */ #define DTM_DMI_OP_BUSY 3 #define CSR_DCSR 0x7b0 -#define CSR_DCSR_DEBUGVER_OFFSET 0x1c -#define CSR_DCSR_DEBUGVER_LENGTH 4 -#define CSR_DCSR_DEBUGVER 0xf0000000U +#define CSR_DCSR_DEBUGVER_OFFSET 0x1cULL +#define CSR_DCSR_DEBUGVER_LENGTH 4ULL +#define CSR_DCSR_DEBUGVER 0xf0000000ULL /* * none: There is no debug support. */ @@ -183,9 +233,9 @@ * available version of this spec. */ #define CSR_DCSR_DEBUGVER_CUSTOM 15 -#define CSR_DCSR_EBREAKVS_OFFSET 0x11 -#define CSR_DCSR_EBREAKVS_LENGTH 1 -#define CSR_DCSR_EBREAKVS 0x20000 +#define CSR_DCSR_EBREAKVS_OFFSET 0x11ULL +#define CSR_DCSR_EBREAKVS_LENGTH 1ULL +#define CSR_DCSR_EBREAKVS 0x20000ULL /* * exception: {\tt ebreak} instructions in VS-mode behave as described in the * Privileged Spec. @@ -198,9 +248,9 @@ /* * This bit is hardwired to 0 if the hart does not support virtualization mode. */ -#define CSR_DCSR_EBREAKVU_OFFSET 0x10 -#define CSR_DCSR_EBREAKVU_LENGTH 1 -#define CSR_DCSR_EBREAKVU 0x10000 +#define CSR_DCSR_EBREAKVU_OFFSET 0x10ULL +#define CSR_DCSR_EBREAKVU_LENGTH 1ULL +#define CSR_DCSR_EBREAKVU 0x10000ULL /* * exception: {\tt ebreak} instructions in VU-mode behave as described in the * Privileged Spec. @@ -213,9 +263,9 @@ /* * This bit is hardwired to 0 if the hart does not support virtualization mode. */ -#define CSR_DCSR_EBREAKM_OFFSET 0xf -#define CSR_DCSR_EBREAKM_LENGTH 1 -#define CSR_DCSR_EBREAKM 0x8000 +#define CSR_DCSR_EBREAKM_OFFSET 0xfULL +#define CSR_DCSR_EBREAKM_LENGTH 1ULL +#define CSR_DCSR_EBREAKM 0x8000ULL /* * exception: {\tt ebreak} instructions in M-mode behave as described in the * Privileged Spec. @@ -225,9 +275,9 @@ * debug mode: {\tt ebreak} instructions in M-mode enter Debug Mode. */ #define CSR_DCSR_EBREAKM_DEBUG_MODE 1 -#define CSR_DCSR_EBREAKS_OFFSET 0xd -#define CSR_DCSR_EBREAKS_LENGTH 1 -#define CSR_DCSR_EBREAKS 0x2000 +#define CSR_DCSR_EBREAKS_OFFSET 0xdULL +#define CSR_DCSR_EBREAKS_LENGTH 1ULL +#define CSR_DCSR_EBREAKS 0x2000ULL /* * exception: {\tt ebreak} instructions in S-mode behave as described in the * Privileged Spec. @@ -240,9 +290,9 @@ /* * This bit is hardwired to 0 if the hart does not support S-mode. */ -#define CSR_DCSR_EBREAKU_OFFSET 0xc -#define CSR_DCSR_EBREAKU_LENGTH 1 -#define CSR_DCSR_EBREAKU 0x1000 +#define CSR_DCSR_EBREAKU_OFFSET 0xcULL +#define CSR_DCSR_EBREAKU_LENGTH 1ULL +#define CSR_DCSR_EBREAKU 0x1000ULL /* * exception: {\tt ebreak} instructions in U-mode behave as described in the * Privileged Spec. @@ -255,15 +305,18 @@ /* * This bit is hardwired to 0 if the hart does not support U-mode. */ -#define CSR_DCSR_STEPIE_OFFSET 0xb -#define CSR_DCSR_STEPIE_LENGTH 1 -#define CSR_DCSR_STEPIE 0x800 +#define CSR_DCSR_STEPIE_OFFSET 0xbULL +#define CSR_DCSR_STEPIE_LENGTH 1ULL +#define CSR_DCSR_STEPIE 0x800ULL /* - * interrupts disabled: Interrupts (including NMI) are disabled during single stepping. + * interrupts disabled: Interrupts (including NMI) are disabled during single stepping + * with \FcsrDcsrStep set. + * This value should be supported. */ #define CSR_DCSR_STEPIE_INTERRUPTS_DISABLED 0 /* - * interrupts enabled: Interrupts (including NMI) are enabled during single stepping. + * interrupts enabled: Interrupts (including NMI) are enabled during single stepping + * with \FcsrDcsrStep set. */ #define CSR_DCSR_STEPIE_INTERRUPTS_ENABLED 1 /* @@ -273,9 +326,9 @@ * The debugger must not change the value of this bit while the hart * is running. */ -#define CSR_DCSR_STOPCOUNT_OFFSET 0xa -#define CSR_DCSR_STOPCOUNT_LENGTH 1 -#define CSR_DCSR_STOPCOUNT 0x400 +#define CSR_DCSR_STOPCOUNT_OFFSET 0xaULL +#define CSR_DCSR_STOPCOUNT_LENGTH 1ULL +#define CSR_DCSR_STOPCOUNT 0x400ULL /* * normal: Increment counters as usual. */ @@ -291,17 +344,20 @@ /* * An implementation may hardwire this bit to 0 or 1. */ -#define CSR_DCSR_STOPTIME_OFFSET 9 -#define CSR_DCSR_STOPTIME_LENGTH 1 -#define CSR_DCSR_STOPTIME 0x200 +#define CSR_DCSR_STOPTIME_OFFSET 9ULL +#define CSR_DCSR_STOPTIME_LENGTH 1ULL +#define CSR_DCSR_STOPTIME 0x200ULL /* - * normal: Increment \Rtime as usual. + * normal: \Rtime continues to reflect \Rmtime. */ #define CSR_DCSR_STOPTIME_NORMAL 0 /* - * freeze: Don't increment \Rtime while in Debug Mode. If all harts - * have \FcsrDcsrStoptime=1 and are in Debug Mode then \Rmtime - * is also allowed to stop incrementing. + * freeze: \Rtime is frozen at the time that Debug Mode was entered. When + * leaving Debug Mode, \Rtime will reflect the latest + * value of \Rmtime again. + * + * While all harts have \FcsrDcsrStoptime=1 and are in Debug Mode, + * \Rmtime is allowed to stop incrementing. */ #define CSR_DCSR_STOPTIME_FREEZE 1 /* @@ -314,9 +370,9 @@ * cycle, hardware should set \FcsrDcsrCause to the cause with the highest * priority. See table~\ref{tab:dcsrcausepriority} for priorities. */ -#define CSR_DCSR_CAUSE_OFFSET 6 -#define CSR_DCSR_CAUSE_LENGTH 3 -#define CSR_DCSR_CAUSE 0x1c0 +#define CSR_DCSR_CAUSE_OFFSET 6ULL +#define CSR_DCSR_CAUSE_LENGTH 3ULL +#define CSR_DCSR_CAUSE 0x1c0ULL /* * ebreak: An {\tt ebreak} instruction was executed. */ @@ -354,12 +410,12 @@ * when exiting Debug Mode. * This bit is hardwired to 0 on harts that do not support virtualization mode. */ -#define CSR_DCSR_V_OFFSET 5 -#define CSR_DCSR_V_LENGTH 1 -#define CSR_DCSR_V 0x20 -#define CSR_DCSR_MPRVEN_OFFSET 4 -#define CSR_DCSR_MPRVEN_LENGTH 1 -#define CSR_DCSR_MPRVEN 0x10 +#define CSR_DCSR_V_OFFSET 5ULL +#define CSR_DCSR_V_LENGTH 1ULL +#define CSR_DCSR_V 0x20ULL +#define CSR_DCSR_MPRVEN_OFFSET 4ULL +#define CSR_DCSR_MPRVEN_LENGTH 1ULL +#define CSR_DCSR_MPRVEN 0x10ULL /* * disabled: \FcsrMstatusMprv in \Rmstatus is ignored in Debug Mode. */ @@ -378,9 +434,9 @@ * reliable debugging may no longer be possible once this bit becomes set. * This is implementation-dependent. */ -#define CSR_DCSR_NMIP_OFFSET 3 -#define CSR_DCSR_NMIP_LENGTH 1 -#define CSR_DCSR_NMIP 8 +#define CSR_DCSR_NMIP_OFFSET 3ULL +#define CSR_DCSR_NMIP_LENGTH 1ULL +#define CSR_DCSR_NMIP 8ULL /* * When set and not in Debug Mode, the hart will only execute a single * instruction and then enter Debug Mode. See Section~\ref{stepBit} @@ -389,9 +445,9 @@ * The debugger must not change the value of this bit while the hart * is running. */ -#define CSR_DCSR_STEP_OFFSET 2 -#define CSR_DCSR_STEP_LENGTH 1 -#define CSR_DCSR_STEP 4 +#define CSR_DCSR_STEP_OFFSET 2ULL +#define CSR_DCSR_STEP_LENGTH 1ULL +#define CSR_DCSR_STEP 4ULL /* * Contains the privilege mode the hart was operating in when Debug * Mode was entered. The encoding is described in Table @@ -402,23 +458,29 @@ * encoding written is not supported or the debugger is not allowed to * change to it, the hart may change to any supported privilege mode. */ -#define CSR_DCSR_PRV_OFFSET 0 -#define CSR_DCSR_PRV_LENGTH 2 -#define CSR_DCSR_PRV 3 +#define CSR_DCSR_PRV_OFFSET 0ULL +#define CSR_DCSR_PRV_LENGTH 2ULL +#define CSR_DCSR_PRV 3ULL #define CSR_DPC 0x7b1 -#define CSR_DPC_DPC_OFFSET 0 -#define CSR_DPC_DPC_LENGTH(DXLEN) DXLEN -#define CSR_DPC_DPC(DXLEN) ((1ULL<<DXLEN) + -1) +#define CSR_DPC_DPC_OFFSET 0ULL +#define CSR_DPC_DPC_LENGTH(DXLEN) (DXLEN) +#define CSR_DPC_DPC(DXLEN) ((1ULL << (DXLEN)) + -1ULL) #define CSR_DSCRATCH0 0x7b2 +#define CSR_DSCRATCH0_DSCRATCH0_OFFSET 0ULL +#define CSR_DSCRATCH0_DSCRATCH0_LENGTH(DXLEN) (DXLEN) +#define CSR_DSCRATCH0_DSCRATCH0(DXLEN) ((1ULL << (DXLEN)) + -1ULL) #define CSR_DSCRATCH1 0x7b3 +#define CSR_DSCRATCH1_DSCRATCH1_OFFSET 0ULL +#define CSR_DSCRATCH1_DSCRATCH1_LENGTH(DXLEN) (DXLEN) +#define CSR_DSCRATCH1_DSCRATCH1(DXLEN) ((1ULL << (DXLEN)) + -1ULL) #define CSR_TSELECT 0x7a0 -#define CSR_TSELECT_INDEX_OFFSET 0 -#define CSR_TSELECT_INDEX_LENGTH(XLEN) XLEN -#define CSR_TSELECT_INDEX(XLEN) ((1ULL<<XLEN) + -1) +#define CSR_TSELECT_INDEX_OFFSET 0ULL +#define CSR_TSELECT_INDEX_LENGTH(XLEN) (XLEN) +#define CSR_TSELECT_INDEX(XLEN) ((1ULL << (XLEN)) + -1ULL) #define CSR_TDATA1 0x7a1 -#define CSR_TDATA1_TYPE_OFFSET(XLEN) (XLEN + -4) -#define CSR_TDATA1_TYPE_LENGTH 4 -#define CSR_TDATA1_TYPE(XLEN) (0xf * (1ULL<<(XLEN + -4))) +#define CSR_TDATA1_TYPE_OFFSET(XLEN) ((XLEN) + -4ULL) +#define CSR_TDATA1_TYPE_LENGTH 4ULL +#define CSR_TDATA1_TYPE(XLEN) (0xfULL * (1ULL << ((XLEN) + -4ULL))) /* * none: There is no trigger at this \RcsrTselect. */ @@ -468,8 +530,9 @@ /* * disabled: This trigger is disabled. In this state, \RcsrTdataTwo and * \RcsrTdataThree can be written with any value that is supported for - * any of the types this trigger implements. The remaining bits in this - * register are ignored. + * any of the types this trigger implements. + * The remaining bits in this register, except for \FcsrTdataOneDmode, + * are ignored. */ #define CSR_TDATA1_TYPE_DISABLED 15 /* @@ -478,9 +541,9 @@ /* * If \FcsrTdataOneType is 0, then this bit is hard-wired to 0. */ -#define CSR_TDATA1_DMODE_OFFSET(XLEN) (XLEN + -5) -#define CSR_TDATA1_DMODE_LENGTH 1 -#define CSR_TDATA1_DMODE(XLEN) (1ULL<<(XLEN + -5)) +#define CSR_TDATA1_DMODE_OFFSET(XLEN) ((XLEN) + -5ULL) +#define CSR_TDATA1_DMODE_LENGTH 1ULL +#define CSR_TDATA1_DMODE(XLEN) (1ULL << ((XLEN) + -5ULL)) /* * both: Both Debug and M-mode can write the {\tt tdata} registers at the * selected \RcsrTselect. @@ -504,18 +567,43 @@ * * Trigger-specific data. */ -#define CSR_TDATA1_DATA_OFFSET 0 -#define CSR_TDATA1_DATA_LENGTH(XLEN) (XLEN + -5) -#define CSR_TDATA1_DATA(XLEN) ((1ULL<<(XLEN + -5)) + -1) +#define CSR_TDATA1_DATA_OFFSET 0ULL +#define CSR_TDATA1_DATA_LENGTH(XLEN) ((XLEN) + -5ULL) +#define CSR_TDATA1_DATA(XLEN) ((1ULL << ((XLEN) + -5ULL)) + -1ULL) #define CSR_TDATA2 0x7a2 -#define CSR_TDATA2_DATA_OFFSET 0 -#define CSR_TDATA2_DATA_LENGTH(XLEN) XLEN -#define CSR_TDATA2_DATA(XLEN) ((1ULL<<XLEN) + -1) +#define CSR_TDATA2_DATA_OFFSET 0ULL +#define CSR_TDATA2_DATA_LENGTH(XLEN) (XLEN) +#define CSR_TDATA2_DATA(XLEN) ((1ULL << (XLEN)) + -1ULL) #define CSR_TDATA3 0x7a3 -#define CSR_TDATA3_DATA_OFFSET 0 -#define CSR_TDATA3_DATA_LENGTH(XLEN) XLEN -#define CSR_TDATA3_DATA(XLEN) ((1ULL<<XLEN) + -1) +#define CSR_TDATA3_DATA_OFFSET 0ULL +#define CSR_TDATA3_DATA_LENGTH(XLEN) (XLEN) +#define CSR_TDATA3_DATA(XLEN) ((1ULL << (XLEN)) + -1ULL) #define CSR_TINFO 0x7a4 +/* + * Contains the version of the Sdtrig extension implemented. + */ +#define CSR_TINFO_VERSION_OFFSET 0x18ULL +#define CSR_TINFO_VERSION_LENGTH 8ULL +#define CSR_TINFO_VERSION 0xff000000ULL +/* + * 0: Supports triggers as described in this spec at commit 5a5c078, + * made on February 2, 2023. + * + * \begin{steps}{In these older versions:} + * \item \RcsrMcontrolSix has a timing bit identical to + * \FcsrMcontrolTiming + * \item \FcsrMcontrolSixHitZero behaves just as \FcsrMcontrolHit. + * \item \FcsrMcontrolSixHitOne is read-only 0. + * \item Encodings for \FcsrMcontrolSixSize for access sizes larger + * than 64 bits are different. + * \end{steps} + */ +#define CSR_TINFO_VERSION_0 0 +/* + * 1: Supports triggers as described in the ratified version 1.0 of + * this document. + */ +#define CSR_TINFO_VERSION_1 1 /* * One bit for each possible \FcsrTdataOneType enumerated in \RcsrTdataOne. Bit N * corresponds to type N. If the bit is set, then that type is @@ -524,9 +612,9 @@ * If the currently selected trigger doesn't exist, this field * contains 1. */ -#define CSR_TINFO_INFO_OFFSET 0 -#define CSR_TINFO_INFO_LENGTH 0x10 -#define CSR_TINFO_INFO 0xffff +#define CSR_TINFO_INFO_OFFSET 0ULL +#define CSR_TINFO_INFO_LENGTH 0x10ULL +#define CSR_TINFO_INFO 0xffffULL #define CSR_TCONTROL 0x7a5 /* * M-mode previous trigger enable field. @@ -535,18 +623,18 @@ * regarding triggers with action=0 firing in M-mode trap handlers. See * Section~\ref{sec:nativetrigger} for more details. * - * When a breakpoint trap into M-mode is taken, \FcsrTcontrolMpte is set to the value of + * When any trap into M-mode is taken, \FcsrTcontrolMpte is set to the value of * \FcsrTcontrolMte. */ -#define CSR_TCONTROL_MPTE_OFFSET 7 -#define CSR_TCONTROL_MPTE_LENGTH 1 -#define CSR_TCONTROL_MPTE 0x80 +#define CSR_TCONTROL_MPTE_OFFSET 7ULL +#define CSR_TCONTROL_MPTE_LENGTH 1ULL +#define CSR_TCONTROL_MPTE 0x80ULL /* * M-mode trigger enable field. */ -#define CSR_TCONTROL_MTE_OFFSET 3 -#define CSR_TCONTROL_MTE_LENGTH 1 -#define CSR_TCONTROL_MTE 8 +#define CSR_TCONTROL_MTE_OFFSET 3ULL +#define CSR_TCONTROL_MTE_LENGTH 1ULL +#define CSR_TCONTROL_MTE 8ULL /* * disabled: Triggers with action=0 do not match/fire while the hart is in M-mode. */ @@ -556,25 +644,10 @@ */ #define CSR_TCONTROL_MTE_ENABLED 1 /* - * When a breakpoint trap into M-mode is taken, \FcsrTcontrolMte is set to 0. When {\tt + * When any trap into M-mode is taken, \FcsrTcontrolMte is set to 0. When {\tt * mret} is executed, \FcsrTcontrolMte is set to the value of \FcsrTcontrolMpte. */ #define CSR_HCONTEXT 0x6a8 -/* - * Hypervisor mode software can write a context number to this register, - * which can be used to set triggers that only fire in that specific - * context. - * - * An implementation may tie any number of upper bits in this field to - * 0. If the H extension is not implemented, it's recommended to implement - * no more than 6 bits on RV32 and 13 on RV64 (as visible through the - * \RcsrMcontext register). If the H extension is implemented, - * it's recommended to implement no more than 7 bits on RV32 - * and 14 on RV64. - */ -#define CSR_HCONTEXT_HCONTEXT_OFFSET 0 -#define CSR_HCONTEXT_HCONTEXT_LENGTH(XLEN) XLEN -#define CSR_HCONTEXT_HCONTEXT(XLEN) ((1ULL<<XLEN) + -1) #define CSR_SCONTEXT 0x5a8 /* * Supervisor mode software can write a context number to this @@ -585,18 +658,33 @@ * 0. It's recommended to implement no more than 16 bits on RV32, and * 34 on RV64. */ -#define CSR_SCONTEXT_DATA_OFFSET 0 -#define CSR_SCONTEXT_DATA_LENGTH(XLEN) XLEN -#define CSR_SCONTEXT_DATA(XLEN) ((1ULL<<XLEN) + -1) +#define CSR_SCONTEXT_DATA_OFFSET 0ULL +#define CSR_SCONTEXT_DATA_LENGTH(XLEN) (XLEN) +#define CSR_SCONTEXT_DATA(XLEN) ((1ULL << (XLEN)) + -1ULL) #define CSR_MCONTEXT 0x7a8 +/* + * M-Mode or HS-Mode (using \RcsrHcontext) software can write a context + * number to this register, which can be used to set triggers that only + * fire in that specific context. + * + * An implementation may tie any number of upper bits in this field to + * 0. If the H extension is not implemented, it's recommended to implement + * no more than 6 bits on RV32 and 13 on RV64 (as visible through the + * \RcsrMcontext register). If the H extension is implemented, + * it's recommended to implement no more than 7 bits on RV32 + * and 14 on RV64. + */ +#define CSR_MCONTEXT_HCONTEXT_OFFSET 0ULL +#define CSR_MCONTEXT_HCONTEXT_LENGTH(XLEN) (XLEN) +#define CSR_MCONTEXT_HCONTEXT(XLEN) ((1ULL << (XLEN)) + -1ULL) #define CSR_MSCONTEXT 0x7aa #define CSR_MCONTROL 0x7a1 -#define CSR_MCONTROL_TYPE_OFFSET(XLEN) (XLEN + -4) -#define CSR_MCONTROL_TYPE_LENGTH 4 -#define CSR_MCONTROL_TYPE(XLEN) (0xf * (1ULL<<(XLEN + -4))) -#define CSR_MCONTROL_DMODE_OFFSET(XLEN) (XLEN + -5) -#define CSR_MCONTROL_DMODE_LENGTH 1 -#define CSR_MCONTROL_DMODE(XLEN) (1ULL<<(XLEN + -5)) +#define CSR_MCONTROL_TYPE_OFFSET(XLEN) ((XLEN) + -4ULL) +#define CSR_MCONTROL_TYPE_LENGTH 4ULL +#define CSR_MCONTROL_TYPE(XLEN) (0xfULL * (1ULL << ((XLEN) + -4ULL))) +#define CSR_MCONTROL_DMODE_OFFSET(XLEN) ((XLEN) + -5ULL) +#define CSR_MCONTROL_DMODE_LENGTH 1ULL +#define CSR_MCONTROL_DMODE(XLEN) (1ULL << ((XLEN) + -5ULL)) /* * Specifies the largest naturally aligned powers-of-two (NAPOT) range * supported by the hardware when \FcsrMcontrolMatch is 1. The value is the @@ -605,18 +693,18 @@ * A value of 63 corresponds to the maximum NAPOT range, which is * $2^{63}$ bytes in size. */ -#define CSR_MCONTROL_MASKMAX_OFFSET(XLEN) (XLEN + -0xb) -#define CSR_MCONTROL_MASKMAX_LENGTH 6 -#define CSR_MCONTROL_MASKMAX(XLEN) (0x3f * (1ULL<<(XLEN + -0xb))) +#define CSR_MCONTROL_MASKMAX_OFFSET(XLEN) ((XLEN) + -0xbULL) +#define CSR_MCONTROL_MASKMAX_LENGTH 6ULL +#define CSR_MCONTROL_MASKMAX(XLEN) (0x3fULL * (1ULL << ((XLEN) + -0xbULL))) /* * This field only exists when XLEN is at least 64. * It contains the 2 high bits of the access size. The low bits * come from \FcsrMcontrolSizelo. See \FcsrMcontrolSizelo for how this * is used. */ -#define CSR_MCONTROL_SIZEHI_OFFSET 0x15 -#define CSR_MCONTROL_SIZEHI_LENGTH 2 -#define CSR_MCONTROL_SIZEHI 0x600000 +#define CSR_MCONTROL_SIZEHI_OFFSET 0x15ULL +#define CSR_MCONTROL_SIZEHI_LENGTH 2ULL +#define CSR_MCONTROL_SIZEHI 0x600000ULL /* * If this bit is implemented then it must become set when this * trigger fires and may become set when this trigger matches. @@ -625,15 +713,15 @@ * trigger(s) matched. If the bit is not implemented, it is always 0 * and writing it has no effect. */ -#define CSR_MCONTROL_HIT_OFFSET 0x14 -#define CSR_MCONTROL_HIT_LENGTH 1 -#define CSR_MCONTROL_HIT 0x100000 +#define CSR_MCONTROL_HIT_OFFSET 0x14ULL +#define CSR_MCONTROL_HIT_LENGTH 1ULL +#define CSR_MCONTROL_HIT 0x100000ULL /* * This bit determines the contents of the XLEN-bit compare values. */ -#define CSR_MCONTROL_SELECT_OFFSET 0x13 -#define CSR_MCONTROL_SELECT_LENGTH 1 -#define CSR_MCONTROL_SELECT 0x80000 +#define CSR_MCONTROL_SELECT_OFFSET 0x13ULL +#define CSR_MCONTROL_SELECT_LENGTH 1ULL +#define CSR_MCONTROL_SELECT 0x80000ULL /* * address: There is at least one compare value and it contains the lowest * virtual address of the access. @@ -649,13 +737,13 @@ * Any bits beyond the size of the data access will contain 0. */ #define CSR_MCONTROL_SELECT_DATA 1 -#define CSR_MCONTROL_TIMING_OFFSET 0x12 -#define CSR_MCONTROL_TIMING_LENGTH 1 -#define CSR_MCONTROL_TIMING 0x40000 +#define CSR_MCONTROL_TIMING_OFFSET 0x12ULL +#define CSR_MCONTROL_TIMING_LENGTH 1ULL +#define CSR_MCONTROL_TIMING 0x40000ULL /* * before: The action for this trigger will be taken just before the - * instruction that triggered it is committed, but after all preceding - * instructions are committed. \Rxepc or \RcsrDpc (depending + * instruction that triggered it is retired, but after all preceding + * instructions are retired. \Rxepc or \RcsrDpc (depending * on \FcsrMcontrolAction) must be set to the virtual address of the * instruction that matched. * @@ -665,12 +753,16 @@ * though the load will not update its destination register. Debuggers * should consider this when setting such breakpoints on, for example, * memory-mapped I/O addresses. + * + * If an instruction matches this trigger and the instruction performs + * multiple memory accesses, it is \unspecified which memory accesses + * have completed before the trigger fires. */ #define CSR_MCONTROL_TIMING_BEFORE 0 /* * after: The action for this trigger will be taken after the instruction - * that triggered it is committed. It should be taken before the next - * instruction is committed, but it is better to implement triggers imprecisely + * that triggered it is retired. It should be taken before the next + * instruction is retired, but it is better to implement triggers imprecisely * than to not implement them at all. \Rxepc or * \RcsrDpc (depending on \FcsrMcontrolAction) must be set to * the virtual address of the next instruction that must be executed to @@ -698,9 +790,9 @@ * This field contains the 2 low bits of the access size. The high bits come * from \FcsrMcontrolSizehi. The combined value is interpreted as follows: */ -#define CSR_MCONTROL_SIZELO_OFFSET 0x10 -#define CSR_MCONTROL_SIZELO_LENGTH 2 -#define CSR_MCONTROL_SIZELO 0x30000 +#define CSR_MCONTROL_SIZELO_OFFSET 0x10ULL +#define CSR_MCONTROL_SIZELO_LENGTH 2ULL +#define CSR_MCONTROL_SIZELO 0x30000ULL /* * any: The trigger will attempt to match against an access of any size. * The behavior is only well-defined if $|select|=0$, or if the access @@ -769,9 +861,9 @@ * The action to take when the trigger fires. The values are explained * in Table~\ref{tab:action}. */ -#define CSR_MCONTROL_ACTION_OFFSET 0xc -#define CSR_MCONTROL_ACTION_LENGTH 4 -#define CSR_MCONTROL_ACTION 0xf000 +#define CSR_MCONTROL_ACTION_OFFSET 0xcULL +#define CSR_MCONTROL_ACTION_LENGTH 4ULL +#define CSR_MCONTROL_ACTION 0xf000ULL /* * breakpoint: */ @@ -800,9 +892,9 @@ * external1: */ #define CSR_MCONTROL_ACTION_EXTERNAL1 9 -#define CSR_MCONTROL_CHAIN_OFFSET 0xb -#define CSR_MCONTROL_CHAIN_LENGTH 1 -#define CSR_MCONTROL_CHAIN 0x800 +#define CSR_MCONTROL_CHAIN_OFFSET 0xbULL +#define CSR_MCONTROL_CHAIN_LENGTH 1ULL +#define CSR_MCONTROL_CHAIN 0x800ULL /* * disabled: When this trigger matches, the configured action is taken. */ @@ -836,9 +928,9 @@ * chain (eg. to meet timing requirements) may do so by zeroing * \FcsrMcontrolChain in writes to \RcsrMcontrol that would make the chain too long. */ -#define CSR_MCONTROL_MATCH_OFFSET 7 -#define CSR_MCONTROL_MATCH_LENGTH 4 -#define CSR_MCONTROL_MATCH 0x780 +#define CSR_MCONTROL_MATCH_OFFSET 7ULL +#define CSR_MCONTROL_MATCH_LENGTH 4ULL +#define CSR_MCONTROL_MATCH 0x780ULL /* * equal: Matches when any compare value equals \RcsrTdataTwo. */ @@ -905,86 +997,142 @@ /* * When set, enable this trigger in M-mode. */ -#define CSR_MCONTROL_M_OFFSET 6 -#define CSR_MCONTROL_M_LENGTH 1 -#define CSR_MCONTROL_M 0x40 +#define CSR_MCONTROL_M_OFFSET 6ULL +#define CSR_MCONTROL_M_LENGTH 1ULL +#define CSR_MCONTROL_M 0x40ULL /* * When set, enable this trigger in S/HS-mode. * This bit is hard-wired to 0 if the hart does not support * S-mode. */ -#define CSR_MCONTROL_S_OFFSET 4 -#define CSR_MCONTROL_S_LENGTH 1 -#define CSR_MCONTROL_S 0x10 +#define CSR_MCONTROL_S_OFFSET 4ULL +#define CSR_MCONTROL_S_LENGTH 1ULL +#define CSR_MCONTROL_S 0x10ULL /* * When set, enable this trigger in U-mode. * This bit is hard-wired to 0 if the hart does not support * U-mode. */ -#define CSR_MCONTROL_U_OFFSET 3 -#define CSR_MCONTROL_U_LENGTH 1 -#define CSR_MCONTROL_U 8 +#define CSR_MCONTROL_U_OFFSET 3ULL +#define CSR_MCONTROL_U_LENGTH 1ULL +#define CSR_MCONTROL_U 8ULL /* * When set, the trigger fires on the virtual address or opcode of an * instruction that is executed. */ -#define CSR_MCONTROL_EXECUTE_OFFSET 2 -#define CSR_MCONTROL_EXECUTE_LENGTH 1 -#define CSR_MCONTROL_EXECUTE 4 +#define CSR_MCONTROL_EXECUTE_OFFSET 2ULL +#define CSR_MCONTROL_EXECUTE_LENGTH 1ULL +#define CSR_MCONTROL_EXECUTE 4ULL /* * When set, the trigger fires on the virtual address or data of any * store. */ -#define CSR_MCONTROL_STORE_OFFSET 1 -#define CSR_MCONTROL_STORE_LENGTH 1 -#define CSR_MCONTROL_STORE 2 +#define CSR_MCONTROL_STORE_OFFSET 1ULL +#define CSR_MCONTROL_STORE_LENGTH 1ULL +#define CSR_MCONTROL_STORE 2ULL /* * When set, the trigger fires on the virtual address or data of any * load. */ -#define CSR_MCONTROL_LOAD_OFFSET 0 -#define CSR_MCONTROL_LOAD_LENGTH 1 -#define CSR_MCONTROL_LOAD 1 +#define CSR_MCONTROL_LOAD_OFFSET 0ULL +#define CSR_MCONTROL_LOAD_LENGTH 1ULL +#define CSR_MCONTROL_LOAD 1ULL #define CSR_MCONTROL6 0x7a1 -#define CSR_MCONTROL6_TYPE_OFFSET(XLEN) (XLEN + -4) -#define CSR_MCONTROL6_TYPE_LENGTH 4 -#define CSR_MCONTROL6_TYPE(XLEN) (0xf * (1ULL<<(XLEN + -4))) -#define CSR_MCONTROL6_DMODE_OFFSET(XLEN) (XLEN + -5) -#define CSR_MCONTROL6_DMODE_LENGTH 1 -#define CSR_MCONTROL6_DMODE(XLEN) (1ULL<<(XLEN + -5)) +#define CSR_MCONTROL6_TYPE_OFFSET(XLEN) ((XLEN) + -4ULL) +#define CSR_MCONTROL6_TYPE_LENGTH 4ULL +#define CSR_MCONTROL6_TYPE(XLEN) (0xfULL * (1ULL << ((XLEN) + -4ULL))) +#define CSR_MCONTROL6_DMODE_OFFSET(XLEN) ((XLEN) + -5ULL) +#define CSR_MCONTROL6_DMODE_LENGTH 1ULL +#define CSR_MCONTROL6_DMODE(XLEN) (1ULL << ((XLEN) + -5ULL)) +/* + * If implemented, the TM updates this field every time the trigger + * fires. + */ +#define CSR_MCONTROL6_UNCERTAIN_OFFSET 0x1aULL +#define CSR_MCONTROL6_UNCERTAIN_LENGTH 1ULL +#define CSR_MCONTROL6_UNCERTAIN 0x4000000ULL +/* + * certain: The trigger that fired satisfied the configured conditions, or + * this bit is not implemented. + */ +#define CSR_MCONTROL6_UNCERTAIN_CERTAIN 0 +/* + * uncertain: The trigger that fired might not have perfectly satisfied the + * configured conditions. Due to the implementation the hardware + * cannot be certain. + */ +#define CSR_MCONTROL6_UNCERTAIN_UNCERTAIN 1 +#define CSR_MCONTROL6_HIT1_OFFSET 0x19ULL +#define CSR_MCONTROL6_HIT1_LENGTH 1ULL +#define CSR_MCONTROL6_HIT1 0x2000000ULL /* * When set, enable this trigger in VS-mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ -#define CSR_MCONTROL6_VS_OFFSET 0x18 -#define CSR_MCONTROL6_VS_LENGTH 1 -#define CSR_MCONTROL6_VS 0x1000000 +#define CSR_MCONTROL6_VS_OFFSET 0x18ULL +#define CSR_MCONTROL6_VS_LENGTH 1ULL +#define CSR_MCONTROL6_VS 0x1000000ULL /* * When set, enable this trigger in VU-mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ -#define CSR_MCONTROL6_VU_OFFSET 0x17 -#define CSR_MCONTROL6_VU_LENGTH 1 -#define CSR_MCONTROL6_VU 0x800000 +#define CSR_MCONTROL6_VU_OFFSET 0x17ULL +#define CSR_MCONTROL6_VU_LENGTH 1ULL +#define CSR_MCONTROL6_VU 0x800000ULL /* - * If this bit is implemented then it must become set when this - * trigger fires and may become set when this trigger matches. - * The trigger's user can set or clear it at any - * time. It is used to determine which - * trigger(s) matched. If the bit is not implemented, it is always 0 - * and writing it has no effect. + * If they are implemented, \FcsrMcontrolSixHitOne (MSB) and + * \FcsrMcontrolSixHitZero (LSB) combine into a single 2-bit field. + * The TM updates this field when the trigger fires. After the debugger + * has seen the update, it will normally write 0 to this field to so it + * can see future changes. + * + * If either of the bits is not implemented, the unimplemented bits + * will be read-only 0. + */ +#define CSR_MCONTROL6_HIT0_OFFSET 0x16ULL +#define CSR_MCONTROL6_HIT0_LENGTH 1ULL +#define CSR_MCONTROL6_HIT0 0x400000ULL +/* + * false: The trigger did not fire. + */ +#define CSR_MCONTROL6_HIT0_FALSE 0 +/* + * before: The trigger fired before the instruction that matched it was + * retired, but after all preceding instructions are retired. This + * explicitly allows for instructions to be partially executed, as + * described in Section \ref{sec:multistate}. + * + * \Rxepc or \RcsrDpc (depending on \FcsrMcontrolSixAction) must be set + * to the virtual address of the instruction that matched. + */ +#define CSR_MCONTROL6_HIT0_BEFORE 1 +/* + * after: The trigger fired after the instruction that triggered and at least + * one additional instruction were retired. + * \Rxepc or \RcsrDpc (depending on \FcsrMcontrolSixAction) must be set + * to the virtual address of the next instruction that must be executed + * to preserve the program flow. + */ +#define CSR_MCONTROL6_HIT0_AFTER 2 +/* + * immediately after: The trigger fired just after the instruction that triggered it was + * retired, but before any subsequent instructions were executed. + * \Rxepc or \RcsrDpc (depending on \FcsrMcontrolSixAction) must be set + * to the virtual address of the next instruction that must be executed + * to preserve the program flow. + * + * If the instruction performed multiple memory accesses, all of them + * have been completed. */ -#define CSR_MCONTROL6_HIT_OFFSET 0x16 -#define CSR_MCONTROL6_HIT_LENGTH 1 -#define CSR_MCONTROL6_HIT 0x400000 +#define CSR_MCONTROL6_HIT0_IMMEDIATELY_AFTER 3 /* * This bit determines the contents of the XLEN-bit compare values. */ -#define CSR_MCONTROL6_SELECT_OFFSET 0x15 -#define CSR_MCONTROL6_SELECT_LENGTH 1 -#define CSR_MCONTROL6_SELECT 0x200000 +#define CSR_MCONTROL6_SELECT_OFFSET 0x15ULL +#define CSR_MCONTROL6_SELECT_LENGTH 1ULL +#define CSR_MCONTROL6_SELECT 0x200000ULL /* * address: There is at least one compare value and it contains the lowest * virtual address of the access. @@ -1000,54 +1148,9 @@ * Any bits beyond the size of the data access will contain 0. */ #define CSR_MCONTROL6_SELECT_DATA 1 -#define CSR_MCONTROL6_TIMING_OFFSET 0x14 -#define CSR_MCONTROL6_TIMING_LENGTH 1 -#define CSR_MCONTROL6_TIMING 0x100000 -/* - * before: The action for this trigger will be taken just before the - * instruction that triggered it is committed, but after all preceding - * instructions are committed. \Rxepc or \RcsrDpc (depending - * on \FcsrMcontrolSixAction) must be set to the virtual address of the - * instruction that matched. - * - * If this is combined with \FcsrMcontrolSixLoad and - * \FcsrMcontrolSixSelect=1 then a memory access will be - * performed (including any side effects of performing such an access) even - * though the load will not update its destination register. Debuggers - * should consider this when setting such breakpoints on, for example, - * memory-mapped I/O addresses. - */ -#define CSR_MCONTROL6_TIMING_BEFORE 0 -/* - * after: The action for this trigger will be taken after the instruction - * that triggered it is committed. It should be taken before the next - * instruction is committed, but it is better to implement triggers imprecisely - * than to not implement them at all. \Rxepc or - * \RcsrDpc (depending on \FcsrMcontrolSixAction) must be set to - * the virtual address of the next instruction that must be executed to - * preserve the program flow. - */ -#define CSR_MCONTROL6_TIMING_AFTER 1 -/* - * Most hardware will only implement one timing or the other, possibly - * dependent on \FcsrMcontrolSixSelect, \FcsrMcontrolSixExecute, - * \FcsrMcontrolSixLoad, and \FcsrMcontrolSixStore. This bit - * primarily exists for the hardware to communicate to the debugger - * what will happen. Hardware may implement the bit fully writable, in - * which case the debugger has a little more control. - * - * Data load triggers with \FcsrMcontrolSixTiming of 0 will result in the same load - * happening again when the debugger lets the hart run. For data load - * triggers, debuggers must first attempt to set the breakpoint with - * \FcsrMcontrolSixTiming of 1. - * - * If a trigger with \FcsrMcontrolSixTiming of 0 matches, it is - * implementation-dependent whether that prevents a trigger with - * \FcsrMcontrolSixTiming of 1 matching as well. - */ -#define CSR_MCONTROL6_SIZE_OFFSET 0x10 -#define CSR_MCONTROL6_SIZE_LENGTH 4 -#define CSR_MCONTROL6_SIZE 0xf0000 +#define CSR_MCONTROL6_SIZE_OFFSET 0x10ULL +#define CSR_MCONTROL6_SIZE_LENGTH 3ULL +#define CSR_MCONTROL6_SIZE 0x70000ULL /* * any: The trigger will attempt to match against an access of any size. * The behavior is only well-defined if $|select|=0$, or if the access @@ -1077,23 +1180,11 @@ * execution of 64-bit instructions. */ #define CSR_MCONTROL6_SIZE_64BIT 5 -/* - * 80bit: The trigger will only match against execution of 80-bit instructions. - */ -#define CSR_MCONTROL6_SIZE_80BIT 6 -/* - * 96bit: The trigger will only match against execution of 96-bit instructions. - */ -#define CSR_MCONTROL6_SIZE_96BIT 7 -/* - * 112bit: The trigger will only match against execution of 112-bit instructions. - */ -#define CSR_MCONTROL6_SIZE_112BIT 8 /* * 128bit: The trigger will only match against 128-bit memory accesses or * execution of 128-bit instructions. */ -#define CSR_MCONTROL6_SIZE_128BIT 9 +#define CSR_MCONTROL6_SIZE_128BIT 6 /* * An implementation must support the value of 0, but all other values * are optional. When an implementation supports address triggers @@ -1116,9 +1207,9 @@ * The action to take when the trigger fires. The values are explained * in Table~\ref{tab:action}. */ -#define CSR_MCONTROL6_ACTION_OFFSET 0xc -#define CSR_MCONTROL6_ACTION_LENGTH 4 -#define CSR_MCONTROL6_ACTION 0xf000 +#define CSR_MCONTROL6_ACTION_OFFSET 0xcULL +#define CSR_MCONTROL6_ACTION_LENGTH 4ULL +#define CSR_MCONTROL6_ACTION 0xf000ULL /* * breakpoint: */ @@ -1147,9 +1238,9 @@ * external1: */ #define CSR_MCONTROL6_ACTION_EXTERNAL1 9 -#define CSR_MCONTROL6_CHAIN_OFFSET 0xb -#define CSR_MCONTROL6_CHAIN_LENGTH 1 -#define CSR_MCONTROL6_CHAIN 0x800 +#define CSR_MCONTROL6_CHAIN_OFFSET 0xbULL +#define CSR_MCONTROL6_CHAIN_LENGTH 1ULL +#define CSR_MCONTROL6_CHAIN 0x800ULL /* * disabled: When this trigger matches, the configured action is taken. */ @@ -1183,9 +1274,9 @@ * chain (eg. to meet timing requirements) may do so by zeroing * \FcsrMcontrolSixChain in writes to \RcsrMcontrolSix that would make the chain too long. */ -#define CSR_MCONTROL6_MATCH_OFFSET 7 -#define CSR_MCONTROL6_MATCH_LENGTH 4 -#define CSR_MCONTROL6_MATCH 0x780 +#define CSR_MCONTROL6_MATCH_OFFSET 7ULL +#define CSR_MCONTROL6_MATCH_LENGTH 4ULL +#define CSR_MCONTROL6_MATCH 0x780ULL /* * equal: Matches when any compare value equals \RcsrTdataTwo. */ @@ -1254,69 +1345,83 @@ /* * When set, enable this trigger in M-mode. */ -#define CSR_MCONTROL6_M_OFFSET 6 -#define CSR_MCONTROL6_M_LENGTH 1 -#define CSR_MCONTROL6_M 0x40 +#define CSR_MCONTROL6_M_OFFSET 6ULL +#define CSR_MCONTROL6_M_LENGTH 1ULL +#define CSR_MCONTROL6_M 0x40ULL +#define CSR_MCONTROL6_UNCERTAINEN_OFFSET 5ULL +#define CSR_MCONTROL6_UNCERTAINEN_LENGTH 1ULL +#define CSR_MCONTROL6_UNCERTAINEN 0x20ULL +/* + * disabled: This trigger will only match if the hardware can perfectly + * evaluate it. + */ +#define CSR_MCONTROL6_UNCERTAINEN_DISABLED 0 +/* + * enabled: This trigger will match if it's possible that it would match if + * the Trigger Module had perfect information about the operations + * being performed. + */ +#define CSR_MCONTROL6_UNCERTAINEN_ENABLED 1 /* * When set, enable this trigger in S/HS-mode. * This bit is hard-wired to 0 if the hart does not support * S-mode. */ -#define CSR_MCONTROL6_S_OFFSET 4 -#define CSR_MCONTROL6_S_LENGTH 1 -#define CSR_MCONTROL6_S 0x10 +#define CSR_MCONTROL6_S_OFFSET 4ULL +#define CSR_MCONTROL6_S_LENGTH 1ULL +#define CSR_MCONTROL6_S 0x10ULL /* * When set, enable this trigger in U-mode. * This bit is hard-wired to 0 if the hart does not support * U-mode. */ -#define CSR_MCONTROL6_U_OFFSET 3 -#define CSR_MCONTROL6_U_LENGTH 1 -#define CSR_MCONTROL6_U 8 +#define CSR_MCONTROL6_U_OFFSET 3ULL +#define CSR_MCONTROL6_U_LENGTH 1ULL +#define CSR_MCONTROL6_U 8ULL /* * When set, the trigger fires on the virtual address or opcode of an * instruction that is executed. */ -#define CSR_MCONTROL6_EXECUTE_OFFSET 2 -#define CSR_MCONTROL6_EXECUTE_LENGTH 1 -#define CSR_MCONTROL6_EXECUTE 4 +#define CSR_MCONTROL6_EXECUTE_OFFSET 2ULL +#define CSR_MCONTROL6_EXECUTE_LENGTH 1ULL +#define CSR_MCONTROL6_EXECUTE 4ULL /* * When set, the trigger fires on the virtual address or data of any * store. */ -#define CSR_MCONTROL6_STORE_OFFSET 1 -#define CSR_MCONTROL6_STORE_LENGTH 1 -#define CSR_MCONTROL6_STORE 2 +#define CSR_MCONTROL6_STORE_OFFSET 1ULL +#define CSR_MCONTROL6_STORE_LENGTH 1ULL +#define CSR_MCONTROL6_STORE 2ULL /* * When set, the trigger fires on the virtual address or data of any * load. */ -#define CSR_MCONTROL6_LOAD_OFFSET 0 -#define CSR_MCONTROL6_LOAD_LENGTH 1 -#define CSR_MCONTROL6_LOAD 1 +#define CSR_MCONTROL6_LOAD_OFFSET 0ULL +#define CSR_MCONTROL6_LOAD_LENGTH 1ULL +#define CSR_MCONTROL6_LOAD 1ULL #define CSR_ICOUNT 0x7a1 -#define CSR_ICOUNT_TYPE_OFFSET(XLEN) (XLEN + -4) -#define CSR_ICOUNT_TYPE_LENGTH 4 -#define CSR_ICOUNT_TYPE(XLEN) (0xf * (1ULL<<(XLEN + -4))) -#define CSR_ICOUNT_DMODE_OFFSET(XLEN) (XLEN + -5) -#define CSR_ICOUNT_DMODE_LENGTH 1 -#define CSR_ICOUNT_DMODE(XLEN) (1ULL<<(XLEN + -5)) +#define CSR_ICOUNT_TYPE_OFFSET(XLEN) ((XLEN) + -4ULL) +#define CSR_ICOUNT_TYPE_LENGTH 4ULL +#define CSR_ICOUNT_TYPE(XLEN) (0xfULL * (1ULL << ((XLEN) + -4ULL))) +#define CSR_ICOUNT_DMODE_OFFSET(XLEN) ((XLEN) + -5ULL) +#define CSR_ICOUNT_DMODE_LENGTH 1ULL +#define CSR_ICOUNT_DMODE(XLEN) (1ULL << ((XLEN) + -5ULL)) /* * When set, enable this trigger in VS-mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ -#define CSR_ICOUNT_VS_OFFSET 0x1a -#define CSR_ICOUNT_VS_LENGTH 1 -#define CSR_ICOUNT_VS 0x4000000 +#define CSR_ICOUNT_VS_OFFSET 0x1aULL +#define CSR_ICOUNT_VS_LENGTH 1ULL +#define CSR_ICOUNT_VS 0x4000000ULL /* * When set, enable this trigger in VU-mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ -#define CSR_ICOUNT_VU_OFFSET 0x19 -#define CSR_ICOUNT_VU_LENGTH 1 -#define CSR_ICOUNT_VU 0x2000000 +#define CSR_ICOUNT_VU_OFFSET 0x19ULL +#define CSR_ICOUNT_VU_LENGTH 1ULL +#define CSR_ICOUNT_VU 0x2000000ULL /* * If this bit is implemented, the hardware sets it when this * trigger fires. The trigger's user can set or clear it at any @@ -1324,53 +1429,53 @@ * trigger(s) fires. If the bit is not implemented, it is always 0 * and writing it has no effect. */ -#define CSR_ICOUNT_HIT_OFFSET 0x18 -#define CSR_ICOUNT_HIT_LENGTH 1 -#define CSR_ICOUNT_HIT 0x1000000 +#define CSR_ICOUNT_HIT_OFFSET 0x18ULL +#define CSR_ICOUNT_HIT_LENGTH 1ULL +#define CSR_ICOUNT_HIT 0x1000000ULL /* * The trigger will generally fire after \FcsrIcountCount instructions * in enabled modes have been executed. See above for the precise behavior. */ -#define CSR_ICOUNT_COUNT_OFFSET 0xa -#define CSR_ICOUNT_COUNT_LENGTH 0xe -#define CSR_ICOUNT_COUNT 0xfffc00 +#define CSR_ICOUNT_COUNT_OFFSET 0xaULL +#define CSR_ICOUNT_COUNT_LENGTH 0xeULL +#define CSR_ICOUNT_COUNT 0xfffc00ULL /* * When set, enable this trigger in M-mode. */ -#define CSR_ICOUNT_M_OFFSET 9 -#define CSR_ICOUNT_M_LENGTH 1 -#define CSR_ICOUNT_M 0x200 +#define CSR_ICOUNT_M_OFFSET 9ULL +#define CSR_ICOUNT_M_LENGTH 1ULL +#define CSR_ICOUNT_M 0x200ULL /* * This bit becomes set when \FcsrIcountCount is decremented from 1 * to 0. It is cleared when the trigger fires, which will happen just * before executing the next instruction in one of the enabled modes. */ -#define CSR_ICOUNT_PENDING_OFFSET 8 -#define CSR_ICOUNT_PENDING_LENGTH 1 -#define CSR_ICOUNT_PENDING 0x100 +#define CSR_ICOUNT_PENDING_OFFSET 8ULL +#define CSR_ICOUNT_PENDING_LENGTH 1ULL +#define CSR_ICOUNT_PENDING 0x100ULL /* * When set, enable this trigger in S/HS-mode. * This bit is hard-wired to 0 if the hart does not support * S-mode. */ -#define CSR_ICOUNT_S_OFFSET 7 -#define CSR_ICOUNT_S_LENGTH 1 -#define CSR_ICOUNT_S 0x80 +#define CSR_ICOUNT_S_OFFSET 7ULL +#define CSR_ICOUNT_S_LENGTH 1ULL +#define CSR_ICOUNT_S 0x80ULL /* * When set, enable this trigger in U-mode. * This bit is hard-wired to 0 if the hart does not support * U-mode. */ -#define CSR_ICOUNT_U_OFFSET 6 -#define CSR_ICOUNT_U_LENGTH 1 -#define CSR_ICOUNT_U 0x40 +#define CSR_ICOUNT_U_OFFSET 6ULL +#define CSR_ICOUNT_U_LENGTH 1ULL +#define CSR_ICOUNT_U 0x40ULL /* * The action to take when the trigger fires. The values are explained * in Table~\ref{tab:action}. */ -#define CSR_ICOUNT_ACTION_OFFSET 0 -#define CSR_ICOUNT_ACTION_LENGTH 6 -#define CSR_ICOUNT_ACTION 0x3f +#define CSR_ICOUNT_ACTION_OFFSET 0ULL +#define CSR_ICOUNT_ACTION_LENGTH 6ULL +#define CSR_ICOUNT_ACTION 0x3fULL /* * breakpoint: */ @@ -1400,12 +1505,12 @@ */ #define CSR_ICOUNT_ACTION_EXTERNAL1 9 #define CSR_ITRIGGER 0x7a1 -#define CSR_ITRIGGER_TYPE_OFFSET(XLEN) (XLEN + -4) -#define CSR_ITRIGGER_TYPE_LENGTH 4 -#define CSR_ITRIGGER_TYPE(XLEN) (0xf * (1ULL<<(XLEN + -4))) -#define CSR_ITRIGGER_DMODE_OFFSET(XLEN) (XLEN + -5) -#define CSR_ITRIGGER_DMODE_LENGTH 1 -#define CSR_ITRIGGER_DMODE(XLEN) (1ULL<<(XLEN + -5)) +#define CSR_ITRIGGER_TYPE_OFFSET(XLEN) ((XLEN) + -4ULL) +#define CSR_ITRIGGER_TYPE_LENGTH 4ULL +#define CSR_ITRIGGER_TYPE(XLEN) (0xfULL * (1ULL << ((XLEN) + -4ULL))) +#define CSR_ITRIGGER_DMODE_OFFSET(XLEN) ((XLEN) + -5ULL) +#define CSR_ITRIGGER_DMODE_LENGTH 1ULL +#define CSR_ITRIGGER_DMODE(XLEN) (1ULL << ((XLEN) + -5ULL)) /* * If this bit is implemented, the hardware sets it when this * trigger matches. The trigger's user can set or clear it at any @@ -1413,66 +1518,66 @@ * trigger(s) matched. If the bit is not implemented, it is always 0 * and writing it has no effect. */ -#define CSR_ITRIGGER_HIT_OFFSET(XLEN) (XLEN + -6) -#define CSR_ITRIGGER_HIT_LENGTH 1 -#define CSR_ITRIGGER_HIT(XLEN) (1ULL<<(XLEN + -6)) +#define CSR_ITRIGGER_HIT_OFFSET(XLEN) ((XLEN) + -6ULL) +#define CSR_ITRIGGER_HIT_LENGTH 1ULL +#define CSR_ITRIGGER_HIT(XLEN) (1ULL << ((XLEN) + -6ULL)) /* * When set, enable this trigger for interrupts that are taken from VS * mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ -#define CSR_ITRIGGER_VS_OFFSET 0xc -#define CSR_ITRIGGER_VS_LENGTH 1 -#define CSR_ITRIGGER_VS 0x1000 +#define CSR_ITRIGGER_VS_OFFSET 0xcULL +#define CSR_ITRIGGER_VS_LENGTH 1ULL +#define CSR_ITRIGGER_VS 0x1000ULL /* * When set, enable this trigger for interrupts that are taken from VU * mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ -#define CSR_ITRIGGER_VU_OFFSET 0xb -#define CSR_ITRIGGER_VU_LENGTH 1 -#define CSR_ITRIGGER_VU 0x800 +#define CSR_ITRIGGER_VU_OFFSET 0xbULL +#define CSR_ITRIGGER_VU_LENGTH 1ULL +#define CSR_ITRIGGER_VU 0x800ULL /* * When set, non-maskable interrupts cause this * trigger to fire if the trigger is enabled for the current mode. */ -#define CSR_ITRIGGER_NMI_OFFSET 0xa -#define CSR_ITRIGGER_NMI_LENGTH 1 -#define CSR_ITRIGGER_NMI 0x400 +#define CSR_ITRIGGER_NMI_OFFSET 0xaULL +#define CSR_ITRIGGER_NMI_LENGTH 1ULL +#define CSR_ITRIGGER_NMI 0x400ULL /* * When set, enable this trigger for interrupts that are taken from M * mode. */ -#define CSR_ITRIGGER_M_OFFSET 9 -#define CSR_ITRIGGER_M_LENGTH 1 -#define CSR_ITRIGGER_M 0x200 +#define CSR_ITRIGGER_M_OFFSET 9ULL +#define CSR_ITRIGGER_M_LENGTH 1ULL +#define CSR_ITRIGGER_M 0x200ULL /* * When set, enable this trigger for interrupts that are taken from S/HS * mode. * This bit is hard-wired to 0 if the hart does not support * S-mode. */ -#define CSR_ITRIGGER_S_OFFSET 7 -#define CSR_ITRIGGER_S_LENGTH 1 -#define CSR_ITRIGGER_S 0x80 +#define CSR_ITRIGGER_S_OFFSET 7ULL +#define CSR_ITRIGGER_S_LENGTH 1ULL +#define CSR_ITRIGGER_S 0x80ULL /* * When set, enable this trigger for interrupts that are taken from U * mode. * This bit is hard-wired to 0 if the hart does not support * U-mode. */ -#define CSR_ITRIGGER_U_OFFSET 6 -#define CSR_ITRIGGER_U_LENGTH 1 -#define CSR_ITRIGGER_U 0x40 +#define CSR_ITRIGGER_U_OFFSET 6ULL +#define CSR_ITRIGGER_U_LENGTH 1ULL +#define CSR_ITRIGGER_U 0x40ULL /* * The action to take when the trigger fires. The values are explained * in Table~\ref{tab:action}. */ -#define CSR_ITRIGGER_ACTION_OFFSET 0 -#define CSR_ITRIGGER_ACTION_LENGTH 6 -#define CSR_ITRIGGER_ACTION 0x3f +#define CSR_ITRIGGER_ACTION_OFFSET 0ULL +#define CSR_ITRIGGER_ACTION_LENGTH 6ULL +#define CSR_ITRIGGER_ACTION 0x3fULL /* * breakpoint: */ @@ -1502,12 +1607,12 @@ */ #define CSR_ITRIGGER_ACTION_EXTERNAL1 9 #define CSR_ETRIGGER 0x7a1 -#define CSR_ETRIGGER_TYPE_OFFSET(XLEN) (XLEN + -4) -#define CSR_ETRIGGER_TYPE_LENGTH 4 -#define CSR_ETRIGGER_TYPE(XLEN) (0xf * (1ULL<<(XLEN + -4))) -#define CSR_ETRIGGER_DMODE_OFFSET(XLEN) (XLEN + -5) -#define CSR_ETRIGGER_DMODE_LENGTH 1 -#define CSR_ETRIGGER_DMODE(XLEN) (1ULL<<(XLEN + -5)) +#define CSR_ETRIGGER_TYPE_OFFSET(XLEN) ((XLEN) + -4ULL) +#define CSR_ETRIGGER_TYPE_LENGTH 4ULL +#define CSR_ETRIGGER_TYPE(XLEN) (0xfULL * (1ULL << ((XLEN) + -4ULL))) +#define CSR_ETRIGGER_DMODE_OFFSET(XLEN) ((XLEN) + -5ULL) +#define CSR_ETRIGGER_DMODE_LENGTH 1ULL +#define CSR_ETRIGGER_DMODE(XLEN) (1ULL << ((XLEN) + -5ULL)) /* * If this bit is implemented, the hardware sets it when this * trigger matches. The trigger's user can set or clear it at any @@ -1515,59 +1620,59 @@ * trigger(s) matched. If the bit is not implemented, it is always 0 * and writing it has no effect. */ -#define CSR_ETRIGGER_HIT_OFFSET(XLEN) (XLEN + -6) -#define CSR_ETRIGGER_HIT_LENGTH 1 -#define CSR_ETRIGGER_HIT(XLEN) (1ULL<<(XLEN + -6)) +#define CSR_ETRIGGER_HIT_OFFSET(XLEN) ((XLEN) + -6ULL) +#define CSR_ETRIGGER_HIT_LENGTH 1ULL +#define CSR_ETRIGGER_HIT(XLEN) (1ULL << ((XLEN) + -6ULL)) /* * When set, enable this trigger for exceptions that are taken from VS * mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ -#define CSR_ETRIGGER_VS_OFFSET 0xc -#define CSR_ETRIGGER_VS_LENGTH 1 -#define CSR_ETRIGGER_VS 0x1000 +#define CSR_ETRIGGER_VS_OFFSET 0xcULL +#define CSR_ETRIGGER_VS_LENGTH 1ULL +#define CSR_ETRIGGER_VS 0x1000ULL /* * When set, enable this trigger for exceptions that are taken from VU * mode. * This bit is hard-wired to 0 if the hart does not support * virtualization mode. */ -#define CSR_ETRIGGER_VU_OFFSET 0xb -#define CSR_ETRIGGER_VU_LENGTH 1 -#define CSR_ETRIGGER_VU 0x800 +#define CSR_ETRIGGER_VU_OFFSET 0xbULL +#define CSR_ETRIGGER_VU_LENGTH 1ULL +#define CSR_ETRIGGER_VU 0x800ULL /* * When set, enable this trigger for exceptions that are taken from M * mode. */ -#define CSR_ETRIGGER_M_OFFSET 9 -#define CSR_ETRIGGER_M_LENGTH 1 -#define CSR_ETRIGGER_M 0x200 +#define CSR_ETRIGGER_M_OFFSET 9ULL +#define CSR_ETRIGGER_M_LENGTH 1ULL +#define CSR_ETRIGGER_M 0x200ULL /* * When set, enable this trigger for exceptions that are taken from S/HS * mode. * This bit is hard-wired to 0 if the hart does not support * S-mode. */ -#define CSR_ETRIGGER_S_OFFSET 7 -#define CSR_ETRIGGER_S_LENGTH 1 -#define CSR_ETRIGGER_S 0x80 +#define CSR_ETRIGGER_S_OFFSET 7ULL +#define CSR_ETRIGGER_S_LENGTH 1ULL +#define CSR_ETRIGGER_S 0x80ULL /* * When set, enable this trigger for exceptions that are taken from U * mode. * This bit is hard-wired to 0 if the hart does not support * U-mode. */ -#define CSR_ETRIGGER_U_OFFSET 6 -#define CSR_ETRIGGER_U_LENGTH 1 -#define CSR_ETRIGGER_U 0x40 +#define CSR_ETRIGGER_U_OFFSET 6ULL +#define CSR_ETRIGGER_U_LENGTH 1ULL +#define CSR_ETRIGGER_U 0x40ULL /* * The action to take when the trigger fires. The values are explained * in Table~\ref{tab:action}. */ -#define CSR_ETRIGGER_ACTION_OFFSET 0 -#define CSR_ETRIGGER_ACTION_LENGTH 6 -#define CSR_ETRIGGER_ACTION 0x3f +#define CSR_ETRIGGER_ACTION_OFFSET 0ULL +#define CSR_ETRIGGER_ACTION_LENGTH 6ULL +#define CSR_ETRIGGER_ACTION 0x3fULL /* * breakpoint: */ @@ -1597,12 +1702,12 @@ */ #define CSR_ETRIGGER_ACTION_EXTERNAL1 9 #define CSR_TMEXTTRIGGER 0x7a1 -#define CSR_TMEXTTRIGGER_TYPE_OFFSET(XLEN) (XLEN + -4) -#define CSR_TMEXTTRIGGER_TYPE_LENGTH 4 -#define CSR_TMEXTTRIGGER_TYPE(XLEN) (0xf * (1ULL<<(XLEN + -4))) -#define CSR_TMEXTTRIGGER_DMODE_OFFSET(XLEN) (XLEN + -5) -#define CSR_TMEXTTRIGGER_DMODE_LENGTH 1 -#define CSR_TMEXTTRIGGER_DMODE(XLEN) (1ULL<<(XLEN + -5)) +#define CSR_TMEXTTRIGGER_TYPE_OFFSET(XLEN) ((XLEN) + -4ULL) +#define CSR_TMEXTTRIGGER_TYPE_LENGTH 4ULL +#define CSR_TMEXTTRIGGER_TYPE(XLEN) (0xfULL * (1ULL << ((XLEN) + -4ULL))) +#define CSR_TMEXTTRIGGER_DMODE_OFFSET(XLEN) ((XLEN) + -5ULL) +#define CSR_TMEXTTRIGGER_DMODE_LENGTH 1ULL +#define CSR_TMEXTTRIGGER_DMODE(XLEN) (1ULL << ((XLEN) + -5ULL)) /* * If this bit is implemented, the hardware sets it when this * trigger matches. The trigger's user can set or clear it at any @@ -1610,30 +1715,30 @@ * trigger(s) matched. If the bit is not implemented, it is always 0 * and writing it has no effect. */ -#define CSR_TMEXTTRIGGER_HIT_OFFSET(XLEN) (XLEN + -6) -#define CSR_TMEXTTRIGGER_HIT_LENGTH 1 -#define CSR_TMEXTTRIGGER_HIT(XLEN) (1ULL<<(XLEN + -6)) +#define CSR_TMEXTTRIGGER_HIT_OFFSET(XLEN) ((XLEN) + -6ULL) +#define CSR_TMEXTTRIGGER_HIT_LENGTH 1ULL +#define CSR_TMEXTTRIGGER_HIT(XLEN) (1ULL << ((XLEN) + -6ULL)) /* * This optional bit, when set, causes this trigger to fire whenever an attached * interrupt controller signals a trigger. */ -#define CSR_TMEXTTRIGGER_INTCTL_OFFSET 0x16 -#define CSR_TMEXTTRIGGER_INTCTL_LENGTH 1 -#define CSR_TMEXTTRIGGER_INTCTL 0x400000 +#define CSR_TMEXTTRIGGER_INTCTL_OFFSET 0x16ULL +#define CSR_TMEXTTRIGGER_INTCTL_LENGTH 1ULL +#define CSR_TMEXTTRIGGER_INTCTL 0x400000ULL /* - * Selects any combination of up to 16 external debug trigger inputs + * Selects any combination of up to 16 TM external trigger inputs * that cause this trigger to fire. */ -#define CSR_TMEXTTRIGGER_SELECT_OFFSET 6 -#define CSR_TMEXTTRIGGER_SELECT_LENGTH 0x10 -#define CSR_TMEXTTRIGGER_SELECT 0x3fffc0 +#define CSR_TMEXTTRIGGER_SELECT_OFFSET 6ULL +#define CSR_TMEXTTRIGGER_SELECT_LENGTH 0x10ULL +#define CSR_TMEXTTRIGGER_SELECT 0x3fffc0ULL /* * The action to take when the trigger fires. The values are explained * in Table~\ref{tab:action}. */ -#define CSR_TMEXTTRIGGER_ACTION_OFFSET 0 -#define CSR_TMEXTTRIGGER_ACTION_LENGTH 6 -#define CSR_TMEXTTRIGGER_ACTION 0x3f +#define CSR_TMEXTTRIGGER_ACTION_OFFSET 0ULL +#define CSR_TMEXTTRIGGER_ACTION_LENGTH 6ULL +#define CSR_TMEXTTRIGGER_ACTION 0x3fULL /* * breakpoint: */ @@ -1666,26 +1771,28 @@ /* * Data used together with \FcsrTextraThirtytwoMhselect. */ -#define CSR_TEXTRA32_MHVALUE_OFFSET 0x1a -#define CSR_TEXTRA32_MHVALUE_LENGTH 6 -#define CSR_TEXTRA32_MHVALUE 0xfc000000U -#define CSR_TEXTRA32_MHSELECT_OFFSET 0x17 -#define CSR_TEXTRA32_MHSELECT_LENGTH 3 -#define CSR_TEXTRA32_MHSELECT 0x3800000 +#define CSR_TEXTRA32_MHVALUE_OFFSET 0x1aULL +#define CSR_TEXTRA32_MHVALUE_LENGTH 6ULL +#define CSR_TEXTRA32_MHVALUE 0xfc000000ULL +#define CSR_TEXTRA32_MHSELECT_OFFSET 0x17ULL +#define CSR_TEXTRA32_MHSELECT_LENGTH 3ULL +#define CSR_TEXTRA32_MHSELECT 0x3800000ULL /* * ignore: Ignore \FcsrTextraThirtytwoMhvalue. */ #define CSR_TEXTRA32_MHSELECT_IGNORE 0 /* - * mcontext: This trigger will only match if the low bits of + * mcontext: This trigger will only match or fire if the low bits of * \RcsrMcontext/\RcsrHcontext equal \FcsrTextraThirtytwoMhvalue. */ #define CSR_TEXTRA32_MHSELECT_MCONTEXT 4 /* - * 1, 5 (mcontext\_select): This trigger will only match if the low bits of + * 1, 5 (mcontext\_select): This trigger will only match or fire if the + * low bits of * \RcsrMcontext/\RcsrHcontext equal \{\FcsrTextraThirtytwoMhvalue, mhselect[2]\}. * - * 2, 6 (vmid\_select): This trigger will only match if VMID in hgatp equals the lower VMIDMAX + * 2, 6 (vmid\_select): This trigger will only match or fire if VMID in + * hgatp equals the lower VMIDMAX * (defined in the Privileged Spec) bits of \{\FcsrTextraThirtytwoMhvalue, mhselect[2]\}. * * 3, 7 (reserved): Reserved. @@ -1698,31 +1805,31 @@ * When the next most significant bit of this field is 1, it causes bits 15:8 * to be ignored in the comparison, when \FcsrTextraThirtytwoSselect=1. */ -#define CSR_TEXTRA32_SBYTEMASK_OFFSET 0x12 -#define CSR_TEXTRA32_SBYTEMASK_LENGTH 2 -#define CSR_TEXTRA32_SBYTEMASK 0xc0000 +#define CSR_TEXTRA32_SBYTEMASK_OFFSET 0x12ULL +#define CSR_TEXTRA32_SBYTEMASK_LENGTH 2ULL +#define CSR_TEXTRA32_SBYTEMASK 0xc0000ULL /* * Data used together with \FcsrTextraThirtytwoSselect. * * This field should be tied to 0 when S-mode is not supported. */ -#define CSR_TEXTRA32_SVALUE_OFFSET 2 -#define CSR_TEXTRA32_SVALUE_LENGTH 0x10 -#define CSR_TEXTRA32_SVALUE 0x3fffc -#define CSR_TEXTRA32_SSELECT_OFFSET 0 -#define CSR_TEXTRA32_SSELECT_LENGTH 2 -#define CSR_TEXTRA32_SSELECT 3 +#define CSR_TEXTRA32_SVALUE_OFFSET 2ULL +#define CSR_TEXTRA32_SVALUE_LENGTH 0x10ULL +#define CSR_TEXTRA32_SVALUE 0x3fffcULL +#define CSR_TEXTRA32_SSELECT_OFFSET 0ULL +#define CSR_TEXTRA32_SSELECT_LENGTH 2ULL +#define CSR_TEXTRA32_SSELECT 3ULL /* * ignore: Ignore \FcsrTextraThirtytwoSvalue. */ #define CSR_TEXTRA32_SSELECT_IGNORE 0 /* - * scontext: This trigger will only match if the low bits of + * scontext: This trigger will only match or fire if the low bits of * \RcsrScontext equal \FcsrTextraThirtytwoSvalue. */ #define CSR_TEXTRA32_SSELECT_SCONTEXT 1 /* - * asid: This trigger will only match if: + * asid: This trigger will only match or fire if: * \begin{itemize}[noitemsep,nolistsep] * \item the mode is VS-mode or VU-mode and ASID in \Rvsatp * equals the lower ASIDMAX (defined in the Privileged Spec) bits @@ -1737,11 +1844,11 @@ * This field should be tied to 0 when S-mode is not supported. */ #define CSR_TEXTRA64 0x7a3 -#define CSR_TEXTRA64_MHVALUE_OFFSET 0x33 -#define CSR_TEXTRA64_MHVALUE_LENGTH 0xd +#define CSR_TEXTRA64_MHVALUE_OFFSET 0x33ULL +#define CSR_TEXTRA64_MHVALUE_LENGTH 0xdULL #define CSR_TEXTRA64_MHVALUE 0xfff8000000000000ULL -#define CSR_TEXTRA64_MHSELECT_OFFSET 0x30 -#define CSR_TEXTRA64_MHSELECT_LENGTH 3 +#define CSR_TEXTRA64_MHSELECT_OFFSET 0x30ULL +#define CSR_TEXTRA64_MHSELECT_LENGTH 3ULL #define CSR_TEXTRA64_MHSELECT 0x7000000000000ULL /* * When the least significant bit of this field is 1, it causes bits 7:0 @@ -1751,19 +1858,19 @@ * fourth bit controls the comparison of bits 31:24, and * fifth bit controls the comparison of bits 33:32. */ -#define CSR_TEXTRA64_SBYTEMASK_OFFSET 0x24 -#define CSR_TEXTRA64_SBYTEMASK_LENGTH 5 +#define CSR_TEXTRA64_SBYTEMASK_OFFSET 0x24ULL +#define CSR_TEXTRA64_SBYTEMASK_LENGTH 5ULL #define CSR_TEXTRA64_SBYTEMASK 0x1f000000000ULL -#define CSR_TEXTRA64_SVALUE_OFFSET 2 -#define CSR_TEXTRA64_SVALUE_LENGTH 0x22 +#define CSR_TEXTRA64_SVALUE_OFFSET 2ULL +#define CSR_TEXTRA64_SVALUE_LENGTH 0x22ULL #define CSR_TEXTRA64_SVALUE 0xffffffffcULL -#define CSR_TEXTRA64_SSELECT_OFFSET 0 -#define CSR_TEXTRA64_SSELECT_LENGTH 2 -#define CSR_TEXTRA64_SSELECT 3 +#define CSR_TEXTRA64_SSELECT_OFFSET 0ULL +#define CSR_TEXTRA64_SSELECT_LENGTH 2ULL +#define CSR_TEXTRA64_SSELECT 3ULL #define DM_DMSTATUS 0x11 -#define DM_DMSTATUS_NDMRESETPENDING_OFFSET 0x18 -#define DM_DMSTATUS_NDMRESETPENDING_LENGTH 1 -#define DM_DMSTATUS_NDMRESETPENDING 0x1000000 +#define DM_DMSTATUS_NDMRESETPENDING_OFFSET 0x18ULL +#define DM_DMSTATUS_NDMRESETPENDING_LENGTH 1ULL +#define DM_DMSTATUS_NDMRESETPENDING 0x1000000ULL /* * false: Unimplemented, or \FdmDmcontrolNdmreset is zero and no ndmreset is currently * in progress. @@ -1773,9 +1880,9 @@ * true: \FdmDmcontrolNdmreset is currently nonzero, or there is an ndmreset in progress. */ #define DM_DMSTATUS_NDMRESETPENDING_TRUE 1 -#define DM_DMSTATUS_STICKYUNAVAIL_OFFSET 0x17 -#define DM_DMSTATUS_STICKYUNAVAIL_LENGTH 1 -#define DM_DMSTATUS_STICKYUNAVAIL 0x800000 +#define DM_DMSTATUS_STICKYUNAVAIL_OFFSET 0x17ULL +#define DM_DMSTATUS_STICKYUNAVAIL_LENGTH 1ULL +#define DM_DMSTATUS_STICKYUNAVAIL 0x800000ULL /* * current: The per-hart {\tt unavail} bits reflect the current state of the hart. */ @@ -1793,94 +1900,94 @@ * * This must be 1 when \FdmAbstractcsProgbufsize is 1. */ -#define DM_DMSTATUS_IMPEBREAK_OFFSET 0x16 -#define DM_DMSTATUS_IMPEBREAK_LENGTH 1 -#define DM_DMSTATUS_IMPEBREAK 0x400000 +#define DM_DMSTATUS_IMPEBREAK_OFFSET 0x16ULL +#define DM_DMSTATUS_IMPEBREAK_LENGTH 1ULL +#define DM_DMSTATUS_IMPEBREAK 0x400000ULL /* * This field is 1 when all currently selected harts have been reset * and reset has not been acknowledged for any of them. */ -#define DM_DMSTATUS_ALLHAVERESET_OFFSET 0x13 -#define DM_DMSTATUS_ALLHAVERESET_LENGTH 1 -#define DM_DMSTATUS_ALLHAVERESET 0x80000 +#define DM_DMSTATUS_ALLHAVERESET_OFFSET 0x13ULL +#define DM_DMSTATUS_ALLHAVERESET_LENGTH 1ULL +#define DM_DMSTATUS_ALLHAVERESET 0x80000ULL /* * This field is 1 when at least one currently selected hart has been * reset and reset has not been acknowledged for that hart. */ -#define DM_DMSTATUS_ANYHAVERESET_OFFSET 0x12 -#define DM_DMSTATUS_ANYHAVERESET_LENGTH 1 -#define DM_DMSTATUS_ANYHAVERESET 0x40000 +#define DM_DMSTATUS_ANYHAVERESET_OFFSET 0x12ULL +#define DM_DMSTATUS_ANYHAVERESET_LENGTH 1ULL +#define DM_DMSTATUS_ANYHAVERESET 0x40000ULL /* * This field is 1 when all currently selected harts have their * resume ack bit\index{resume ack bit} set. */ -#define DM_DMSTATUS_ALLRESUMEACK_OFFSET 0x11 -#define DM_DMSTATUS_ALLRESUMEACK_LENGTH 1 -#define DM_DMSTATUS_ALLRESUMEACK 0x20000 +#define DM_DMSTATUS_ALLRESUMEACK_OFFSET 0x11ULL +#define DM_DMSTATUS_ALLRESUMEACK_LENGTH 1ULL +#define DM_DMSTATUS_ALLRESUMEACK 0x20000ULL /* * This field is 1 when any currently selected hart has its * resume ack bit\index{resume ack bit} set. */ -#define DM_DMSTATUS_ANYRESUMEACK_OFFSET 0x10 -#define DM_DMSTATUS_ANYRESUMEACK_LENGTH 1 -#define DM_DMSTATUS_ANYRESUMEACK 0x10000 +#define DM_DMSTATUS_ANYRESUMEACK_OFFSET 0x10ULL +#define DM_DMSTATUS_ANYRESUMEACK_LENGTH 1ULL +#define DM_DMSTATUS_ANYRESUMEACK 0x10000ULL /* * This field is 1 when all currently selected harts do not exist in * this hardware platform. */ -#define DM_DMSTATUS_ALLNONEXISTENT_OFFSET 0xf -#define DM_DMSTATUS_ALLNONEXISTENT_LENGTH 1 -#define DM_DMSTATUS_ALLNONEXISTENT 0x8000 +#define DM_DMSTATUS_ALLNONEXISTENT_OFFSET 0xfULL +#define DM_DMSTATUS_ALLNONEXISTENT_LENGTH 1ULL +#define DM_DMSTATUS_ALLNONEXISTENT 0x8000ULL /* * This field is 1 when any currently selected hart does not exist in * this hardware platform. */ -#define DM_DMSTATUS_ANYNONEXISTENT_OFFSET 0xe -#define DM_DMSTATUS_ANYNONEXISTENT_LENGTH 1 -#define DM_DMSTATUS_ANYNONEXISTENT 0x4000 +#define DM_DMSTATUS_ANYNONEXISTENT_OFFSET 0xeULL +#define DM_DMSTATUS_ANYNONEXISTENT_LENGTH 1ULL +#define DM_DMSTATUS_ANYNONEXISTENT 0x4000ULL /* * This field is 1 when all currently selected harts are * unavailable, or (if \FdmDmstatusStickyunavail is 1) were * unavailable without that being acknowledged. */ -#define DM_DMSTATUS_ALLUNAVAIL_OFFSET 0xd -#define DM_DMSTATUS_ALLUNAVAIL_LENGTH 1 -#define DM_DMSTATUS_ALLUNAVAIL 0x2000 +#define DM_DMSTATUS_ALLUNAVAIL_OFFSET 0xdULL +#define DM_DMSTATUS_ALLUNAVAIL_LENGTH 1ULL +#define DM_DMSTATUS_ALLUNAVAIL 0x2000ULL /* * This field is 1 when any currently selected hart is unavailable, * or (if \FdmDmstatusStickyunavail is 1) was unavailable without * that being acknowledged. */ -#define DM_DMSTATUS_ANYUNAVAIL_OFFSET 0xc -#define DM_DMSTATUS_ANYUNAVAIL_LENGTH 1 -#define DM_DMSTATUS_ANYUNAVAIL 0x1000 +#define DM_DMSTATUS_ANYUNAVAIL_OFFSET 0xcULL +#define DM_DMSTATUS_ANYUNAVAIL_LENGTH 1ULL +#define DM_DMSTATUS_ANYUNAVAIL 0x1000ULL /* * This field is 1 when all currently selected harts are running. */ -#define DM_DMSTATUS_ALLRUNNING_OFFSET 0xb -#define DM_DMSTATUS_ALLRUNNING_LENGTH 1 -#define DM_DMSTATUS_ALLRUNNING 0x800 +#define DM_DMSTATUS_ALLRUNNING_OFFSET 0xbULL +#define DM_DMSTATUS_ALLRUNNING_LENGTH 1ULL +#define DM_DMSTATUS_ALLRUNNING 0x800ULL /* * This field is 1 when any currently selected hart is running. */ -#define DM_DMSTATUS_ANYRUNNING_OFFSET 0xa -#define DM_DMSTATUS_ANYRUNNING_LENGTH 1 -#define DM_DMSTATUS_ANYRUNNING 0x400 +#define DM_DMSTATUS_ANYRUNNING_OFFSET 0xaULL +#define DM_DMSTATUS_ANYRUNNING_LENGTH 1ULL +#define DM_DMSTATUS_ANYRUNNING 0x400ULL /* * This field is 1 when all currently selected harts are halted. */ -#define DM_DMSTATUS_ALLHALTED_OFFSET 9 -#define DM_DMSTATUS_ALLHALTED_LENGTH 1 -#define DM_DMSTATUS_ALLHALTED 0x200 +#define DM_DMSTATUS_ALLHALTED_OFFSET 9ULL +#define DM_DMSTATUS_ALLHALTED_LENGTH 1ULL +#define DM_DMSTATUS_ALLHALTED 0x200ULL /* * This field is 1 when any currently selected hart is halted. */ -#define DM_DMSTATUS_ANYHALTED_OFFSET 8 -#define DM_DMSTATUS_ANYHALTED_LENGTH 1 -#define DM_DMSTATUS_ANYHALTED 0x100 -#define DM_DMSTATUS_AUTHENTICATED_OFFSET 7 -#define DM_DMSTATUS_AUTHENTICATED_LENGTH 1 -#define DM_DMSTATUS_AUTHENTICATED 0x80 +#define DM_DMSTATUS_ANYHALTED_OFFSET 8ULL +#define DM_DMSTATUS_ANYHALTED_LENGTH 1ULL +#define DM_DMSTATUS_ANYHALTED 0x100ULL +#define DM_DMSTATUS_AUTHENTICATED_OFFSET 7ULL +#define DM_DMSTATUS_AUTHENTICATED_LENGTH 1ULL +#define DM_DMSTATUS_AUTHENTICATED 0x80ULL /* * false: Authentication is required before using the DM. */ @@ -1893,9 +2000,9 @@ * On components that don't implement authentication, this bit must be * preset as 1. */ -#define DM_DMSTATUS_AUTHBUSY_OFFSET 6 -#define DM_DMSTATUS_AUTHBUSY_LENGTH 1 -#define DM_DMSTATUS_AUTHBUSY 0x40 +#define DM_DMSTATUS_AUTHBUSY_OFFSET 6ULL +#define DM_DMSTATUS_AUTHBUSY_LENGTH 1ULL +#define DM_DMSTATUS_AUTHBUSY 0x40ULL /* * ready: The authentication module is ready to process the next * read/write to \RdmAuthdata. @@ -1915,12 +2022,12 @@ * controllable by the \FdmDmcontrolSetresethaltreq and \FdmDmcontrolClrresethaltreq bits. * 0 otherwise. */ -#define DM_DMSTATUS_HASRESETHALTREQ_OFFSET 5 -#define DM_DMSTATUS_HASRESETHALTREQ_LENGTH 1 -#define DM_DMSTATUS_HASRESETHALTREQ 0x20 -#define DM_DMSTATUS_CONFSTRPTRVALID_OFFSET 4 -#define DM_DMSTATUS_CONFSTRPTRVALID_LENGTH 1 -#define DM_DMSTATUS_CONFSTRPTRVALID 0x10 +#define DM_DMSTATUS_HASRESETHALTREQ_OFFSET 5ULL +#define DM_DMSTATUS_HASRESETHALTREQ_LENGTH 1ULL +#define DM_DMSTATUS_HASRESETHALTREQ 0x20ULL +#define DM_DMSTATUS_CONFSTRPTRVALID_OFFSET 4ULL +#define DM_DMSTATUS_CONFSTRPTRVALID_LENGTH 1ULL +#define DM_DMSTATUS_CONFSTRPTRVALID 0x10ULL /* * invalid: \RdmConfstrptrZero--\RdmConfstrptrThree hold information which * is not relevant to the configuration structure. @@ -1931,9 +2038,9 @@ * configuration structure. */ #define DM_DMSTATUS_CONFSTRPTRVALID_VALID 1 -#define DM_DMSTATUS_VERSION_OFFSET 0 -#define DM_DMSTATUS_VERSION_LENGTH 4 -#define DM_DMSTATUS_VERSION 0xf +#define DM_DMSTATUS_VERSION_OFFSET 0ULL +#define DM_DMSTATUS_VERSION_LENGTH 4ULL +#define DM_DMSTATUS_VERSION 0xfULL /* * none: There is no Debug Module present. */ @@ -1969,9 +2076,9 @@ * * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. */ -#define DM_DMCONTROL_HALTREQ_OFFSET 0x1f -#define DM_DMCONTROL_HALTREQ_LENGTH 1 -#define DM_DMCONTROL_HALTREQ 0x80000000U +#define DM_DMCONTROL_HALTREQ_OFFSET 0x1fULL +#define DM_DMCONTROL_HALTREQ_LENGTH 1ULL +#define DM_DMCONTROL_HALTREQ 0x80000000ULL /* * Writing 1 causes the currently selected harts to resume once, if * they are halted when the write occurs. It also clears the resume @@ -1981,9 +2088,9 @@ * * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. */ -#define DM_DMCONTROL_RESUMEREQ_OFFSET 0x1e -#define DM_DMCONTROL_RESUMEREQ_LENGTH 1 -#define DM_DMCONTROL_RESUMEREQ 0x40000000 +#define DM_DMCONTROL_RESUMEREQ_OFFSET 0x1eULL +#define DM_DMCONTROL_RESUMEREQ_LENGTH 1ULL +#define DM_DMCONTROL_RESUMEREQ 0x40000000ULL /* * This optional field writes the reset bit for all the currently * selected harts. To perform a reset the debugger writes 1, and then @@ -1998,12 +2105,12 @@ * * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. */ -#define DM_DMCONTROL_HARTRESET_OFFSET 0x1d -#define DM_DMCONTROL_HARTRESET_LENGTH 1 -#define DM_DMCONTROL_HARTRESET 0x20000000 -#define DM_DMCONTROL_ACKHAVERESET_OFFSET 0x1c -#define DM_DMCONTROL_ACKHAVERESET_LENGTH 1 -#define DM_DMCONTROL_ACKHAVERESET 0x10000000 +#define DM_DMCONTROL_HARTRESET_OFFSET 0x1dULL +#define DM_DMCONTROL_HARTRESET_LENGTH 1ULL +#define DM_DMCONTROL_HARTRESET 0x20000000ULL +#define DM_DMCONTROL_ACKHAVERESET_OFFSET 0x1cULL +#define DM_DMCONTROL_ACKHAVERESET_LENGTH 1ULL +#define DM_DMCONTROL_ACKHAVERESET 0x10000000ULL /* * nop: No effect. */ @@ -2015,9 +2122,9 @@ /* * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. */ -#define DM_DMCONTROL_ACKUNAVAIL_OFFSET 0x1b -#define DM_DMCONTROL_ACKUNAVAIL_LENGTH 1 -#define DM_DMCONTROL_ACKUNAVAIL 0x8000000 +#define DM_DMCONTROL_ACKUNAVAIL_OFFSET 0x1bULL +#define DM_DMCONTROL_ACKUNAVAIL_LENGTH 1ULL +#define DM_DMCONTROL_ACKUNAVAIL 0x8000000ULL /* * nop: No effect. */ @@ -2032,9 +2139,9 @@ /* * Selects the definition of currently selected harts. */ -#define DM_DMCONTROL_HASEL_OFFSET 0x1a -#define DM_DMCONTROL_HASEL_LENGTH 1 -#define DM_DMCONTROL_HASEL 0x4000000 +#define DM_DMCONTROL_HASEL_OFFSET 0x1aULL +#define DM_DMCONTROL_HASEL_LENGTH 1ULL +#define DM_DMCONTROL_HASEL 0x4000000ULL /* * single: There is a single currently selected hart, that is selected by \Fhartsel. */ @@ -2055,16 +2162,16 @@ * The low 10 bits of \Fhartsel: the DM-specific index of the hart to * select. This hart is always part of the currently selected harts. */ -#define DM_DMCONTROL_HARTSELLO_OFFSET 0x10 -#define DM_DMCONTROL_HARTSELLO_LENGTH 0xa -#define DM_DMCONTROL_HARTSELLO 0x3ff0000 +#define DM_DMCONTROL_HARTSELLO_OFFSET 0x10ULL +#define DM_DMCONTROL_HARTSELLO_LENGTH 0xaULL +#define DM_DMCONTROL_HARTSELLO 0x3ff0000ULL /* * The high 10 bits of \Fhartsel: the DM-specific index of the hart to * select. This hart is always part of the currently selected harts. */ -#define DM_DMCONTROL_HARTSELHI_OFFSET 6 -#define DM_DMCONTROL_HARTSELHI_LENGTH 0xa -#define DM_DMCONTROL_HARTSELHI 0xffc0 +#define DM_DMCONTROL_HARTSELHI_OFFSET 6ULL +#define DM_DMCONTROL_HARTSELHI_LENGTH 0xaULL +#define DM_DMCONTROL_HARTSELHI 0xffc0ULL /* * This optional field sets \Fkeepalive for all currently selected * harts, unless \FdmDmcontrolClrkeepalive is simultaneously set to @@ -2072,18 +2179,18 @@ * * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. */ -#define DM_DMCONTROL_SETKEEPALIVE_OFFSET 5 -#define DM_DMCONTROL_SETKEEPALIVE_LENGTH 1 -#define DM_DMCONTROL_SETKEEPALIVE 0x20 +#define DM_DMCONTROL_SETKEEPALIVE_OFFSET 5ULL +#define DM_DMCONTROL_SETKEEPALIVE_LENGTH 1ULL +#define DM_DMCONTROL_SETKEEPALIVE 0x20ULL /* * This optional field clears \Fkeepalive for all currently selected * harts. * * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. */ -#define DM_DMCONTROL_CLRKEEPALIVE_OFFSET 4 -#define DM_DMCONTROL_CLRKEEPALIVE_LENGTH 1 -#define DM_DMCONTROL_CLRKEEPALIVE 0x10 +#define DM_DMCONTROL_CLRKEEPALIVE_OFFSET 4ULL +#define DM_DMCONTROL_CLRKEEPALIVE_LENGTH 1ULL +#define DM_DMCONTROL_CLRKEEPALIVE 0x10ULL /* * This optional field writes the halt-on-reset request bit for all * currently selected harts, unless \FdmDmcontrolClrresethaltreq is @@ -2096,18 +2203,18 @@ * * If \FdmDmstatusHasresethaltreq is 0, this field is not implemented. */ -#define DM_DMCONTROL_SETRESETHALTREQ_OFFSET 3 -#define DM_DMCONTROL_SETRESETHALTREQ_LENGTH 1 -#define DM_DMCONTROL_SETRESETHALTREQ 8 +#define DM_DMCONTROL_SETRESETHALTREQ_OFFSET 3ULL +#define DM_DMCONTROL_SETRESETHALTREQ_LENGTH 1ULL +#define DM_DMCONTROL_SETRESETHALTREQ 8ULL /* * This optional field clears the halt-on-reset request bit for all * currently selected harts. * * Writes apply to the new value of \Fhartsel and \FdmDmcontrolHasel. */ -#define DM_DMCONTROL_CLRRESETHALTREQ_OFFSET 2 -#define DM_DMCONTROL_CLRRESETHALTREQ_LENGTH 1 -#define DM_DMCONTROL_CLRRESETHALTREQ 4 +#define DM_DMCONTROL_CLRRESETHALTREQ_OFFSET 2ULL +#define DM_DMCONTROL_CLRRESETHALTREQ_LENGTH 1ULL +#define DM_DMCONTROL_CLRRESETHALTREQ 4ULL /* * This bit controls the reset signal from the DM to the rest of the * hardware platform. The signal should reset every part of the hardware platform, including @@ -2117,9 +2224,9 @@ * and then writes 0 * to deassert the reset. */ -#define DM_DMCONTROL_NDMRESET_OFFSET 1 -#define DM_DMCONTROL_NDMRESET_LENGTH 1 -#define DM_DMCONTROL_NDMRESET 2 +#define DM_DMCONTROL_NDMRESET_OFFSET 1ULL +#define DM_DMCONTROL_NDMRESET_LENGTH 1ULL +#define DM_DMCONTROL_NDMRESET 2ULL /* * This bit serves as a reset signal for the Debug Module itself. * After changing the value of this bit, the debugger must poll @@ -2129,9 +2236,9 @@ * take an arbitrarily long time to complete activation or deactivation and will * indicate completion by setting \FdmDmcontrolDmactive to the requested value. */ -#define DM_DMCONTROL_DMACTIVE_OFFSET 0 -#define DM_DMCONTROL_DMACTIVE_LENGTH 1 -#define DM_DMCONTROL_DMACTIVE 1 +#define DM_DMCONTROL_DMACTIVE_OFFSET 0ULL +#define DM_DMCONTROL_DMACTIVE_LENGTH 1ULL +#define DM_DMCONTROL_DMACTIVE 1ULL /* * inactive: The module's state, including authentication mechanism, * takes its reset values (the \FdmDmcontrolDmactive bit is the only bit which can @@ -2163,12 +2270,12 @@ * The debugger can make no assumptions about the contents of these * registers between commands. */ -#define DM_HARTINFO_NSCRATCH_OFFSET 0x14 -#define DM_HARTINFO_NSCRATCH_LENGTH 4 -#define DM_HARTINFO_NSCRATCH 0xf00000 -#define DM_HARTINFO_DATAACCESS_OFFSET 0x10 -#define DM_HARTINFO_DATAACCESS_LENGTH 1 -#define DM_HARTINFO_DATAACCESS 0x10000 +#define DM_HARTINFO_NSCRATCH_OFFSET 0x14ULL +#define DM_HARTINFO_NSCRATCH_LENGTH 4ULL +#define DM_HARTINFO_NSCRATCH 0xf00000ULL +#define DM_HARTINFO_DATAACCESS_OFFSET 0x10ULL +#define DM_HARTINFO_DATAACCESS_LENGTH 1ULL +#define DM_HARTINFO_DATAACCESS 0x10000ULL /* * csr: The {\tt data} registers are shadowed in the hart by CSRs. * Each CSR is DXLEN bits in size, and corresponds @@ -2187,16 +2294,12 @@ * If \FdmHartinfoDataaccess is 1: Number of 32-bit words in the memory map * dedicated to shadowing the {\tt data} registers. * - * If this value is non-zero, then the {tt data} registers must go - * beyond being MRs and guarantee they each store a single value, that is - * readable/writable by either side. - * * Since there are at most 12 {\tt data} registers, the value in this * register must be 12 or smaller. */ -#define DM_HARTINFO_DATASIZE_OFFSET 0xc -#define DM_HARTINFO_DATASIZE_LENGTH 4 -#define DM_HARTINFO_DATASIZE 0xf000 +#define DM_HARTINFO_DATASIZE_OFFSET 0xcULL +#define DM_HARTINFO_DATASIZE_LENGTH 4ULL +#define DM_HARTINFO_DATASIZE 0xf000ULL /* * If \FdmHartinfoDataaccess is 0: The number of the first CSR dedicated to * shadowing the {\tt data} registers. @@ -2206,32 +2309,32 @@ * range of -2048 to 2047, easily addressed with a load or store using * \Xzero as the address register. */ -#define DM_HARTINFO_DATAADDR_OFFSET 0 -#define DM_HARTINFO_DATAADDR_LENGTH 0xc -#define DM_HARTINFO_DATAADDR 0xfff +#define DM_HARTINFO_DATAADDR_OFFSET 0ULL +#define DM_HARTINFO_DATAADDR_LENGTH 0xcULL +#define DM_HARTINFO_DATAADDR 0xfffULL #define DM_HAWINDOWSEL 0x14 /* * The high bits of this field may be tied to 0, depending on how large * the array mask register is. E.g.\ on a hardware platform with 48 harts only bit 0 * of this field may actually be writable. */ -#define DM_HAWINDOWSEL_HAWINDOWSEL_OFFSET 0 -#define DM_HAWINDOWSEL_HAWINDOWSEL_LENGTH 0xf -#define DM_HAWINDOWSEL_HAWINDOWSEL 0x7fff +#define DM_HAWINDOWSEL_HAWINDOWSEL_OFFSET 0ULL +#define DM_HAWINDOWSEL_HAWINDOWSEL_LENGTH 0xfULL +#define DM_HAWINDOWSEL_HAWINDOWSEL 0x7fffULL #define DM_HAWINDOW 0x15 -#define DM_HAWINDOW_MASKDATA_OFFSET 0 -#define DM_HAWINDOW_MASKDATA_LENGTH 0x20 -#define DM_HAWINDOW_MASKDATA 0xffffffffU +#define DM_HAWINDOW_MASKDATA_OFFSET 0ULL +#define DM_HAWINDOW_MASKDATA_LENGTH 0x20ULL +#define DM_HAWINDOW_MASKDATA 0xffffffffULL #define DM_ABSTRACTCS 0x16 /* * Size of the Program Buffer, in 32-bit words. Valid sizes are 0 - 16. */ -#define DM_ABSTRACTCS_PROGBUFSIZE_OFFSET 0x18 -#define DM_ABSTRACTCS_PROGBUFSIZE_LENGTH 5 -#define DM_ABSTRACTCS_PROGBUFSIZE 0x1f000000 -#define DM_ABSTRACTCS_BUSY_OFFSET 0xc -#define DM_ABSTRACTCS_BUSY_LENGTH 1 -#define DM_ABSTRACTCS_BUSY 0x1000 +#define DM_ABSTRACTCS_PROGBUFSIZE_OFFSET 0x18ULL +#define DM_ABSTRACTCS_PROGBUFSIZE_LENGTH 5ULL +#define DM_ABSTRACTCS_PROGBUFSIZE 0x1f000000ULL +#define DM_ABSTRACTCS_BUSY_OFFSET 0xcULL +#define DM_ABSTRACTCS_BUSY_LENGTH 1ULL +#define DM_ABSTRACTCS_BUSY 0x1000ULL /* * ready: There is no abstract command currently being executed. */ @@ -2250,12 +2353,19 @@ * permission checks that apply based on the current architectural * state of the hart performing the access, or with a relaxed set of * permission checks (e.g. PMP restrictions are ignored). The - * details of the latter are implementation-specific. When set to 0, - * full permissions apply; when set to 1, relaxed permissions apply. + * details of the latter are implementation-specific. + */ +#define DM_ABSTRACTCS_RELAXEDPRIV_OFFSET 0xbULL +#define DM_ABSTRACTCS_RELAXEDPRIV_LENGTH 1ULL +#define DM_ABSTRACTCS_RELAXEDPRIV 0x800ULL +/* + * full checks: Full permission checks apply. */ -#define DM_ABSTRACTCS_RELAXEDPRIV_OFFSET 0xb -#define DM_ABSTRACTCS_RELAXEDPRIV_LENGTH 1 -#define DM_ABSTRACTCS_RELAXEDPRIV 0x800 +#define DM_ABSTRACTCS_RELAXEDPRIV_FULL_CHECKS 0 +/* + * relaxed checks: Relaxed permission checks apply. + */ +#define DM_ABSTRACTCS_RELAXEDPRIV_RELAXED_CHECKS 1 /* * Gets set if an abstract command fails. The bits in this field remain set until * they are cleared by writing 1 to them. No abstract command is @@ -2263,9 +2373,9 @@ * * This field only contains a valid value if \FdmAbstractcsBusy is 0. */ -#define DM_ABSTRACTCS_CMDERR_OFFSET 8 -#define DM_ABSTRACTCS_CMDERR_LENGTH 3 -#define DM_ABSTRACTCS_CMDERR 0x700 +#define DM_ABSTRACTCS_CMDERR_OFFSET 8ULL +#define DM_ABSTRACTCS_CMDERR_LENGTH 3ULL +#define DM_ABSTRACTCS_CMDERR 0x700ULL /* * none: No error. */ @@ -2311,24 +2421,24 @@ * Number of {\tt data} registers that are implemented as part of the * abstract command interface. Valid sizes are 1 -- 12. */ -#define DM_ABSTRACTCS_DATACOUNT_OFFSET 0 -#define DM_ABSTRACTCS_DATACOUNT_LENGTH 4 -#define DM_ABSTRACTCS_DATACOUNT 0xf +#define DM_ABSTRACTCS_DATACOUNT_OFFSET 0ULL +#define DM_ABSTRACTCS_DATACOUNT_LENGTH 4ULL +#define DM_ABSTRACTCS_DATACOUNT 0xfULL #define DM_COMMAND 0x17 /* * The type determines the overall functionality of this * abstract command. */ -#define DM_COMMAND_CMDTYPE_OFFSET 0x18 -#define DM_COMMAND_CMDTYPE_LENGTH 8 -#define DM_COMMAND_CMDTYPE 0xff000000U +#define DM_COMMAND_CMDTYPE_OFFSET 0x18ULL +#define DM_COMMAND_CMDTYPE_LENGTH 8ULL +#define DM_COMMAND_CMDTYPE 0xff000000ULL /* * This field is interpreted in a command-specific manner, * described for each abstract command. */ -#define DM_COMMAND_CONTROL_OFFSET 0 -#define DM_COMMAND_CONTROL_LENGTH 0x18 -#define DM_COMMAND_CONTROL 0xffffff +#define DM_COMMAND_CONTROL_OFFSET 0ULL +#define DM_COMMAND_CONTROL_LENGTH 0x18ULL +#define DM_COMMAND_CONTROL 0xffffffULL #define DM_ABSTRACTAUTO 0x18 /* * When a bit in this field is 1, read or write accesses to the @@ -2336,42 +2446,42 @@ * current value in \RdmCommand was written there again after the * access to {\tt progbuf} completes. */ -#define DM_ABSTRACTAUTO_AUTOEXECPROGBUF_OFFSET 0x10 -#define DM_ABSTRACTAUTO_AUTOEXECPROGBUF_LENGTH 0x10 -#define DM_ABSTRACTAUTO_AUTOEXECPROGBUF 0xffff0000U +#define DM_ABSTRACTAUTO_AUTOEXECPROGBUF_OFFSET 0x10ULL +#define DM_ABSTRACTAUTO_AUTOEXECPROGBUF_LENGTH 0x10ULL +#define DM_ABSTRACTAUTO_AUTOEXECPROGBUF 0xffff0000ULL /* * When a bit in this field is 1, read or write accesses to the * corresponding {\tt data} word cause the DM to act as if the current * value in \RdmCommand was written there again after the * access to {\tt data} completes. */ -#define DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET 0 -#define DM_ABSTRACTAUTO_AUTOEXECDATA_LENGTH 0xc -#define DM_ABSTRACTAUTO_AUTOEXECDATA 0xfff +#define DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET 0ULL +#define DM_ABSTRACTAUTO_AUTOEXECDATA_LENGTH 0xcULL +#define DM_ABSTRACTAUTO_AUTOEXECDATA 0xfffULL #define DM_CONFSTRPTR0 0x19 -#define DM_CONFSTRPTR0_ADDR_OFFSET 0 -#define DM_CONFSTRPTR0_ADDR_LENGTH 0x20 -#define DM_CONFSTRPTR0_ADDR 0xffffffffU +#define DM_CONFSTRPTR0_ADDR_OFFSET 0ULL +#define DM_CONFSTRPTR0_ADDR_LENGTH 0x20ULL +#define DM_CONFSTRPTR0_ADDR 0xffffffffULL #define DM_CONFSTRPTR1 0x1a -#define DM_CONFSTRPTR1_ADDR_OFFSET 0 -#define DM_CONFSTRPTR1_ADDR_LENGTH 0x20 -#define DM_CONFSTRPTR1_ADDR 0xffffffffU +#define DM_CONFSTRPTR1_ADDR_OFFSET 0ULL +#define DM_CONFSTRPTR1_ADDR_LENGTH 0x20ULL +#define DM_CONFSTRPTR1_ADDR 0xffffffffULL #define DM_CONFSTRPTR2 0x1b -#define DM_CONFSTRPTR2_ADDR_OFFSET 0 -#define DM_CONFSTRPTR2_ADDR_LENGTH 0x20 -#define DM_CONFSTRPTR2_ADDR 0xffffffffU +#define DM_CONFSTRPTR2_ADDR_OFFSET 0ULL +#define DM_CONFSTRPTR2_ADDR_LENGTH 0x20ULL +#define DM_CONFSTRPTR2_ADDR 0xffffffffULL #define DM_CONFSTRPTR3 0x1c -#define DM_CONFSTRPTR3_ADDR_OFFSET 0 -#define DM_CONFSTRPTR3_ADDR_LENGTH 0x20 -#define DM_CONFSTRPTR3_ADDR 0xffffffffU +#define DM_CONFSTRPTR3_ADDR_OFFSET 0ULL +#define DM_CONFSTRPTR3_ADDR_LENGTH 0x20ULL +#define DM_CONFSTRPTR3_ADDR 0xffffffffULL #define DM_NEXTDM 0x1d -#define DM_NEXTDM_ADDR_OFFSET 0 -#define DM_NEXTDM_ADDR_LENGTH 0x20 -#define DM_NEXTDM_ADDR 0xffffffffU +#define DM_NEXTDM_ADDR_OFFSET 0ULL +#define DM_NEXTDM_ADDR_LENGTH 0x20ULL +#define DM_NEXTDM_ADDR 0xffffffffULL #define DM_DATA0 0x04 -#define DM_DATA0_DATA_OFFSET 0 -#define DM_DATA0_DATA_LENGTH 0x20 -#define DM_DATA0_DATA 0xffffffffU +#define DM_DATA0_DATA_OFFSET 0ULL +#define DM_DATA0_DATA_LENGTH 0x20ULL +#define DM_DATA0_DATA 0xffffffffULL #define DM_DATA1 0x05 #define DM_DATA2 0x06 #define DM_DATA3 0x07 @@ -2384,9 +2494,9 @@ #define DM_DATA10 0x0e #define DM_DATA11 0x0f #define DM_PROGBUF0 0x20 -#define DM_PROGBUF0_DATA_OFFSET 0 -#define DM_PROGBUF0_DATA_LENGTH 0x20 -#define DM_PROGBUF0_DATA 0xffffffffU +#define DM_PROGBUF0_DATA_OFFSET 0ULL +#define DM_PROGBUF0_DATA_LENGTH 0x20ULL +#define DM_PROGBUF0_DATA 0xffffffffULL #define DM_PROGBUF1 0x21 #define DM_PROGBUF2 0x22 #define DM_PROGBUF3 0x23 @@ -2403,13 +2513,13 @@ #define DM_PROGBUF14 0x2e #define DM_PROGBUF15 0x2f #define DM_AUTHDATA 0x30 -#define DM_AUTHDATA_DATA_OFFSET 0 -#define DM_AUTHDATA_DATA_LENGTH 0x20 -#define DM_AUTHDATA_DATA 0xffffffffU +#define DM_AUTHDATA_DATA_OFFSET 0ULL +#define DM_AUTHDATA_DATA_LENGTH 0x20ULL +#define DM_AUTHDATA_DATA 0xffffffffULL #define DM_DMCS2 0x32 -#define DM_DMCS2_GROUPTYPE_OFFSET 0xb -#define DM_DMCS2_GROUPTYPE_LENGTH 1 -#define DM_DMCS2_GROUPTYPE 0x800 +#define DM_DMCS2_GROUPTYPE_OFFSET 0xbULL +#define DM_DMCS2_GROUPTYPE_LENGTH 1ULL +#define DM_DMCS2_GROUPTYPE 0x800ULL /* * halt: The remaining fields in this register configure halt groups. */ @@ -2424,9 +2534,9 @@ * If a non-existent trigger value is written here, the hardware will * change it to a valid one or 0 if no DM external triggers exist. */ -#define DM_DMCS2_DMEXTTRIGGER_OFFSET 7 -#define DM_DMCS2_DMEXTTRIGGER_LENGTH 4 -#define DM_DMCS2_DMEXTTRIGGER 0x780 +#define DM_DMCS2_DMEXTTRIGGER_OFFSET 7ULL +#define DM_DMCS2_DMEXTTRIGGER_LENGTH 4ULL +#define DM_DMCS2_DMEXTTRIGGER 0x780ULL /* * When \FdmDmcsTwoHgselect is 0, contains the group of the hart * specified by \Fhartsel. @@ -2444,9 +2554,9 @@ * * If groups aren't implemented, then this entire field is 0. */ -#define DM_DMCS2_GROUP_OFFSET 2 -#define DM_DMCS2_GROUP_LENGTH 5 -#define DM_DMCS2_GROUP 0x7c +#define DM_DMCS2_GROUP_OFFSET 2ULL +#define DM_DMCS2_GROUP_LENGTH 5ULL +#define DM_DMCS2_GROUP 0x7cULL /* * When 1 is written and \FdmDmcsTwoHgselect is 0, for every selected * hart the DM will change its group to the value written to \FdmDmcsTwoGroup, @@ -2462,12 +2572,12 @@ * * Writing 0 has no effect. */ -#define DM_DMCS2_HGWRITE_OFFSET 1 -#define DM_DMCS2_HGWRITE_LENGTH 1 -#define DM_DMCS2_HGWRITE 2 -#define DM_DMCS2_HGSELECT_OFFSET 0 -#define DM_DMCS2_HGSELECT_LENGTH 1 -#define DM_DMCS2_HGSELECT 1 +#define DM_DMCS2_HGWRITE_OFFSET 1ULL +#define DM_DMCS2_HGWRITE_LENGTH 1ULL +#define DM_DMCS2_HGWRITE 2ULL +#define DM_DMCS2_HGSELECT_OFFSET 0ULL +#define DM_DMCS2_HGSELECT_LENGTH 1ULL +#define DM_DMCS2_HGSELECT 1ULL /* * harts: Operate on harts. */ @@ -2480,25 +2590,25 @@ * If there are no DM external triggers, this field must be tied to 0. */ #define DM_HALTSUM0 0x40 -#define DM_HALTSUM0_HALTSUM0_OFFSET 0 -#define DM_HALTSUM0_HALTSUM0_LENGTH 0x20 -#define DM_HALTSUM0_HALTSUM0 0xffffffffU +#define DM_HALTSUM0_HALTSUM0_OFFSET 0ULL +#define DM_HALTSUM0_HALTSUM0_LENGTH 0x20ULL +#define DM_HALTSUM0_HALTSUM0 0xffffffffULL #define DM_HALTSUM1 0x13 -#define DM_HALTSUM1_HALTSUM1_OFFSET 0 -#define DM_HALTSUM1_HALTSUM1_LENGTH 0x20 -#define DM_HALTSUM1_HALTSUM1 0xffffffffU +#define DM_HALTSUM1_HALTSUM1_OFFSET 0ULL +#define DM_HALTSUM1_HALTSUM1_LENGTH 0x20ULL +#define DM_HALTSUM1_HALTSUM1 0xffffffffULL #define DM_HALTSUM2 0x34 -#define DM_HALTSUM2_HALTSUM2_OFFSET 0 -#define DM_HALTSUM2_HALTSUM2_LENGTH 0x20 -#define DM_HALTSUM2_HALTSUM2 0xffffffffU +#define DM_HALTSUM2_HALTSUM2_OFFSET 0ULL +#define DM_HALTSUM2_HALTSUM2_LENGTH 0x20ULL +#define DM_HALTSUM2_HALTSUM2 0xffffffffULL #define DM_HALTSUM3 0x35 -#define DM_HALTSUM3_HALTSUM3_OFFSET 0 -#define DM_HALTSUM3_HALTSUM3_LENGTH 0x20 -#define DM_HALTSUM3_HALTSUM3 0xffffffffU +#define DM_HALTSUM3_HALTSUM3_OFFSET 0ULL +#define DM_HALTSUM3_HALTSUM3_LENGTH 0x20ULL +#define DM_HALTSUM3_HALTSUM3 0xffffffffULL #define DM_SBCS 0x38 -#define DM_SBCS_SBVERSION_OFFSET 0x1d -#define DM_SBCS_SBVERSION_LENGTH 3 -#define DM_SBCS_SBVERSION 0xe0000000U +#define DM_SBCS_SBVERSION_OFFSET 0x1dULL +#define DM_SBCS_SBVERSION_LENGTH 3ULL +#define DM_SBCS_SBVERSION 0xe0000000ULL /* * legacy: The System Bus interface conforms to mainline drafts of this * spec older than 1 January, 2018. @@ -2520,11 +2630,11 @@ * While this field is set, no more system bus accesses can be * initiated by the Debug Module. */ -#define DM_SBCS_SBBUSYERROR_OFFSET 0x16 -#define DM_SBCS_SBBUSYERROR_LENGTH 1 -#define DM_SBCS_SBBUSYERROR 0x400000 +#define DM_SBCS_SBBUSYERROR_OFFSET 0x16ULL +#define DM_SBCS_SBBUSYERROR_LENGTH 1ULL +#define DM_SBCS_SBBUSYERROR 0x400000ULL /* - * When 1, indicates the system bus master is busy. (Whether the + * When 1, indicates the system bus manager is busy. (Whether the * system bus itself is busy is related, but not the same thing.) This * bit goes high immediately when a read or write is requested for any * reason, and does not go low until the access is fully completed. @@ -2533,22 +2643,22 @@ * behavior. A debugger must not write to \RdmSbcs until it reads * \FdmSbcsSbbusy as 0. */ -#define DM_SBCS_SBBUSY_OFFSET 0x15 -#define DM_SBCS_SBBUSY_LENGTH 1 -#define DM_SBCS_SBBUSY 0x200000 +#define DM_SBCS_SBBUSY_OFFSET 0x15ULL +#define DM_SBCS_SBBUSY_LENGTH 1ULL +#define DM_SBCS_SBBUSY 0x200000ULL /* * When 1, every write to \RdmSbaddressZero automatically triggers a * system bus read at the new address. */ -#define DM_SBCS_SBREADONADDR_OFFSET 0x14 -#define DM_SBCS_SBREADONADDR_LENGTH 1 -#define DM_SBCS_SBREADONADDR 0x100000 +#define DM_SBCS_SBREADONADDR_OFFSET 0x14ULL +#define DM_SBCS_SBREADONADDR_LENGTH 1ULL +#define DM_SBCS_SBREADONADDR 0x100000ULL /* * Select the access size to use for system bus accesses. */ -#define DM_SBCS_SBACCESS_OFFSET 0x11 -#define DM_SBCS_SBACCESS_LENGTH 3 -#define DM_SBCS_SBACCESS 0xe0000 +#define DM_SBCS_SBACCESS_OFFSET 0x11ULL +#define DM_SBCS_SBACCESS_LENGTH 3ULL +#define DM_SBCS_SBACCESS 0xe0000ULL /* * 8bit: 8-bit */ @@ -2577,28 +2687,28 @@ * When 1, {\tt sbaddress} is incremented by the access size (in * bytes) selected in \FdmSbcsSbaccess after every system bus access. */ -#define DM_SBCS_SBAUTOINCREMENT_OFFSET 0x10 -#define DM_SBCS_SBAUTOINCREMENT_LENGTH 1 -#define DM_SBCS_SBAUTOINCREMENT 0x10000 +#define DM_SBCS_SBAUTOINCREMENT_OFFSET 0x10ULL +#define DM_SBCS_SBAUTOINCREMENT_LENGTH 1ULL +#define DM_SBCS_SBAUTOINCREMENT 0x10000ULL /* * When 1, every read from \RdmSbdataZero automatically triggers a * system bus read at the (possibly auto-incremented) address. */ -#define DM_SBCS_SBREADONDATA_OFFSET 0xf -#define DM_SBCS_SBREADONDATA_LENGTH 1 -#define DM_SBCS_SBREADONDATA 0x8000 +#define DM_SBCS_SBREADONDATA_OFFSET 0xfULL +#define DM_SBCS_SBREADONDATA_LENGTH 1ULL +#define DM_SBCS_SBREADONDATA 0x8000ULL /* * When the Debug Module's system bus - * master encounters an error, this field gets set. The bits in this + * manager encounters an error, this field gets set. The bits in this * field remain set until they are cleared by writing 1 to them. * While this field is non-zero, no more system bus accesses can be * initiated by the Debug Module. * * An implementation may report ``Other'' (7) for any error condition. */ -#define DM_SBCS_SBERROR_OFFSET 0xc -#define DM_SBCS_SBERROR_LENGTH 3 -#define DM_SBCS_SBERROR 0x7000 +#define DM_SBCS_SBERROR_OFFSET 0xcULL +#define DM_SBCS_SBERROR_LENGTH 3ULL +#define DM_SBCS_SBERROR 0x7000ULL /* * none: There was no bus error. */ @@ -2627,101 +2737,101 @@ * Width of system bus addresses in bits. (0 indicates there is no bus * access support.) */ -#define DM_SBCS_SBASIZE_OFFSET 5 -#define DM_SBCS_SBASIZE_LENGTH 7 -#define DM_SBCS_SBASIZE 0xfe0 +#define DM_SBCS_SBASIZE_OFFSET 5ULL +#define DM_SBCS_SBASIZE_LENGTH 7ULL +#define DM_SBCS_SBASIZE 0xfe0ULL /* * 1 when 128-bit system bus accesses are supported. */ -#define DM_SBCS_SBACCESS128_OFFSET 4 -#define DM_SBCS_SBACCESS128_LENGTH 1 -#define DM_SBCS_SBACCESS128 0x10 +#define DM_SBCS_SBACCESS128_OFFSET 4ULL +#define DM_SBCS_SBACCESS128_LENGTH 1ULL +#define DM_SBCS_SBACCESS128 0x10ULL /* * 1 when 64-bit system bus accesses are supported. */ -#define DM_SBCS_SBACCESS64_OFFSET 3 -#define DM_SBCS_SBACCESS64_LENGTH 1 -#define DM_SBCS_SBACCESS64 8 +#define DM_SBCS_SBACCESS64_OFFSET 3ULL +#define DM_SBCS_SBACCESS64_LENGTH 1ULL +#define DM_SBCS_SBACCESS64 8ULL /* * 1 when 32-bit system bus accesses are supported. */ -#define DM_SBCS_SBACCESS32_OFFSET 2 -#define DM_SBCS_SBACCESS32_LENGTH 1 -#define DM_SBCS_SBACCESS32 4 +#define DM_SBCS_SBACCESS32_OFFSET 2ULL +#define DM_SBCS_SBACCESS32_LENGTH 1ULL +#define DM_SBCS_SBACCESS32 4ULL /* * 1 when 16-bit system bus accesses are supported. */ -#define DM_SBCS_SBACCESS16_OFFSET 1 -#define DM_SBCS_SBACCESS16_LENGTH 1 -#define DM_SBCS_SBACCESS16 2 +#define DM_SBCS_SBACCESS16_OFFSET 1ULL +#define DM_SBCS_SBACCESS16_LENGTH 1ULL +#define DM_SBCS_SBACCESS16 2ULL /* * 1 when 8-bit system bus accesses are supported. */ -#define DM_SBCS_SBACCESS8_OFFSET 0 -#define DM_SBCS_SBACCESS8_LENGTH 1 -#define DM_SBCS_SBACCESS8 1 +#define DM_SBCS_SBACCESS8_OFFSET 0ULL +#define DM_SBCS_SBACCESS8_LENGTH 1ULL +#define DM_SBCS_SBACCESS8 1ULL #define DM_SBADDRESS0 0x39 /* * Accesses bits 31:0 of the physical address in {\tt sbaddress}. */ -#define DM_SBADDRESS0_ADDRESS_OFFSET 0 -#define DM_SBADDRESS0_ADDRESS_LENGTH 0x20 -#define DM_SBADDRESS0_ADDRESS 0xffffffffU +#define DM_SBADDRESS0_ADDRESS_OFFSET 0ULL +#define DM_SBADDRESS0_ADDRESS_LENGTH 0x20ULL +#define DM_SBADDRESS0_ADDRESS 0xffffffffULL #define DM_SBADDRESS1 0x3a /* * Accesses bits 63:32 of the physical address in {\tt sbaddress} (if * the system address bus is that wide). */ -#define DM_SBADDRESS1_ADDRESS_OFFSET 0 -#define DM_SBADDRESS1_ADDRESS_LENGTH 0x20 -#define DM_SBADDRESS1_ADDRESS 0xffffffffU +#define DM_SBADDRESS1_ADDRESS_OFFSET 0ULL +#define DM_SBADDRESS1_ADDRESS_LENGTH 0x20ULL +#define DM_SBADDRESS1_ADDRESS 0xffffffffULL #define DM_SBADDRESS2 0x3b /* * Accesses bits 95:64 of the physical address in {\tt sbaddress} (if * the system address bus is that wide). */ -#define DM_SBADDRESS2_ADDRESS_OFFSET 0 -#define DM_SBADDRESS2_ADDRESS_LENGTH 0x20 -#define DM_SBADDRESS2_ADDRESS 0xffffffffU +#define DM_SBADDRESS2_ADDRESS_OFFSET 0ULL +#define DM_SBADDRESS2_ADDRESS_LENGTH 0x20ULL +#define DM_SBADDRESS2_ADDRESS 0xffffffffULL #define DM_SBADDRESS3 0x37 /* * Accesses bits 127:96 of the physical address in {\tt sbaddress} (if * the system address bus is that wide). */ -#define DM_SBADDRESS3_ADDRESS_OFFSET 0 -#define DM_SBADDRESS3_ADDRESS_LENGTH 0x20 -#define DM_SBADDRESS3_ADDRESS 0xffffffffU +#define DM_SBADDRESS3_ADDRESS_OFFSET 0ULL +#define DM_SBADDRESS3_ADDRESS_LENGTH 0x20ULL +#define DM_SBADDRESS3_ADDRESS 0xffffffffULL #define DM_SBDATA0 0x3c /* * Accesses bits 31:0 of {\tt sbdata}. */ -#define DM_SBDATA0_DATA_OFFSET 0 -#define DM_SBDATA0_DATA_LENGTH 0x20 -#define DM_SBDATA0_DATA 0xffffffffU +#define DM_SBDATA0_DATA_OFFSET 0ULL +#define DM_SBDATA0_DATA_LENGTH 0x20ULL +#define DM_SBDATA0_DATA 0xffffffffULL #define DM_SBDATA1 0x3d /* * Accesses bits 63:32 of {\tt sbdata} (if the system bus is that * wide). */ -#define DM_SBDATA1_DATA_OFFSET 0 -#define DM_SBDATA1_DATA_LENGTH 0x20 -#define DM_SBDATA1_DATA 0xffffffffU +#define DM_SBDATA1_DATA_OFFSET 0ULL +#define DM_SBDATA1_DATA_LENGTH 0x20ULL +#define DM_SBDATA1_DATA 0xffffffffULL #define DM_SBDATA2 0x3e /* * Accesses bits 95:64 of {\tt sbdata} (if the system bus is that * wide). */ -#define DM_SBDATA2_DATA_OFFSET 0 -#define DM_SBDATA2_DATA_LENGTH 0x20 -#define DM_SBDATA2_DATA 0xffffffffU +#define DM_SBDATA2_DATA_OFFSET 0ULL +#define DM_SBDATA2_DATA_LENGTH 0x20ULL +#define DM_SBDATA2_DATA 0xffffffffULL #define DM_SBDATA3 0x3f /* * Accesses bits 127:96 of {\tt sbdata} (if the system bus is that * wide). */ -#define DM_SBDATA3_DATA_OFFSET 0 -#define DM_SBDATA3_DATA_LENGTH 0x20 -#define DM_SBDATA3_DATA 0xffffffffU +#define DM_SBDATA3_DATA_OFFSET 0ULL +#define DM_SBDATA3_DATA_LENGTH 0x20ULL +#define DM_SBDATA3_DATA 0xffffffffULL #define DM_CUSTOM 0x1f #define DM_CUSTOM0 0x70 #define DM_CUSTOM1 0x71 @@ -2743,18 +2853,18 @@ /* * Description of what this field is used for. */ -#define SHORTNAME_FIELD_OFFSET 0 -#define SHORTNAME_FIELD_LENGTH 8 -#define SHORTNAME_FIELD 0xff +#define SHORTNAME_FIELD_OFFSET 0ULL +#define SHORTNAME_FIELD_LENGTH 8ULL +#define SHORTNAME_FIELD 0xffULL /* * This is 0 to indicate Access Register Command. */ -#define AC_ACCESS_REGISTER_CMDTYPE_OFFSET 0x18 -#define AC_ACCESS_REGISTER_CMDTYPE_LENGTH 8 -#define AC_ACCESS_REGISTER_CMDTYPE 0xff000000U -#define AC_ACCESS_REGISTER_AARSIZE_OFFSET 0x14 -#define AC_ACCESS_REGISTER_AARSIZE_LENGTH 3 -#define AC_ACCESS_REGISTER_AARSIZE 0x700000 +#define AC_ACCESS_REGISTER_CMDTYPE_OFFSET 0x18ULL +#define AC_ACCESS_REGISTER_CMDTYPE_LENGTH 8ULL +#define AC_ACCESS_REGISTER_CMDTYPE 0xff000000ULL +#define AC_ACCESS_REGISTER_AARSIZE_OFFSET 0x14ULL +#define AC_ACCESS_REGISTER_AARSIZE_LENGTH 3ULL +#define AC_ACCESS_REGISTER_AARSIZE 0x700000ULL /* * 32bit: Access the lowest 32 bits of the register. */ @@ -2777,9 +2887,9 @@ * This field controls the Argument Width as referenced in * Table~\ref{tab:datareg}. */ -#define AC_ACCESS_REGISTER_AARPOSTINCREMENT_OFFSET 0x13 -#define AC_ACCESS_REGISTER_AARPOSTINCREMENT_LENGTH 1 -#define AC_ACCESS_REGISTER_AARPOSTINCREMENT 0x80000 +#define AC_ACCESS_REGISTER_AARPOSTINCREMENT_OFFSET 0x13ULL +#define AC_ACCESS_REGISTER_AARPOSTINCREMENT_LENGTH 1ULL +#define AC_ACCESS_REGISTER_AARPOSTINCREMENT 0x80000ULL /* * disabled: No effect. This variant must be supported. */ @@ -2792,9 +2902,9 @@ * happens when \FacAccessregisterTransfer is 0. */ #define AC_ACCESS_REGISTER_AARPOSTINCREMENT_ENABLED 1 -#define AC_ACCESS_REGISTER_POSTEXEC_OFFSET 0x12 -#define AC_ACCESS_REGISTER_POSTEXEC_LENGTH 1 -#define AC_ACCESS_REGISTER_POSTEXEC 0x40000 +#define AC_ACCESS_REGISTER_POSTEXEC_OFFSET 0x12ULL +#define AC_ACCESS_REGISTER_POSTEXEC_LENGTH 1ULL +#define AC_ACCESS_REGISTER_POSTEXEC 0x40000ULL /* * disabled: No effect. This variant must be supported, and is the only * supported one if \FdmAbstractcsProgbufsize is 0. @@ -2806,9 +2916,9 @@ * optional. */ #define AC_ACCESS_REGISTER_POSTEXEC_ENABLED 1 -#define AC_ACCESS_REGISTER_TRANSFER_OFFSET 0x11 -#define AC_ACCESS_REGISTER_TRANSFER_LENGTH 1 -#define AC_ACCESS_REGISTER_TRANSFER 0x20000 +#define AC_ACCESS_REGISTER_TRANSFER_OFFSET 0x11ULL +#define AC_ACCESS_REGISTER_TRANSFER_LENGTH 1ULL +#define AC_ACCESS_REGISTER_TRANSFER 0x20000ULL /* * disabled: Don't do the operation specified by \FacAccessregisterWrite. */ @@ -2824,9 +2934,9 @@ /* * When \FacAccessregisterTransfer is set: */ -#define AC_ACCESS_REGISTER_WRITE_OFFSET 0x10 -#define AC_ACCESS_REGISTER_WRITE_LENGTH 1 -#define AC_ACCESS_REGISTER_WRITE 0x10000 +#define AC_ACCESS_REGISTER_WRITE_OFFSET 0x10ULL +#define AC_ACCESS_REGISTER_WRITE_LENGTH 1ULL +#define AC_ACCESS_REGISTER_WRITE 0x10000ULL /* * arg0: Copy data from the specified register into {\tt arg0} portion * of {\tt data}. @@ -2843,29 +2953,29 @@ * \RcsrDpc may be used as an alias for PC if this command is * supported on a non-halted hart. */ -#define AC_ACCESS_REGISTER_REGNO_OFFSET 0 -#define AC_ACCESS_REGISTER_REGNO_LENGTH 0x10 -#define AC_ACCESS_REGISTER_REGNO 0xffff +#define AC_ACCESS_REGISTER_REGNO_OFFSET 0ULL +#define AC_ACCESS_REGISTER_REGNO_LENGTH 0x10ULL +#define AC_ACCESS_REGISTER_REGNO 0xffffULL /* * This is 1 to indicate Quick Access command. */ -#define AC_QUICK_ACCESS_CMDTYPE_OFFSET 0x18 -#define AC_QUICK_ACCESS_CMDTYPE_LENGTH 8 -#define AC_QUICK_ACCESS_CMDTYPE 0xff000000U +#define AC_QUICK_ACCESS_CMDTYPE_OFFSET 0x18ULL +#define AC_QUICK_ACCESS_CMDTYPE_LENGTH 8ULL +#define AC_QUICK_ACCESS_CMDTYPE 0xff000000ULL /* * This is 2 to indicate Access Memory Command. */ -#define AC_ACCESS_MEMORY_CMDTYPE_OFFSET 0x18 -#define AC_ACCESS_MEMORY_CMDTYPE_LENGTH 8 -#define AC_ACCESS_MEMORY_CMDTYPE 0xff000000U +#define AC_ACCESS_MEMORY_CMDTYPE_OFFSET 0x18ULL +#define AC_ACCESS_MEMORY_CMDTYPE_LENGTH 8ULL +#define AC_ACCESS_MEMORY_CMDTYPE 0xff000000ULL /* * An implementation does not have to implement both virtual and * physical accesses, but it must fail accesses that it doesn't * support. */ -#define AC_ACCESS_MEMORY_AAMVIRTUAL_OFFSET 0x17 -#define AC_ACCESS_MEMORY_AAMVIRTUAL_LENGTH 1 -#define AC_ACCESS_MEMORY_AAMVIRTUAL 0x800000 +#define AC_ACCESS_MEMORY_AAMVIRTUAL_OFFSET 0x17ULL +#define AC_ACCESS_MEMORY_AAMVIRTUAL_LENGTH 1ULL +#define AC_ACCESS_MEMORY_AAMVIRTUAL 0x800000ULL /* * physical: Addresses are physical (to the hart they are performed on). */ @@ -2880,9 +2990,9 @@ * may optionally allow \FacAccessmemoryAamvirtual set to 1, which would produce the same result as * that same abstract command with \FacAccessmemoryAamvirtual cleared. */ -#define AC_ACCESS_MEMORY_AAMSIZE_OFFSET 0x14 -#define AC_ACCESS_MEMORY_AAMSIZE_LENGTH 3 -#define AC_ACCESS_MEMORY_AAMSIZE 0x700000 +#define AC_ACCESS_MEMORY_AAMSIZE_OFFSET 0x14ULL +#define AC_ACCESS_MEMORY_AAMSIZE_LENGTH 3ULL +#define AC_ACCESS_MEMORY_AAMSIZE 0x700000ULL /* * 8bit: Access the lowest 8 bits of the memory location. */ @@ -2911,12 +3021,12 @@ * Supporting this variant is optional, but highly recommended for * performance reasons. */ -#define AC_ACCESS_MEMORY_AAMPOSTINCREMENT_OFFSET 0x13 -#define AC_ACCESS_MEMORY_AAMPOSTINCREMENT_LENGTH 1 -#define AC_ACCESS_MEMORY_AAMPOSTINCREMENT 0x80000 -#define AC_ACCESS_MEMORY_WRITE_OFFSET 0x10 -#define AC_ACCESS_MEMORY_WRITE_LENGTH 1 -#define AC_ACCESS_MEMORY_WRITE 0x10000 +#define AC_ACCESS_MEMORY_AAMPOSTINCREMENT_OFFSET 0x13ULL +#define AC_ACCESS_MEMORY_AAMPOSTINCREMENT_LENGTH 1ULL +#define AC_ACCESS_MEMORY_AAMPOSTINCREMENT 0x80000ULL +#define AC_ACCESS_MEMORY_WRITE_OFFSET 0x10ULL +#define AC_ACCESS_MEMORY_WRITE_LENGTH 1ULL +#define AC_ACCESS_MEMORY_WRITE 0x10000ULL /* * arg0: Copy data from the memory location specified in {\tt arg1} into * the low bits of {\tt arg0}. The value of the remaining bits of @@ -2931,9 +3041,9 @@ /* * These bits are reserved for target-specific uses. */ -#define AC_ACCESS_MEMORY_TARGET_SPECIFIC_OFFSET 0xe -#define AC_ACCESS_MEMORY_TARGET_SPECIFIC_LENGTH 2 -#define AC_ACCESS_MEMORY_TARGET_SPECIFIC 0xc000 +#define AC_ACCESS_MEMORY_TARGET_SPECIFIC_OFFSET 0xeULL +#define AC_ACCESS_MEMORY_TARGET_SPECIFIC_LENGTH 2ULL +#define AC_ACCESS_MEMORY_TARGET_SPECIFIC 0xc000ULL #define VIRT_PRIV virtual /* * Contains the virtualization mode the hart was operating in when Debug @@ -2942,9 +3052,9 @@ * A user can write this value to change the hart's virtualization mode * when exiting Debug Mode. */ -#define VIRT_PRIV_V_OFFSET 2 -#define VIRT_PRIV_V_LENGTH 1 -#define VIRT_PRIV_V 4 +#define VIRT_PRIV_V_OFFSET 2ULL +#define VIRT_PRIV_V_LENGTH 1ULL +#define VIRT_PRIV_V 4ULL /* * Contains the privilege mode the hart was operating in when Debug * Mode was entered. The encoding is described in Table @@ -2952,110 +3062,95 @@ * the Privileged Spec. A user can write this * value to change the hart's privilege mode when exiting Debug Mode. */ -#define VIRT_PRIV_PRV_OFFSET 0 -#define VIRT_PRIV_PRV_LENGTH 2 -#define VIRT_PRIV_PRV 3 -#define DMI_SERCS 0x34 -/* - * Number of supported serial ports. - */ -#define DMI_SERCS_SERIALCOUNT_OFFSET 0x1c -#define DMI_SERCS_SERIALCOUNT_LENGTH 4 -#define DMI_SERCS_SERIALCOUNT 0xf0000000U -/* - * Select which serial port is accessed by \RdmiSerrx and \RdmiSertx. - */ -#define DMI_SERCS_SERIAL_OFFSET 0x18 -#define DMI_SERCS_SERIAL_LENGTH 3 -#define DMI_SERCS_SERIAL 0x7000000 -#define DMI_SERCS_ERROR7_OFFSET 0x17 -#define DMI_SERCS_ERROR7_LENGTH 1 -#define DMI_SERCS_ERROR7 0x800000 -#define DMI_SERCS_VALID7_OFFSET 0x16 -#define DMI_SERCS_VALID7_LENGTH 1 -#define DMI_SERCS_VALID7 0x400000 -#define DMI_SERCS_FULL7_OFFSET 0x15 -#define DMI_SERCS_FULL7_LENGTH 1 -#define DMI_SERCS_FULL7 0x200000 -#define DMI_SERCS_ERROR6_OFFSET 0x14 -#define DMI_SERCS_ERROR6_LENGTH 1 -#define DMI_SERCS_ERROR6 0x100000 -#define DMI_SERCS_VALID6_OFFSET 0x13 -#define DMI_SERCS_VALID6_LENGTH 1 -#define DMI_SERCS_VALID6 0x80000 -#define DMI_SERCS_FULL6_OFFSET 0x12 -#define DMI_SERCS_FULL6_LENGTH 1 -#define DMI_SERCS_FULL6 0x40000 -#define DMI_SERCS_ERROR5_OFFSET 0x11 -#define DMI_SERCS_ERROR5_LENGTH 1 -#define DMI_SERCS_ERROR5 0x20000 -#define DMI_SERCS_VALID5_OFFSET 0x10 -#define DMI_SERCS_VALID5_LENGTH 1 -#define DMI_SERCS_VALID5 0x10000 -#define DMI_SERCS_FULL5_OFFSET 0xf -#define DMI_SERCS_FULL5_LENGTH 1 -#define DMI_SERCS_FULL5 0x8000 -#define DMI_SERCS_ERROR4_OFFSET 0xe -#define DMI_SERCS_ERROR4_LENGTH 1 -#define DMI_SERCS_ERROR4 0x4000 -#define DMI_SERCS_VALID4_OFFSET 0xd -#define DMI_SERCS_VALID4_LENGTH 1 -#define DMI_SERCS_VALID4 0x2000 -#define DMI_SERCS_FULL4_OFFSET 0xc -#define DMI_SERCS_FULL4_LENGTH 1 -#define DMI_SERCS_FULL4 0x1000 -#define DMI_SERCS_ERROR3_OFFSET 0xb -#define DMI_SERCS_ERROR3_LENGTH 1 -#define DMI_SERCS_ERROR3 0x800 -#define DMI_SERCS_VALID3_OFFSET 0xa -#define DMI_SERCS_VALID3_LENGTH 1 -#define DMI_SERCS_VALID3 0x400 -#define DMI_SERCS_FULL3_OFFSET 9 -#define DMI_SERCS_FULL3_LENGTH 1 -#define DMI_SERCS_FULL3 0x200 -#define DMI_SERCS_ERROR2_OFFSET 8 -#define DMI_SERCS_ERROR2_LENGTH 1 -#define DMI_SERCS_ERROR2 0x100 -#define DMI_SERCS_VALID2_OFFSET 7 -#define DMI_SERCS_VALID2_LENGTH 1 -#define DMI_SERCS_VALID2 0x80 -#define DMI_SERCS_FULL2_OFFSET 6 -#define DMI_SERCS_FULL2_LENGTH 1 -#define DMI_SERCS_FULL2 0x40 -#define DMI_SERCS_ERROR1_OFFSET 5 -#define DMI_SERCS_ERROR1_LENGTH 1 -#define DMI_SERCS_ERROR1 0x20 -#define DMI_SERCS_VALID1_OFFSET 4 -#define DMI_SERCS_VALID1_LENGTH 1 -#define DMI_SERCS_VALID1 0x10 -#define DMI_SERCS_FULL1_OFFSET 3 -#define DMI_SERCS_FULL1_LENGTH 1 -#define DMI_SERCS_FULL1 8 -/* - * 1 when the debugger-to-core queue for serial port 0 has - * over or underflowed. This bit will remain set until it is reset by - * writing 1 to this bit. - */ -#define DMI_SERCS_ERROR0_OFFSET 2 -#define DMI_SERCS_ERROR0_LENGTH 1 -#define DMI_SERCS_ERROR0 4 -/* - * 1 when the core-to-debugger queue for serial port 0 is not empty. - */ -#define DMI_SERCS_VALID0_OFFSET 1 -#define DMI_SERCS_VALID0_LENGTH 1 -#define DMI_SERCS_VALID0 2 -/* - * 1 when the debugger-to-core queue for serial port 0 is full. - */ -#define DMI_SERCS_FULL0_OFFSET 0 -#define DMI_SERCS_FULL0_LENGTH 1 -#define DMI_SERCS_FULL0 1 -#define DMI_SERTX 0x35 -#define DMI_SERTX_DATA_OFFSET 0 -#define DMI_SERTX_DATA_LENGTH 0x20 -#define DMI_SERTX_DATA 0xffffffffU -#define DMI_SERRX 0x36 -#define DMI_SERRX_DATA_OFFSET 0 -#define DMI_SERRX_DATA_LENGTH 0x20 -#define DMI_SERRX_DATA 0xffffffffU +#define VIRT_PRIV_PRV_OFFSET 0ULL +#define VIRT_PRIV_PRV_LENGTH 2ULL +#define VIRT_PRIV_PRV 3ULL +enum riscv_debug_reg_ordinal { + DTM_IDCODE_ORDINAL, + DTM_DTMCS_ORDINAL, + DTM_DMI_ORDINAL, + DTM_BYPASS_ORDINAL, + CSR_DCSR_ORDINAL, + CSR_DPC_ORDINAL, + CSR_DSCRATCH0_ORDINAL, + CSR_DSCRATCH1_ORDINAL, + CSR_TSELECT_ORDINAL, + CSR_TDATA1_ORDINAL, + CSR_TDATA2_ORDINAL, + CSR_TDATA3_ORDINAL, + CSR_TINFO_ORDINAL, + CSR_TCONTROL_ORDINAL, + CSR_SCONTEXT_ORDINAL, + CSR_MCONTEXT_ORDINAL, + CSR_MCONTROL_ORDINAL, + CSR_MCONTROL6_ORDINAL, + CSR_ICOUNT_ORDINAL, + CSR_ITRIGGER_ORDINAL, + CSR_ETRIGGER_ORDINAL, + CSR_TMEXTTRIGGER_ORDINAL, + CSR_TEXTRA32_ORDINAL, + CSR_TEXTRA64_ORDINAL, + DM_DMSTATUS_ORDINAL, + DM_DMCONTROL_ORDINAL, + DM_HARTINFO_ORDINAL, + DM_HAWINDOWSEL_ORDINAL, + DM_HAWINDOW_ORDINAL, + DM_ABSTRACTCS_ORDINAL, + DM_COMMAND_ORDINAL, + DM_ABSTRACTAUTO_ORDINAL, + DM_CONFSTRPTR0_ORDINAL, + DM_CONFSTRPTR1_ORDINAL, + DM_CONFSTRPTR2_ORDINAL, + DM_CONFSTRPTR3_ORDINAL, + DM_NEXTDM_ORDINAL, + DM_DATA0_ORDINAL, + DM_PROGBUF0_ORDINAL, + DM_AUTHDATA_ORDINAL, + DM_DMCS2_ORDINAL, + DM_HALTSUM0_ORDINAL, + DM_HALTSUM1_ORDINAL, + DM_HALTSUM2_ORDINAL, + DM_HALTSUM3_ORDINAL, + DM_SBCS_ORDINAL, + DM_SBADDRESS0_ORDINAL, + DM_SBADDRESS1_ORDINAL, + DM_SBADDRESS2_ORDINAL, + DM_SBADDRESS3_ORDINAL, + DM_SBDATA0_ORDINAL, + DM_SBDATA1_ORDINAL, + DM_SBDATA2_ORDINAL, + DM_SBDATA3_ORDINAL, + SHORTNAME_ORDINAL, + AC_ACCESS_REGISTER_ORDINAL, + AC_QUICK_ACCESS_ORDINAL, + AC_ACCESS_MEMORY_ORDINAL, + VIRT_PRIV_ORDINAL +}; +typedef struct { + struct { + unsigned int value; int is_set; + } DXLEN; + struct { + unsigned int value; int is_set; + } XLEN; + struct { + unsigned int value; int is_set; + } abits; +} riscv_debug_reg_ctx_t; + +typedef struct { + const char *name; + unsigned int lsb; // inclusive + unsigned int msb; // inclusive + const char **values; // If non-NULL, array of human-readable string for each possible value +} riscv_debug_reg_field_info_t; +typedef struct riscv_debug_reg_field_list_t { + riscv_debug_reg_field_info_t field; + struct riscv_debug_reg_field_list_t (*get_next)(riscv_debug_reg_ctx_t context); +} riscv_debug_reg_field_list_t; +typedef struct { + const char *name; + struct riscv_debug_reg_field_list_t (* const get_fields_head)(riscv_debug_reg_ctx_t context); +} riscv_debug_reg_info_t; +riscv_debug_reg_info_t get_riscv_debug_reg_info(enum riscv_debug_reg_ordinal reg_ordinal); +#endif diff --git a/src/target/riscv/debug_reg_printer.c b/src/target/riscv/debug_reg_printer.c new file mode 100644 index 0000000000..fc7dabd265 --- /dev/null +++ b/src/target/riscv/debug_reg_printer.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <stdio.h> +#include <inttypes.h> +#include <assert.h> +#include <stdarg.h> + +#include "debug_reg_printer.h" + +static unsigned int get_len_or_sprintf(char *buf, unsigned int curr, const char *format, ...) +{ + assert(format); + va_list args; + int length; + + va_start(args, format); + if (buf) + length = vsprintf(buf + curr, format, args); + else + length = vsnprintf(NULL, 0, format, args); + va_end(args); + assert(length >= 0); + return (unsigned int)length; +} + +static unsigned int print_number(char *buf, unsigned int offset, uint64_t value) +{ + const char * const format = value > 9 ? "0x%" PRIx64 : "%" PRIx64; + + return get_len_or_sprintf(buf, offset, format, value); +} + +static unsigned int riscv_debug_reg_field_value_to_s(char *buf, unsigned int offset, + const char * const *field_value_names, uint64_t field_value) +{ + const char * const field_value_name = field_value_names ? + field_value_names[field_value] : + NULL; + + if (!field_value_name) + return print_number(buf, offset, field_value); + return get_len_or_sprintf(buf, offset, "%s", field_value_name); +} + +static unsigned int riscv_debug_reg_field_to_s(char *buf, unsigned int offset, + riscv_debug_reg_field_info_t field, riscv_debug_reg_ctx_t context, + uint64_t field_value) +{ + const unsigned int name_len = get_len_or_sprintf(buf, offset, "%s=", field.name); + + return name_len + riscv_debug_reg_field_value_to_s(buf, offset + name_len, + field.values, field_value); +} + +static uint64_t riscv_debug_reg_field_value(riscv_debug_reg_field_info_t field, uint64_t value) +{ + assert(field.msb < 64); + assert(field.msb >= field.lsb); + const uint64_t trailing_ones_mask = (uint64_t)(-1) >> (63 - field.msb); + return (value & trailing_ones_mask) >> field.lsb; +} + +static unsigned int riscv_debug_reg_fields_to_s(char *buf, unsigned int offset, + struct riscv_debug_reg_field_list_t (*get_next)(riscv_debug_reg_ctx_t contex), + riscv_debug_reg_ctx_t context, uint64_t value, + enum riscv_debug_reg_show show) +{ + unsigned int curr = offset; + curr += get_len_or_sprintf(buf, curr, " {"); + char *separator = ""; + for (struct riscv_debug_reg_field_list_t list; get_next; get_next = list.get_next) { + list = get_next(context); + + uint64_t field_value = riscv_debug_reg_field_value(list.field, value); + + if (show == RISCV_DEBUG_REG_SHOW_ALL || + (show == RISCV_DEBUG_REG_HIDE_UNNAMED_0 && + (field_value != 0 || + (list.field.values && list.field.values[0]))) || + (show == RISCV_DEBUG_REG_HIDE_ALL_0 && field_value != 0)) { + curr += get_len_or_sprintf(buf, curr, separator); + curr += riscv_debug_reg_field_to_s(buf, curr, list.field, context, + field_value); + separator = " "; + } + } + curr += get_len_or_sprintf(buf, curr, "}"); + return curr - offset; +} + +unsigned int riscv_debug_reg_to_s(char *buf, enum riscv_debug_reg_ordinal reg_ordinal, + riscv_debug_reg_ctx_t context, uint64_t value, + enum riscv_debug_reg_show show) +{ + unsigned int length = 0; + + riscv_debug_reg_info_t reg = get_riscv_debug_reg_info(reg_ordinal); + + length += get_len_or_sprintf(buf, length, "%s=", reg.name); + length += print_number(buf, length, value); + + if (reg.get_fields_head) + length += riscv_debug_reg_fields_to_s(buf, length, + reg.get_fields_head, context, value, show); + + if (buf) + buf[length] = '\0'; + return length; +} diff --git a/src/target/riscv/debug_reg_printer.h b/src/target/riscv/debug_reg_printer.h new file mode 100644 index 0000000000..98226b7729 --- /dev/null +++ b/src/target/riscv/debug_reg_printer.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "debug_defines.h" + +enum riscv_debug_reg_show { + RISCV_DEBUG_REG_SHOW_ALL, + RISCV_DEBUG_REG_HIDE_ALL_0, + RISCV_DEBUG_REG_HIDE_UNNAMED_0, +}; + +/** + * This function is used to fill a buffer with a decoded string representation + * of register's value. + * @param buf If non-NULL, the buffer to write the string into. + * Otherwise, the function does not perform any writes, + * it just calculates the number of characters used. + * @param reg_ordinal + * The ordinal of the register. + * @param context The structure, containing the information about the target, + * necessary to decode the register. + * @param value The value to be decoded. + * + * Returns the number of characters used by the string representation + * (excluding '\0'). + * + * Example: + * const struct riscv_debug_reg_ctx_t context = { + * .abits = { .value = <abits value>, .is_set = true } + * }; + * char buf[riscv_debug_reg_to_s(NULL, DTM_DMI_ORDINAL, context, <dmi value>) + 1] + * riscv_debug_reg_to_s(buf, DTM_DMI_ORDINAL, context, <dmi value>); + */ +unsigned int riscv_debug_reg_to_s(char *buf, enum riscv_debug_reg_ordinal reg_ordinal, + riscv_debug_reg_ctx_t context, uint64_t value, + enum riscv_debug_reg_show show); diff --git a/src/target/riscv/encoding.h b/src/target/riscv/encoding.h index c2da4e6767..3ac537c377 100644 --- a/src/target/riscv/encoding.h +++ b/src/target/riscv/encoding.h @@ -1,10 +1,10 @@ /* SPDX-License-Identifier: BSD-3-Clause */ -/* Copyright (c) 2022 RISC-V International */ +/* Copyright (c) 2023 RISC-V International */ /* * This file is auto-generated by running 'make' in - * https://github.com/riscv/riscv-opcodes (dcdf8d3) + * https://github.com/riscv/riscv-opcodes (ed68c21) */ #ifndef RISCV_CSR_ENCODING_H @@ -156,14 +156,17 @@ #define MENVCFG_CBIE 0x00000030 #define MENVCFG_CBCFE 0x00000040 #define MENVCFG_CBZE 0x00000080 +#define MENVCFG_HADE 0x2000000000000000 #define MENVCFG_PBMTE 0x4000000000000000 #define MENVCFG_STCE 0x8000000000000000 +#define MENVCFGH_HADE 0x20000000 #define MENVCFGH_PBMTE 0x40000000 #define MENVCFGH_STCE 0x80000000 #define MSTATEEN0_CS 0x00000001 #define MSTATEEN0_FCSR 0x00000002 +#define MSTATEEN0_JVT 0x00000004 #define MSTATEEN0_HCONTEXT 0x0200000000000000 #define MSTATEEN0_HENVCFG 0x4000000000000000 #define MSTATEEN_HSTATEEN 0x8000000000000000 @@ -190,14 +193,17 @@ #define HENVCFG_CBIE 0x00000030 #define HENVCFG_CBCFE 0x00000040 #define HENVCFG_CBZE 0x00000080 +#define HENVCFG_HADE 0x2000000000000000 #define HENVCFG_PBMTE 0x4000000000000000 #define HENVCFG_STCE 0x8000000000000000 +#define HENVCFGH_HADE 0x20000000 #define HENVCFGH_PBMTE 0x40000000 #define HENVCFGH_STCE 0x80000000 #define HSTATEEN0_CS 0x00000001 #define HSTATEEN0_FCSR 0x00000002 +#define HSTATEEN0_JVT 0x00000004 #define HSTATEEN0_SCONTEXT 0x0200000000000000 #define HSTATEEN0_SENVCFG 0x4000000000000000 #define HSTATEEN_SSTATEEN 0x8000000000000000 @@ -213,6 +219,7 @@ #define SSTATEEN0_CS 0x00000001 #define SSTATEEN0_FCSR 0x00000002 +#define SSTATEEN0_JVT 0x00000004 #define MSECCFG_MML 0x00000001 #define MSECCFG_MMWP 0x00000002 @@ -220,6 +227,10 @@ #define MSECCFG_USEED 0x00000100 #define MSECCFG_SSEED 0x00000200 +/* jvt fields */ +#define JVT_MODE 0x3F +#define JVT_BASE (~0x3F) + #define PRV_U 0 #define PRV_S 1 #define PRV_M 3 @@ -366,12 +377,8 @@ #define MASK_ADD8 0xfe00707f #define MATCH_ADD_UW 0x800003b #define MASK_ADD_UW 0xfe00707f -#define MATCH_ADDD 0x7b -#define MASK_ADDD 0xfe00707f #define MATCH_ADDI 0x13 #define MASK_ADDI 0x707f -#define MATCH_ADDID 0x5b -#define MASK_ADDID 0x707f #define MATCH_ADDIW 0x1b #define MASK_ADDIW 0x707f #define MATCH_ADDW 0x3b @@ -474,10 +481,6 @@ #define MASK_BINV 0xfe00707f #define MATCH_BINVI 0x68001013 #define MASK_BINVI 0xfc00707f -#define MATCH_BITREV 0xe6000077 -#define MASK_BITREV 0xfe00707f -#define MATCH_BITREVI 0xe8000077 -#define MASK_BITREVI 0xfc00707f #define MATCH_BLT 0x4063 #define MASK_BLT 0x707f #define MATCH_BLTU 0x6063 @@ -490,8 +493,6 @@ #define MASK_BMATXOR 0xfe00707f #define MATCH_BNE 0x1063 #define MASK_BNE 0x707f -#define MATCH_BPICK 0x3077 -#define MASK_BPICK 0x600707f #define MATCH_BSET 0x28001033 #define MASK_BSET 0xfe00707f #define MATCH_BSETI 0x28001013 @@ -542,38 +543,48 @@ #define MASK_C_JALR 0xf07f #define MATCH_C_JR 0x8002 #define MASK_C_JR 0xf07f +#define MATCH_C_LBU 0x8000 +#define MASK_C_LBU 0xfc03 #define MATCH_C_LD 0x6000 #define MASK_C_LD 0xe003 #define MATCH_C_LDSP 0x6002 #define MASK_C_LDSP 0xe003 +#define MATCH_C_LH 0x8440 +#define MASK_C_LH 0xfc43 +#define MATCH_C_LHU 0x8400 +#define MASK_C_LHU 0xfc43 #define MATCH_C_LI 0x4001 #define MASK_C_LI 0xe003 -#define MATCH_C_LQ 0x2000 -#define MASK_C_LQ 0xe003 -#define MATCH_C_LQSP 0x2002 -#define MASK_C_LQSP 0xe003 #define MATCH_C_LUI 0x6001 #define MASK_C_LUI 0xe003 #define MATCH_C_LW 0x4000 #define MASK_C_LW 0xe003 #define MATCH_C_LWSP 0x4002 #define MASK_C_LWSP 0xe003 +#define MATCH_C_MUL 0x9c41 +#define MASK_C_MUL 0xfc63 #define MATCH_C_MV 0x8002 #define MASK_C_MV 0xf003 #define MATCH_C_NOP 0x1 #define MASK_C_NOP 0xef83 +#define MATCH_C_NOT 0x9c75 +#define MASK_C_NOT 0xfc7f #define MATCH_C_OR 0x8c41 #define MASK_C_OR 0xfc63 +#define MATCH_C_SB 0x8800 +#define MASK_C_SB 0xfc03 #define MATCH_C_SD 0xe000 #define MASK_C_SD 0xe003 #define MATCH_C_SDSP 0xe002 #define MASK_C_SDSP 0xe003 +#define MATCH_C_SEXT_B 0x9c65 +#define MASK_C_SEXT_B 0xfc7f +#define MATCH_C_SEXT_H 0x9c6d +#define MASK_C_SEXT_H 0xfc7f +#define MATCH_C_SH 0x8c00 +#define MASK_C_SH 0xfc43 #define MATCH_C_SLLI 0x2 #define MASK_C_SLLI 0xe003 -#define MATCH_C_SQ 0xa000 -#define MASK_C_SQ 0xe003 -#define MATCH_C_SQSP 0xa002 -#define MASK_C_SQSP 0xe003 #define MATCH_C_SRAI 0x8401 #define MASK_C_SRAI 0xec03 #define MATCH_C_SRLI 0x8001 @@ -588,6 +599,12 @@ #define MASK_C_SWSP 0xe003 #define MATCH_C_XOR 0x8c21 #define MASK_C_XOR 0xfc63 +#define MATCH_C_ZEXT_B 0x9c61 +#define MASK_C_ZEXT_B 0xfc7f +#define MATCH_C_ZEXT_H 0x9c69 +#define MASK_C_ZEXT_H 0xfc7f +#define MATCH_C_ZEXT_W 0x9c71 +#define MASK_C_ZEXT_W 0xfc7f #define MATCH_CBO_CLEAN 0x10200f #define MASK_CBO_CLEAN 0xfff07fff #define MATCH_CBO_FLUSH 0x20200f @@ -602,12 +619,6 @@ #define MASK_CLMULH 0xfe00707f #define MATCH_CLMULR 0xa002033 #define MASK_CLMULR 0xfe00707f -#define MATCH_CLO16 0xaeb00077 -#define MASK_CLO16 0xfff0707f -#define MATCH_CLO32 0xafb00077 -#define MASK_CLO32 0xfff0707f -#define MATCH_CLO8 0xae300077 -#define MASK_CLO8 0xfff0707f #define MATCH_CLRS16 0xae800077 #define MASK_CLRS16 0xfff0707f #define MATCH_CLRS32 0xaf800077 @@ -624,6 +635,20 @@ #define MASK_CLZ8 0xfff0707f #define MATCH_CLZW 0x6000101b #define MASK_CLZW 0xfff0707f +#define MATCH_CM_JALT 0xa002 +#define MASK_CM_JALT 0xfc03 +#define MATCH_CM_MVA01S 0xac62 +#define MASK_CM_MVA01S 0xfc63 +#define MATCH_CM_MVSA01 0xac22 +#define MASK_CM_MVSA01 0xfc63 +#define MATCH_CM_POP 0xba02 +#define MASK_CM_POP 0xff03 +#define MATCH_CM_POPRET 0xbe02 +#define MASK_CM_POPRET 0xff03 +#define MATCH_CM_POPRETZ 0xbc02 +#define MASK_CM_POPRETZ 0xff03 +#define MATCH_CM_PUSH 0xb802 +#define MASK_CM_PUSH 0xff03 #define MATCH_CMIX 0x6001033 #define MASK_CMIX 0x600707f #define MATCH_CMOV 0x6005033 @@ -676,6 +701,10 @@ #define MASK_CTZ 0xfff0707f #define MATCH_CTZW 0x6010101b #define MASK_CTZW 0xfff0707f +#define MATCH_CZERO_EQZ 0xe005033 +#define MASK_CZERO_EQZ 0xfe00707f +#define MATCH_CZERO_NEZ 0xe007033 +#define MASK_CZERO_NEZ 0xfe00707f #define MATCH_DIV 0x2004033 #define MASK_DIV 0xfe00707f #define MATCH_DIVU 0x2005033 @@ -1238,14 +1267,10 @@ #define MASK_LBU 0x707f #define MATCH_LD 0x3003 #define MASK_LD 0x707f -#define MATCH_LDU 0x7003 -#define MASK_LDU 0x707f #define MATCH_LH 0x1003 #define MASK_LH 0x707f #define MATCH_LHU 0x5003 #define MASK_LHU 0x707f -#define MATCH_LQ 0x300f -#define MASK_LQ 0x707f #define MATCH_LR_D 0x1000302f #define MASK_LR_D 0xf9f0707f #define MATCH_LR_W 0x1000202f @@ -1262,14 +1287,10 @@ #define MASK_MAX 0xfe00707f #define MATCH_MAXU 0xa007033 #define MASK_MAXU 0xfe00707f -#define MATCH_MAXW 0xf2000077 -#define MASK_MAXW 0xfe00707f #define MATCH_MIN 0xa004033 #define MASK_MIN 0xfe00707f #define MATCH_MINU 0xa005033 #define MASK_MINU 0xfe00707f -#define MATCH_MINW 0xf0000077 -#define MASK_MINW 0xfe00707f #define MATCH_MRET 0x30200073 #define MASK_MRET 0xffffffff #define MATCH_MSUBR32 0xc6001077 @@ -1312,8 +1333,6 @@ #define MASK_PBSADA 0xfe00707f #define MATCH_PKBB16 0xe001077 #define MASK_PKBB16 0xfe00707f -#define MATCH_PKBB32 0xe002077 -#define MASK_PKBB32 0xfe00707f #define MATCH_PKBT16 0x1e001077 #define MASK_PKBT16 0xfe00707f #define MATCH_PKBT32 0x1e002077 @@ -1324,8 +1343,6 @@ #define MASK_PKTB32 0xfe00707f #define MATCH_PKTT16 0x2e001077 #define MASK_PKTT16 0xfe00707f -#define MATCH_PKTT32 0x2e002077 -#define MASK_PKTT32 0xfe00707f #define MATCH_PREFETCH_I 0x6013 #define MASK_PREFETCH_I 0x1f07fff #define MATCH_PREFETCH_R 0x106013 @@ -1478,20 +1495,18 @@ #define MASK_SLL32 0xfe00707f #define MATCH_SLL8 0x5c000077 #define MASK_SLL8 0xfe00707f -#define MATCH_SLLD 0x107b -#define MASK_SLLD 0xfe00707f #define MATCH_SLLI 0x1013 -#define MASK_SLLI 0xf800707f +#define MASK_SLLI 0xfc00707f #define MATCH_SLLI16 0x74000077 #define MASK_SLLI16 0xff00707f #define MATCH_SLLI32 0x74002077 #define MASK_SLLI32 0xfe00707f #define MATCH_SLLI8 0x7c000077 #define MASK_SLLI8 0xff80707f +#define MATCH_SLLI_RV32 0x1013 +#define MASK_SLLI_RV32 0xfe00707f #define MATCH_SLLI_UW 0x800101b #define MASK_SLLI_UW 0xfc00707f -#define MATCH_SLLID 0x105b -#define MASK_SLLID 0xfc00707f #define MATCH_SLLIW 0x101b #define MASK_SLLIW 0xfe00707f #define MATCH_SLLW 0x103b @@ -1604,8 +1619,6 @@ #define MASK_SMXDS 0xfe00707f #define MATCH_SMXDS32 0x78002077 #define MASK_SMXDS32 0xfe00707f -#define MATCH_SQ 0x4023 -#define MASK_SQ 0x707f #define MATCH_SRA 0x40005033 #define MASK_SRA 0xfe00707f #define MATCH_SRA16 0x50000077 @@ -1622,10 +1635,8 @@ #define MASK_SRA8_U 0xfe00707f #define MATCH_SRA_U 0x24001077 #define MASK_SRA_U 0xfe00707f -#define MATCH_SRAD 0x4000507b -#define MASK_SRAD 0xfe00707f #define MATCH_SRAI 0x40005013 -#define MASK_SRAI 0xf800707f +#define MASK_SRAI 0xfc00707f #define MATCH_SRAI16 0x70000077 #define MASK_SRAI16 0xff00707f #define MATCH_SRAI16_U 0x71000077 @@ -1638,10 +1649,10 @@ #define MASK_SRAI8 0xff80707f #define MATCH_SRAI8_U 0x78800077 #define MASK_SRAI8_U 0xff80707f +#define MATCH_SRAI_RV32 0x40005013 +#define MASK_SRAI_RV32 0xfe00707f #define MATCH_SRAI_U 0xd4001077 #define MASK_SRAI_U 0xfc00707f -#define MATCH_SRAID 0x4000505b -#define MASK_SRAID 0xfc00707f #define MATCH_SRAIW 0x4000501b #define MASK_SRAIW 0xfe00707f #define MATCH_SRAIW_U 0x34001077 @@ -1664,10 +1675,8 @@ #define MASK_SRL8 0xfe00707f #define MATCH_SRL8_U 0x6a000077 #define MASK_SRL8_U 0xfe00707f -#define MATCH_SRLD 0x507b -#define MASK_SRLD 0xfe00707f #define MATCH_SRLI 0x5013 -#define MASK_SRLI 0xf800707f +#define MASK_SRLI 0xfc00707f #define MATCH_SRLI16 0x72000077 #define MASK_SRLI16 0xff00707f #define MATCH_SRLI16_U 0x73000077 @@ -1680,8 +1689,8 @@ #define MASK_SRLI8 0xff80707f #define MATCH_SRLI8_U 0x7a800077 #define MASK_SRLI8_U 0xff80707f -#define MATCH_SRLID 0x505b -#define MASK_SRLID 0xfc00707f +#define MATCH_SRLI_RV32 0x5013 +#define MASK_SRLI_RV32 0xfe00707f #define MATCH_SRLIW 0x501b #define MASK_SRLIW 0xfe00707f #define MATCH_SRLW 0x503b @@ -1712,8 +1721,6 @@ #define MASK_SUB64 0xfe00707f #define MATCH_SUB8 0x4a000077 #define MASK_SUB8 0xfe00707f -#define MATCH_SUBD 0x4000007b -#define MASK_SUBD 0xfe00707f #define MATCH_SUBW 0x4000003b #define MASK_SUBW 0xfe00707f #define MATCH_SUNPKD810 0xac800077 @@ -1728,8 +1735,6 @@ #define MASK_SUNPKD832 0xfff0707f #define MATCH_SW 0x2023 #define MASK_SW 0x707f -#define MATCH_SWAP8 0xad800077 -#define MASK_SWAP8 0xfff0707f #define MATCH_UCLIP16 0x85000077 #define MASK_UCLIP16 0xff00707f #define MATCH_UCLIP32 0xf4000077 @@ -2750,10 +2755,6 @@ #define MASK_VZEXT_VF4 0xfc0ff07f #define MATCH_VZEXT_VF8 0x48012057 #define MASK_VZEXT_VF8 0xfc0ff07f -#define MATCH_WEXT 0xce000077 -#define MASK_WEXT 0xfe00707f -#define MATCH_WEXTI 0xde000077 -#define MASK_WEXTI 0xfe00707f #define MATCH_WFI 0x10500073 #define MASK_WFI 0xffffffff #define MATCH_WRS_NTO 0xd00073 @@ -2793,6 +2794,7 @@ #define CSR_VXRM 0xa #define CSR_VCSR 0xf #define CSR_SEED 0x15 +#define CSR_JVT 0x17 #define CSR_CYCLE 0xc00 #define CSR_TIME 0xc01 #define CSR_INSTRET 0xc02 @@ -2845,6 +2847,9 @@ #define CSR_STVAL 0x143 #define CSR_SIP 0x144 #define CSR_STIMECMP 0x14d +#define CSR_SISELECT 0x150 +#define CSR_SIREG 0x151 +#define CSR_STOPEI 0x15c #define CSR_SATP 0x180 #define CSR_SCONTEXT 0x5a8 #define CSR_VSSTATUS 0x200 @@ -2856,6 +2861,9 @@ #define CSR_VSTVAL 0x243 #define CSR_VSIP 0x244 #define CSR_VSTIMECMP 0x24d +#define CSR_VSISELECT 0x250 +#define CSR_VSIREG 0x251 +#define CSR_VSTOPEI 0x25c #define CSR_VSATP 0x280 #define CSR_HSTATUS 0x600 #define CSR_HEDELEG 0x602 @@ -2864,6 +2872,8 @@ #define CSR_HTIMEDELTA 0x605 #define CSR_HCOUNTEREN 0x606 #define CSR_HGEIE 0x607 +#define CSR_HVIEN 0x608 +#define CSR_HVICTL 0x609 #define CSR_HENVCFG 0x60a #define CSR_HSTATEEN0 0x60c #define CSR_HSTATEEN1 0x60d @@ -2872,11 +2882,15 @@ #define CSR_HTVAL 0x643 #define CSR_HIP 0x644 #define CSR_HVIP 0x645 +#define CSR_HVIPRIO1 0x646 +#define CSR_HVIPRIO2 0x647 #define CSR_HTINST 0x64a #define CSR_HGATP 0x680 #define CSR_HCONTEXT 0x6a8 #define CSR_HGEIP 0xe12 +#define CSR_VSTOPI 0xeb0 #define CSR_SCOUNTOVF 0xda0 +#define CSR_STOPI 0xdb0 #define CSR_UTVT 0x7 #define CSR_UNXTI 0x45 #define CSR_UINTSTATUS 0x46 @@ -2899,6 +2913,8 @@ #define CSR_MIE 0x304 #define CSR_MTVEC 0x305 #define CSR_MCOUNTEREN 0x306 +#define CSR_MVIEN 0x308 +#define CSR_MVIP 0x309 #define CSR_MENVCFG 0x30a #define CSR_MSTATEEN0 0x30c #define CSR_MSTATEEN1 0x30d @@ -2912,6 +2928,9 @@ #define CSR_MIP 0x344 #define CSR_MTINST 0x34a #define CSR_MTVAL2 0x34b +#define CSR_MISELECT 0x350 +#define CSR_MIREG 0x351 +#define CSR_MTOPEI 0x35c #define CSR_PMPCFG0 0x3a0 #define CSR_PMPCFG1 0x3a1 #define CSR_PMPCFG2 0x3a2 @@ -3070,10 +3089,20 @@ #define CSR_MIMPID 0xf13 #define CSR_MHARTID 0xf14 #define CSR_MCONFIGPTR 0xf15 +#define CSR_MTOPI 0xfb0 +#define CSR_SIEH 0x114 +#define CSR_SIPH 0x154 #define CSR_STIMECMPH 0x15d +#define CSR_VSIEH 0x214 +#define CSR_VSIPH 0x254 #define CSR_VSTIMECMPH 0x25d #define CSR_HTIMEDELTAH 0x615 +#define CSR_HIDELEGH 0x613 +#define CSR_HVIENH 0x618 #define CSR_HENVCFGH 0x61a +#define CSR_HVIPH 0x655 +#define CSR_HVIPRIO1H 0x656 +#define CSR_HVIPRIO2H 0x657 #define CSR_HSTATEEN0H 0x61c #define CSR_HSTATEEN1H 0x61d #define CSR_HSTATEEN2H 0x61e @@ -3111,11 +3140,16 @@ #define CSR_HPMCOUNTER30H 0xc9e #define CSR_HPMCOUNTER31H 0xc9f #define CSR_MSTATUSH 0x310 +#define CSR_MIDELEGH 0x313 +#define CSR_MIEH 0x314 +#define CSR_MVIENH 0x318 +#define CSR_MVIPH 0x319 #define CSR_MENVCFGH 0x31a #define CSR_MSTATEEN0H 0x31c #define CSR_MSTATEEN1H 0x31d #define CSR_MSTATEEN2H 0x31e #define CSR_MSTATEEN3H 0x31f +#define CSR_MIPH 0x354 #define CSR_MHPMEVENT3H 0x723 #define CSR_MHPMEVENT4H 0x724 #define CSR_MHPMEVENT5H 0x725 @@ -3221,7 +3255,7 @@ #define INSN_FIELD_IMM12LO 0xf80 #define INSN_FIELD_BIMM12LO 0xf80 #define INSN_FIELD_ZIMM 0xf8000 -#define INSN_FIELD_SHAMT 0x7f00000 +#define INSN_FIELD_SHAMTQ 0x7f00000 #define INSN_FIELD_SHAMTW 0x1f00000 #define INSN_FIELD_SHAMTW4 0xf00000 #define INSN_FIELD_SHAMTD 0x3f00000 @@ -3276,6 +3310,11 @@ #define INSN_FIELD_C_UIMM9SPHI 0x1000 #define INSN_FIELD_C_UIMM10SP_S 0x1f80 #define INSN_FIELD_C_UIMM9SP_S 0x1f80 +#define INSN_FIELD_C_UIMM2 0x60 +#define INSN_FIELD_C_UIMM1 0x20 +#define INSN_FIELD_C_RLIST 0xf0 +#define INSN_FIELD_C_SPIMM 0xc +#define INSN_FIELD_C_INDEX 0x3fc #define INSN_FIELD_RS1_P 0x380 #define INSN_FIELD_RS2_P 0x1c #define INSN_FIELD_RD_P 0x1c @@ -3288,6 +3327,8 @@ #define INSN_FIELD_C_RS2_N0 0x7c #define INSN_FIELD_C_RS1_N0 0xf80 #define INSN_FIELD_C_RS2 0x7c +#define INSN_FIELD_C_SREG1 0x380 +#define INSN_FIELD_C_SREG2 0x1c #endif #ifdef DECLARE_INSN DECLARE_INSN(add, MATCH_ADD, MASK_ADD) @@ -3296,9 +3337,7 @@ DECLARE_INSN(add32, MATCH_ADD32, MASK_ADD32) DECLARE_INSN(add64, MATCH_ADD64, MASK_ADD64) DECLARE_INSN(add8, MATCH_ADD8, MASK_ADD8) DECLARE_INSN(add_uw, MATCH_ADD_UW, MASK_ADD_UW) -DECLARE_INSN(addd, MATCH_ADDD, MASK_ADDD) DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) -DECLARE_INSN(addid, MATCH_ADDID, MASK_ADDID) DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) DECLARE_INSN(aes32dsi, MATCH_AES32DSI, MASK_AES32DSI) @@ -3350,15 +3389,12 @@ DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) DECLARE_INSN(binv, MATCH_BINV, MASK_BINV) DECLARE_INSN(binvi, MATCH_BINVI, MASK_BINVI) -DECLARE_INSN(bitrev, MATCH_BITREV, MASK_BITREV) -DECLARE_INSN(bitrevi, MATCH_BITREVI, MASK_BITREVI) DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) DECLARE_INSN(bmatflip, MATCH_BMATFLIP, MASK_BMATFLIP) DECLARE_INSN(bmator, MATCH_BMATOR, MASK_BMATOR) DECLARE_INSN(bmatxor, MATCH_BMATXOR, MASK_BMATXOR) DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) -DECLARE_INSN(bpick, MATCH_BPICK, MASK_BPICK) DECLARE_INSN(bset, MATCH_BSET, MASK_BSET) DECLARE_INSN(bseti, MATCH_BSETI, MASK_BSETI) DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) @@ -3384,22 +3420,27 @@ DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) +DECLARE_INSN(c_lbu, MATCH_C_LBU, MASK_C_LBU) DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) +DECLARE_INSN(c_lh, MATCH_C_LH, MASK_C_LH) +DECLARE_INSN(c_lhu, MATCH_C_LHU, MASK_C_LHU) DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) -DECLARE_INSN(c_lq, MATCH_C_LQ, MASK_C_LQ) -DECLARE_INSN(c_lqsp, MATCH_C_LQSP, MASK_C_LQSP) DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) +DECLARE_INSN(c_mul, MATCH_C_MUL, MASK_C_MUL) DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) +DECLARE_INSN(c_not, MATCH_C_NOT, MASK_C_NOT) DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) +DECLARE_INSN(c_sb, MATCH_C_SB, MASK_C_SB) DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) +DECLARE_INSN(c_sext_b, MATCH_C_SEXT_B, MASK_C_SEXT_B) +DECLARE_INSN(c_sext_h, MATCH_C_SEXT_H, MASK_C_SEXT_H) +DECLARE_INSN(c_sh, MATCH_C_SH, MASK_C_SH) DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) -DECLARE_INSN(c_sq, MATCH_C_SQ, MASK_C_SQ) -DECLARE_INSN(c_sqsp, MATCH_C_SQSP, MASK_C_SQSP) DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) @@ -3407,6 +3448,9 @@ DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) +DECLARE_INSN(c_zext_b, MATCH_C_ZEXT_B, MASK_C_ZEXT_B) +DECLARE_INSN(c_zext_h, MATCH_C_ZEXT_H, MASK_C_ZEXT_H) +DECLARE_INSN(c_zext_w, MATCH_C_ZEXT_W, MASK_C_ZEXT_W) DECLARE_INSN(cbo_clean, MATCH_CBO_CLEAN, MASK_CBO_CLEAN) DECLARE_INSN(cbo_flush, MATCH_CBO_FLUSH, MASK_CBO_FLUSH) DECLARE_INSN(cbo_inval, MATCH_CBO_INVAL, MASK_CBO_INVAL) @@ -3414,9 +3458,6 @@ DECLARE_INSN(cbo_zero, MATCH_CBO_ZERO, MASK_CBO_ZERO) DECLARE_INSN(clmul, MATCH_CLMUL, MASK_CLMUL) DECLARE_INSN(clmulh, MATCH_CLMULH, MASK_CLMULH) DECLARE_INSN(clmulr, MATCH_CLMULR, MASK_CLMULR) -DECLARE_INSN(clo16, MATCH_CLO16, MASK_CLO16) -DECLARE_INSN(clo32, MATCH_CLO32, MASK_CLO32) -DECLARE_INSN(clo8, MATCH_CLO8, MASK_CLO8) DECLARE_INSN(clrs16, MATCH_CLRS16, MASK_CLRS16) DECLARE_INSN(clrs32, MATCH_CLRS32, MASK_CLRS32) DECLARE_INSN(clrs8, MATCH_CLRS8, MASK_CLRS8) @@ -3425,6 +3466,13 @@ DECLARE_INSN(clz16, MATCH_CLZ16, MASK_CLZ16) DECLARE_INSN(clz32, MATCH_CLZ32, MASK_CLZ32) DECLARE_INSN(clz8, MATCH_CLZ8, MASK_CLZ8) DECLARE_INSN(clzw, MATCH_CLZW, MASK_CLZW) +DECLARE_INSN(cm_jalt, MATCH_CM_JALT, MASK_CM_JALT) +DECLARE_INSN(cm_mva01s, MATCH_CM_MVA01S, MASK_CM_MVA01S) +DECLARE_INSN(cm_mvsa01, MATCH_CM_MVSA01, MASK_CM_MVSA01) +DECLARE_INSN(cm_pop, MATCH_CM_POP, MASK_CM_POP) +DECLARE_INSN(cm_popret, MATCH_CM_POPRET, MASK_CM_POPRET) +DECLARE_INSN(cm_popretz, MATCH_CM_POPRETZ, MASK_CM_POPRETZ) +DECLARE_INSN(cm_push, MATCH_CM_PUSH, MASK_CM_PUSH) DECLARE_INSN(cmix, MATCH_CMIX, MASK_CMIX) DECLARE_INSN(cmov, MATCH_CMOV, MASK_CMOV) DECLARE_INSN(cmpeq16, MATCH_CMPEQ16, MASK_CMPEQ16) @@ -3451,6 +3499,8 @@ DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) DECLARE_INSN(ctz, MATCH_CTZ, MASK_CTZ) DECLARE_INSN(ctzw, MATCH_CTZW, MASK_CTZW) +DECLARE_INSN(czero_eqz, MATCH_CZERO_EQZ, MASK_CZERO_EQZ) +DECLARE_INSN(czero_nez, MATCH_CZERO_NEZ, MASK_CZERO_NEZ) DECLARE_INSN(div, MATCH_DIV, MASK_DIV) DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) @@ -3732,10 +3782,8 @@ DECLARE_INSN(kwmmul_u, MATCH_KWMMUL_U, MASK_KWMMUL_U) DECLARE_INSN(lb, MATCH_LB, MASK_LB) DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) DECLARE_INSN(ld, MATCH_LD, MASK_LD) -DECLARE_INSN(ldu, MATCH_LDU, MASK_LDU) DECLARE_INSN(lh, MATCH_LH, MASK_LH) DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) -DECLARE_INSN(lq, MATCH_LQ, MASK_LQ) DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) @@ -3744,10 +3792,8 @@ DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) DECLARE_INSN(maddr32, MATCH_MADDR32, MASK_MADDR32) DECLARE_INSN(max, MATCH_MAX, MASK_MAX) DECLARE_INSN(maxu, MATCH_MAXU, MASK_MAXU) -DECLARE_INSN(maxw, MATCH_MAXW, MASK_MAXW) DECLARE_INSN(min, MATCH_MIN, MASK_MIN) DECLARE_INSN(minu, MATCH_MINU, MASK_MINU) -DECLARE_INSN(minw, MATCH_MINW, MASK_MINW) DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) DECLARE_INSN(msubr32, MATCH_MSUBR32, MASK_MSUBR32) DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) @@ -3769,13 +3815,11 @@ DECLARE_INSN(pause, MATCH_PAUSE, MASK_PAUSE) DECLARE_INSN(pbsad, MATCH_PBSAD, MASK_PBSAD) DECLARE_INSN(pbsada, MATCH_PBSADA, MASK_PBSADA) DECLARE_INSN(pkbb16, MATCH_PKBB16, MASK_PKBB16) -DECLARE_INSN(pkbb32, MATCH_PKBB32, MASK_PKBB32) DECLARE_INSN(pkbt16, MATCH_PKBT16, MASK_PKBT16) DECLARE_INSN(pkbt32, MATCH_PKBT32, MASK_PKBT32) DECLARE_INSN(pktb16, MATCH_PKTB16, MASK_PKTB16) DECLARE_INSN(pktb32, MATCH_PKTB32, MASK_PKTB32) DECLARE_INSN(pktt16, MATCH_PKTT16, MASK_PKTT16) -DECLARE_INSN(pktt32, MATCH_PKTT32, MASK_PKTT32) DECLARE_INSN(prefetch_i, MATCH_PREFETCH_I, MASK_PREFETCH_I) DECLARE_INSN(prefetch_r, MATCH_PREFETCH_R, MASK_PREFETCH_R) DECLARE_INSN(prefetch_w, MATCH_PREFETCH_W, MASK_PREFETCH_W) @@ -3852,13 +3896,12 @@ DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) DECLARE_INSN(sll16, MATCH_SLL16, MASK_SLL16) DECLARE_INSN(sll32, MATCH_SLL32, MASK_SLL32) DECLARE_INSN(sll8, MATCH_SLL8, MASK_SLL8) -DECLARE_INSN(slld, MATCH_SLLD, MASK_SLLD) DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) DECLARE_INSN(slli16, MATCH_SLLI16, MASK_SLLI16) DECLARE_INSN(slli32, MATCH_SLLI32, MASK_SLLI32) DECLARE_INSN(slli8, MATCH_SLLI8, MASK_SLLI8) +DECLARE_INSN(slli_rv32, MATCH_SLLI_RV32, MASK_SLLI_RV32) DECLARE_INSN(slli_uw, MATCH_SLLI_UW, MASK_SLLI_UW) -DECLARE_INSN(sllid, MATCH_SLLID, MASK_SLLID) DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) DECLARE_INSN(slo, MATCH_SLO, MASK_SLO) @@ -3915,7 +3958,6 @@ DECLARE_INSN(smulx16, MATCH_SMULX16, MASK_SMULX16) DECLARE_INSN(smulx8, MATCH_SMULX8, MASK_SMULX8) DECLARE_INSN(smxds, MATCH_SMXDS, MASK_SMXDS) DECLARE_INSN(smxds32, MATCH_SMXDS32, MASK_SMXDS32) -DECLARE_INSN(sq, MATCH_SQ, MASK_SQ) DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) DECLARE_INSN(sra16, MATCH_SRA16, MASK_SRA16) DECLARE_INSN(sra16_u, MATCH_SRA16_U, MASK_SRA16_U) @@ -3924,7 +3966,6 @@ DECLARE_INSN(sra32_u, MATCH_SRA32_U, MASK_SRA32_U) DECLARE_INSN(sra8, MATCH_SRA8, MASK_SRA8) DECLARE_INSN(sra8_u, MATCH_SRA8_U, MASK_SRA8_U) DECLARE_INSN(sra_u, MATCH_SRA_U, MASK_SRA_U) -DECLARE_INSN(srad, MATCH_SRAD, MASK_SRAD) DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) DECLARE_INSN(srai16, MATCH_SRAI16, MASK_SRAI16) DECLARE_INSN(srai16_u, MATCH_SRAI16_U, MASK_SRAI16_U) @@ -3932,8 +3973,8 @@ DECLARE_INSN(srai32, MATCH_SRAI32, MASK_SRAI32) DECLARE_INSN(srai32_u, MATCH_SRAI32_U, MASK_SRAI32_U) DECLARE_INSN(srai8, MATCH_SRAI8, MASK_SRAI8) DECLARE_INSN(srai8_u, MATCH_SRAI8_U, MASK_SRAI8_U) +DECLARE_INSN(srai_rv32, MATCH_SRAI_RV32, MASK_SRAI_RV32) DECLARE_INSN(srai_u, MATCH_SRAI_U, MASK_SRAI_U) -DECLARE_INSN(sraid, MATCH_SRAID, MASK_SRAID) DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) DECLARE_INSN(sraiw_u, MATCH_SRAIW_U, MASK_SRAIW_U) DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) @@ -3945,7 +3986,6 @@ DECLARE_INSN(srl32, MATCH_SRL32, MASK_SRL32) DECLARE_INSN(srl32_u, MATCH_SRL32_U, MASK_SRL32_U) DECLARE_INSN(srl8, MATCH_SRL8, MASK_SRL8) DECLARE_INSN(srl8_u, MATCH_SRL8_U, MASK_SRL8_U) -DECLARE_INSN(srld, MATCH_SRLD, MASK_SRLD) DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) DECLARE_INSN(srli16, MATCH_SRLI16, MASK_SRLI16) DECLARE_INSN(srli16_u, MATCH_SRLI16_U, MASK_SRLI16_U) @@ -3953,7 +3993,7 @@ DECLARE_INSN(srli32, MATCH_SRLI32, MASK_SRLI32) DECLARE_INSN(srli32_u, MATCH_SRLI32_U, MASK_SRLI32_U) DECLARE_INSN(srli8, MATCH_SRLI8, MASK_SRLI8) DECLARE_INSN(srli8_u, MATCH_SRLI8_U, MASK_SRLI8_U) -DECLARE_INSN(srlid, MATCH_SRLID, MASK_SRLID) +DECLARE_INSN(srli_rv32, MATCH_SRLI_RV32, MASK_SRLI_RV32) DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) DECLARE_INSN(sro, MATCH_SRO, MASK_SRO) @@ -3969,7 +4009,6 @@ DECLARE_INSN(sub16, MATCH_SUB16, MASK_SUB16) DECLARE_INSN(sub32, MATCH_SUB32, MASK_SUB32) DECLARE_INSN(sub64, MATCH_SUB64, MASK_SUB64) DECLARE_INSN(sub8, MATCH_SUB8, MASK_SUB8) -DECLARE_INSN(subd, MATCH_SUBD, MASK_SUBD) DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) DECLARE_INSN(sunpkd810, MATCH_SUNPKD810, MASK_SUNPKD810) DECLARE_INSN(sunpkd820, MATCH_SUNPKD820, MASK_SUNPKD820) @@ -3977,7 +4016,6 @@ DECLARE_INSN(sunpkd830, MATCH_SUNPKD830, MASK_SUNPKD830) DECLARE_INSN(sunpkd831, MATCH_SUNPKD831, MASK_SUNPKD831) DECLARE_INSN(sunpkd832, MATCH_SUNPKD832, MASK_SUNPKD832) DECLARE_INSN(sw, MATCH_SW, MASK_SW) -DECLARE_INSN(swap8, MATCH_SWAP8, MASK_SWAP8) DECLARE_INSN(uclip16, MATCH_UCLIP16, MASK_UCLIP16) DECLARE_INSN(uclip32, MATCH_UCLIP32, MASK_UCLIP32) DECLARE_INSN(uclip8, MATCH_UCLIP8, MASK_UCLIP8) @@ -4488,8 +4526,6 @@ DECLARE_INSN(vxor_vx, MATCH_VXOR_VX, MASK_VXOR_VX) DECLARE_INSN(vzext_vf2, MATCH_VZEXT_VF2, MASK_VZEXT_VF2) DECLARE_INSN(vzext_vf4, MATCH_VZEXT_VF4, MASK_VZEXT_VF4) DECLARE_INSN(vzext_vf8, MATCH_VZEXT_VF8, MASK_VZEXT_VF8) -DECLARE_INSN(wext, MATCH_WEXT, MASK_WEXT) -DECLARE_INSN(wexti, MATCH_WEXTI, MASK_WEXTI) DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) DECLARE_INSN(wrs_nto, MATCH_WRS_NTO, MASK_WRS_NTO) DECLARE_INSN(wrs_sto, MATCH_WRS_STO, MASK_WRS_STO) @@ -4515,6 +4551,7 @@ DECLARE_CSR(vxsat, CSR_VXSAT) DECLARE_CSR(vxrm, CSR_VXRM) DECLARE_CSR(vcsr, CSR_VCSR) DECLARE_CSR(seed, CSR_SEED) +DECLARE_CSR(jvt, CSR_JVT) DECLARE_CSR(cycle, CSR_CYCLE) DECLARE_CSR(time, CSR_TIME) DECLARE_CSR(instret, CSR_INSTRET) @@ -4567,6 +4604,9 @@ DECLARE_CSR(scause, CSR_SCAUSE) DECLARE_CSR(stval, CSR_STVAL) DECLARE_CSR(sip, CSR_SIP) DECLARE_CSR(stimecmp, CSR_STIMECMP) +DECLARE_CSR(siselect, CSR_SISELECT) +DECLARE_CSR(sireg, CSR_SIREG) +DECLARE_CSR(stopei, CSR_STOPEI) DECLARE_CSR(satp, CSR_SATP) DECLARE_CSR(scontext, CSR_SCONTEXT) DECLARE_CSR(vsstatus, CSR_VSSTATUS) @@ -4578,6 +4618,9 @@ DECLARE_CSR(vscause, CSR_VSCAUSE) DECLARE_CSR(vstval, CSR_VSTVAL) DECLARE_CSR(vsip, CSR_VSIP) DECLARE_CSR(vstimecmp, CSR_VSTIMECMP) +DECLARE_CSR(vsiselect, CSR_VSISELECT) +DECLARE_CSR(vsireg, CSR_VSIREG) +DECLARE_CSR(vstopei, CSR_VSTOPEI) DECLARE_CSR(vsatp, CSR_VSATP) DECLARE_CSR(hstatus, CSR_HSTATUS) DECLARE_CSR(hedeleg, CSR_HEDELEG) @@ -4586,6 +4629,8 @@ DECLARE_CSR(hie, CSR_HIE) DECLARE_CSR(htimedelta, CSR_HTIMEDELTA) DECLARE_CSR(hcounteren, CSR_HCOUNTEREN) DECLARE_CSR(hgeie, CSR_HGEIE) +DECLARE_CSR(hvien, CSR_HVIEN) +DECLARE_CSR(hvictl, CSR_HVICTL) DECLARE_CSR(henvcfg, CSR_HENVCFG) DECLARE_CSR(hstateen0, CSR_HSTATEEN0) DECLARE_CSR(hstateen1, CSR_HSTATEEN1) @@ -4594,11 +4639,15 @@ DECLARE_CSR(hstateen3, CSR_HSTATEEN3) DECLARE_CSR(htval, CSR_HTVAL) DECLARE_CSR(hip, CSR_HIP) DECLARE_CSR(hvip, CSR_HVIP) +DECLARE_CSR(hviprio1, CSR_HVIPRIO1) +DECLARE_CSR(hviprio2, CSR_HVIPRIO2) DECLARE_CSR(htinst, CSR_HTINST) DECLARE_CSR(hgatp, CSR_HGATP) DECLARE_CSR(hcontext, CSR_HCONTEXT) DECLARE_CSR(hgeip, CSR_HGEIP) +DECLARE_CSR(vstopi, CSR_VSTOPI) DECLARE_CSR(scountovf, CSR_SCOUNTOVF) +DECLARE_CSR(stopi, CSR_STOPI) DECLARE_CSR(utvt, CSR_UTVT) DECLARE_CSR(unxti, CSR_UNXTI) DECLARE_CSR(uintstatus, CSR_UINTSTATUS) @@ -4621,6 +4670,8 @@ DECLARE_CSR(mideleg, CSR_MIDELEG) DECLARE_CSR(mie, CSR_MIE) DECLARE_CSR(mtvec, CSR_MTVEC) DECLARE_CSR(mcounteren, CSR_MCOUNTEREN) +DECLARE_CSR(mvien, CSR_MVIEN) +DECLARE_CSR(mvip, CSR_MVIP) DECLARE_CSR(menvcfg, CSR_MENVCFG) DECLARE_CSR(mstateen0, CSR_MSTATEEN0) DECLARE_CSR(mstateen1, CSR_MSTATEEN1) @@ -4634,6 +4685,9 @@ DECLARE_CSR(mtval, CSR_MTVAL) DECLARE_CSR(mip, CSR_MIP) DECLARE_CSR(mtinst, CSR_MTINST) DECLARE_CSR(mtval2, CSR_MTVAL2) +DECLARE_CSR(miselect, CSR_MISELECT) +DECLARE_CSR(mireg, CSR_MIREG) +DECLARE_CSR(mtopei, CSR_MTOPEI) DECLARE_CSR(pmpcfg0, CSR_PMPCFG0) DECLARE_CSR(pmpcfg1, CSR_PMPCFG1) DECLARE_CSR(pmpcfg2, CSR_PMPCFG2) @@ -4792,10 +4846,20 @@ DECLARE_CSR(marchid, CSR_MARCHID) DECLARE_CSR(mimpid, CSR_MIMPID) DECLARE_CSR(mhartid, CSR_MHARTID) DECLARE_CSR(mconfigptr, CSR_MCONFIGPTR) +DECLARE_CSR(mtopi, CSR_MTOPI) +DECLARE_CSR(sieh, CSR_SIEH) +DECLARE_CSR(siph, CSR_SIPH) DECLARE_CSR(stimecmph, CSR_STIMECMPH) +DECLARE_CSR(vsieh, CSR_VSIEH) +DECLARE_CSR(vsiph, CSR_VSIPH) DECLARE_CSR(vstimecmph, CSR_VSTIMECMPH) DECLARE_CSR(htimedeltah, CSR_HTIMEDELTAH) +DECLARE_CSR(hidelegh, CSR_HIDELEGH) +DECLARE_CSR(hvienh, CSR_HVIENH) DECLARE_CSR(henvcfgh, CSR_HENVCFGH) +DECLARE_CSR(hviph, CSR_HVIPH) +DECLARE_CSR(hviprio1h, CSR_HVIPRIO1H) +DECLARE_CSR(hviprio2h, CSR_HVIPRIO2H) DECLARE_CSR(hstateen0h, CSR_HSTATEEN0H) DECLARE_CSR(hstateen1h, CSR_HSTATEEN1H) DECLARE_CSR(hstateen2h, CSR_HSTATEEN2H) @@ -4833,11 +4897,16 @@ DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) DECLARE_CSR(mstatush, CSR_MSTATUSH) +DECLARE_CSR(midelegh, CSR_MIDELEGH) +DECLARE_CSR(mieh, CSR_MIEH) +DECLARE_CSR(mvienh, CSR_MVIENH) +DECLARE_CSR(mviph, CSR_MVIPH) DECLARE_CSR(menvcfgh, CSR_MENVCFGH) DECLARE_CSR(mstateen0h, CSR_MSTATEEN0H) DECLARE_CSR(mstateen1h, CSR_MSTATEEN1H) DECLARE_CSR(mstateen2h, CSR_MSTATEEN2H) DECLARE_CSR(mstateen3h, CSR_MSTATEEN3H) +DECLARE_CSR(miph, CSR_MIPH) DECLARE_CSR(mhpmevent3h, CSR_MHPMEVENT3H) DECLARE_CSR(mhpmevent4h, CSR_MHPMEVENT4H) DECLARE_CSR(mhpmevent5h, CSR_MHPMEVENT5H) diff --git a/src/target/riscv/field_helpers.h b/src/target/riscv/field_helpers.h new file mode 100644 index 0000000000..16578f1977 --- /dev/null +++ b/src/target/riscv/field_helpers.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef FIELD_HELPERS_H +#define FIELD_HELPERS_H + +#include <stdint.h> +#include <assert.h> + +static inline uint64_t get_field(uint64_t reg, uint64_t mask) +{ + return (reg & mask) / (mask & ~(mask << 1)); +} + +static inline uint32_t get_field32(uint64_t reg, uint64_t mask) +{ + uint64_t value = get_field(reg, mask); + assert(value <= UINT32_MAX); + return value; +} + +static inline uint64_t set_field(uint64_t reg, uint64_t mask, uint64_t val) +{ + /* Clear current value from field. */ + reg &= ~mask; + uint64_t low_field_bit = mask & ~(mask << 1); + /* Assert if the value doesn't fit in the field. */ + assert(((val * low_field_bit) & ~mask) == 0); + reg |= (val * low_field_bit) & mask; + return reg; +} + +static inline uint32_t set_field32(uint32_t reg, uint32_t mask, uint32_t val) +{ + return (uint32_t)set_field(reg, mask, val); +} + +static inline uint64_t field_value(uint64_t mask, uint64_t val) +{ + return set_field(0, mask, val); +} + +static inline uint32_t field_value32(uint32_t mask, uint32_t val) +{ + return set_field32(0, mask, val); +} + +#endif diff --git a/src/target/riscv/gdb_regs.h b/src/target/riscv/gdb_regs.h index 32bc1d577b..570c50845c 100644 --- a/src/target/riscv/gdb_regs.h +++ b/src/target/riscv/gdb_regs.h @@ -81,12 +81,15 @@ enum gdb_regno { GDB_REGNO_VSTART = CSR_VSTART + GDB_REGNO_CSR0, GDB_REGNO_VXSAT = CSR_VXSAT + GDB_REGNO_CSR0, GDB_REGNO_VXRM = CSR_VXRM + GDB_REGNO_CSR0, + GDB_REGNO_VCSR = CSR_VCSR + GDB_REGNO_CSR0, GDB_REGNO_VLENB = CSR_VLENB + GDB_REGNO_CSR0, GDB_REGNO_VL = CSR_VL + GDB_REGNO_CSR0, GDB_REGNO_VTYPE = CSR_VTYPE + GDB_REGNO_CSR0, GDB_REGNO_TSELECT = CSR_TSELECT + GDB_REGNO_CSR0, GDB_REGNO_TDATA1 = CSR_TDATA1 + GDB_REGNO_CSR0, GDB_REGNO_TDATA2 = CSR_TDATA2 + GDB_REGNO_CSR0, + GDB_REGNO_TDATA3 = CSR_TDATA3 + GDB_REGNO_CSR0, + GDB_REGNO_TINFO = CSR_TINFO + GDB_REGNO_CSR0, GDB_REGNO_MISA = CSR_MISA + GDB_REGNO_CSR0, GDB_REGNO_DPC = CSR_DPC + GDB_REGNO_CSR0, GDB_REGNO_DCSR = CSR_DCSR + GDB_REGNO_CSR0, @@ -95,6 +98,11 @@ enum gdb_regno { GDB_REGNO_MEPC = CSR_MEPC + GDB_REGNO_CSR0, GDB_REGNO_MCAUSE = CSR_MCAUSE + GDB_REGNO_CSR0, GDB_REGNO_SATP = CSR_SATP + GDB_REGNO_CSR0, + GDB_REGNO_VSATP = CSR_VSATP + GDB_REGNO_CSR0, + GDB_REGNO_HGATP = CSR_HGATP + GDB_REGNO_CSR0, + GDB_REGNO_HSTATUS = CSR_HSTATUS + GDB_REGNO_CSR0, + GDB_REGNO_MTOPI = CSR_MTOPI + GDB_REGNO_CSR0, + GDB_REGNO_MTOPEI = CSR_MTOPEI + GDB_REGNO_CSR0, GDB_REGNO_CSR4095 = GDB_REGNO_CSR0 + 4095, GDB_REGNO_PRIV = 4161, /* It's still undecided what register numbers GDB will actually use for @@ -112,6 +120,6 @@ enum gdb_regno { GDB_REGNO_COUNT }; -const char *gdb_regno_name(enum gdb_regno regno); +const char *gdb_regno_name(struct target *target, enum gdb_regno regno); #endif diff --git a/src/target/riscv/opcodes.h b/src/target/riscv/opcodes.h index 992196f47b..59c34139ca 100644 --- a/src/target/riscv/opcodes.h +++ b/src/target/riscv/opcodes.h @@ -294,10 +294,11 @@ static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) return inst_rs2(shamt) | inst_rs1(src) | inst_rd(dest) | MATCH_SRLI; } -static uint32_t fence(void) __attribute__((unused)); -static uint32_t fence(void) +static uint32_t fence_rw_rw(void) __attribute__((unused)); +static uint32_t fence_rw_rw(void) { - return MATCH_FENCE; + /* fence rw,rw */ + return MATCH_FENCE | 0x3300000; } static uint32_t auipc(unsigned int dest) __attribute__((unused)); diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index 8e2ce5dbd5..c4ffb3f4d6 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later #ifdef HAVE_CONFIG_H #include "config.h" @@ -11,6 +11,7 @@ #include "helper/log.h" #include "asm.h" +#include "debug_defines.h" #include "encoding.h" /* Program interface. */ @@ -19,22 +20,20 @@ int riscv_program_init(struct riscv_program *p, struct target *target) memset(p, 0, sizeof(*p)); p->target = target; p->instruction_count = 0; - p->target_xlen = riscv_xlen(target); - for (size_t i = 0; i < RISCV_REGISTER_COUNT; ++i) - p->writes_xreg[i] = 0; - for (size_t i = 0; i < RISCV_MAX_DEBUG_BUFFER_SIZE; ++i) - p->debug_buffer[i] = -1; + for (size_t i = 0; i < RISCV_MAX_PROGBUF_SIZE; ++i) + p->progbuf[i] = -1; + p->execution_result = RISCV_PROGBUF_EXEC_RESULT_NOT_EXECUTED; return ERROR_OK; } int riscv_program_write(struct riscv_program *program) { for (unsigned i = 0; i < program->instruction_count; ++i) { - LOG_DEBUG("debug_buffer[%02x] = DASM(0x%08x)", i, program->debug_buffer[i]); - if (riscv_write_debug_buffer(program->target, i, - program->debug_buffer[i]) != ERROR_OK) + LOG_TARGET_DEBUG(program->target, "progbuf[%02x] = DASM(0x%08x)", + i, program->progbuf[i]); + if (riscv_write_progbuf(program->target, i, program->progbuf[i]) != ERROR_OK) return ERROR_FAIL; } return ERROR_OK; @@ -45,39 +44,29 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) { keep_alive(); - riscv_reg_t saved_registers[GDB_REGNO_XPR31 + 1]; - for (size_t i = GDB_REGNO_ZERO + 1; i <= GDB_REGNO_XPR31; ++i) { - if (p->writes_xreg[i]) { - LOG_DEBUG("Saving register %d as used by program", (int)i); - int result = riscv_get_register(t, &saved_registers[i], i); - if (result != ERROR_OK) - return result; - } - } + p->execution_result = RISCV_PROGBUF_EXEC_RESULT_UNKNOWN; if (riscv_program_ebreak(p) != ERROR_OK) { - LOG_ERROR("Unable to write ebreak"); - for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) - LOG_ERROR("ram[%02x]: DASM(0x%08" PRIx32 ") [0x%08" PRIx32 "]", - (int)i, p->debug_buffer[i], p->debug_buffer[i]); + LOG_TARGET_ERROR(t, "Unable to insert ebreak into program buffer"); + for (size_t i = 0; i < riscv_progbuf_size(p->target); ++i) + LOG_TARGET_ERROR(t, "ram[%02x]: DASM(0x%08" PRIx32 ") [0x%08" PRIx32 "]", + (int)i, p->progbuf[i], p->progbuf[i]); return ERROR_FAIL; } if (riscv_program_write(p) != ERROR_OK) return ERROR_FAIL; - if (riscv_execute_debug_buffer(t) != ERROR_OK) { - LOG_DEBUG("Unable to execute program %p", p); + uint32_t cmderr; + if (riscv_execute_progbuf(t, &cmderr) != ERROR_OK) { + p->execution_result = (cmderr == DM_ABSTRACTCS_CMDERR_EXCEPTION) + ? RISCV_PROGBUF_EXEC_RESULT_EXCEPTION + : RISCV_PROGBUF_EXEC_RESULT_UNKNOWN_ERROR; + /* TODO: what happens if we fail here, but need to restore registers? */ + LOG_TARGET_DEBUG(t, "Unable to execute program %p", p); return ERROR_FAIL; } - - for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) - if (i >= riscv_debug_buffer_size(p->target)) - p->debug_buffer[i] = riscv_read_debug_buffer(t, i); - - for (size_t i = GDB_REGNO_ZERO; i <= GDB_REGNO_XPR31; ++i) - if (p->writes_xreg[i]) - riscv_set_register(t, i, saved_registers[i]); + p->execution_result = RISCV_PROGBUF_EXEC_RESULT_SUCCESS; return ERROR_OK; } @@ -102,6 +91,23 @@ int riscv_program_sbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno return riscv_program_insert(p, sb(d, b, offset)); } +int riscv_program_store(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset, + unsigned int size) +{ + switch (size) { + case 1: + return riscv_program_sbr(p, d, b, offset); + case 2: + return riscv_program_shr(p, d, b, offset); + case 4: + return riscv_program_swr(p, d, b, offset); + case 8: + return riscv_program_sdr(p, d, b, offset); + } + assert(false && "Unsupported size"); + return ERROR_FAIL; +} + int riscv_program_ldr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { return riscv_program_insert(p, ld(d, b, offset)); @@ -122,6 +128,23 @@ int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno return riscv_program_insert(p, lb(d, b, offset)); } +int riscv_program_load(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset, + unsigned int size) +{ + switch (size) { + case 1: + return riscv_program_lbr(p, d, b, offset); + case 2: + return riscv_program_lhr(p, d, b, offset); + case 4: + return riscv_program_lwr(p, d, b, offset); + case 8: + return riscv_program_ldr(p, d, b, offset); + } + assert(false && "Unsupported size"); + return ERROR_FAIL; +} + int riscv_program_csrrsi(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr) { assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095); @@ -151,16 +174,16 @@ int riscv_program_fence_i(struct riscv_program *p) return riscv_program_insert(p, fence_i()); } -int riscv_program_fence(struct riscv_program *p) +int riscv_program_fence_rw_rw(struct riscv_program *p) { - return riscv_program_insert(p, fence()); + return riscv_program_insert(p, fence_rw_rw()); } int riscv_program_ebreak(struct riscv_program *p) { struct target *target = p->target; RISCV_INFO(r); - if (p->instruction_count == riscv_debug_buffer_size(p->target) && + if (p->instruction_count == riscv_progbuf_size(p->target) && r->impebreak) { return ERROR_OK; } @@ -174,14 +197,14 @@ int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno int riscv_program_insert(struct riscv_program *p, riscv_insn_t i) { - if (p->instruction_count >= riscv_debug_buffer_size(p->target)) { - LOG_ERROR("Unable to insert instruction:"); - LOG_ERROR(" instruction_count=%d", (int)p->instruction_count); - LOG_ERROR(" buffer size =%d", (int)riscv_debug_buffer_size(p->target)); + if (p->instruction_count >= riscv_progbuf_size(p->target)) { + LOG_TARGET_ERROR(p->target, "Unable to insert program into progbuf, " + "capacity would be exceeded (progbufsize=%d).", + (int)riscv_progbuf_size(p->target)); return ERROR_FAIL; } - p->debug_buffer[p->instruction_count] = i; + p->progbuf[p->instruction_count] = i; p->instruction_count++; return ERROR_OK; } diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h index 62a04f0933..361191aa41 100644 --- a/src/target/riscv/program.h +++ b/src/target/riscv/program.h @@ -5,27 +5,32 @@ #include "riscv.h" -#define RISCV_MAX_DEBUG_BUFFER_SIZE 32 +#define RISCV_MAX_PROGBUF_SIZE 32 #define RISCV_REGISTER_COUNT 32 #define RISCV_DSCRATCH_COUNT 2 +typedef enum { + RISCV_PROGBUF_EXEC_RESULT_NOT_EXECUTED, + RISCV_PROGBUF_EXEC_RESULT_UNKNOWN, + RISCV_PROGBUF_EXEC_RESULT_EXCEPTION, + RISCV_PROGBUF_EXEC_RESULT_UNKNOWN_ERROR, + RISCV_PROGBUF_EXEC_RESULT_SUCCESS +} riscv_progbuf_exec_result_t; + /* The various RISC-V debug specifications all revolve around setting up * program buffers and executing them on the target. This structure contains a * single program, which can then be executed on targets. */ struct riscv_program { struct target *target; - uint32_t debug_buffer[RISCV_MAX_DEBUG_BUFFER_SIZE]; + uint32_t progbuf[RISCV_MAX_PROGBUF_SIZE]; /* Number of 32-bit instructions in the program. */ size_t instruction_count; - /* Side effects of executing this program. These must be accounted for - * in order to maintain correct executing of the target system. */ - bool writes_xreg[RISCV_REGISTER_COUNT]; - - /* XLEN on the target. */ - int target_xlen; + /* execution result of the program */ + /* TODO: remove this field. We should make it a parameter to riscv_program_exec */ + riscv_progbuf_exec_result_t execution_result; }; /* Initializes a program with the header. */ @@ -51,11 +56,15 @@ int riscv_program_ldr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); +int riscv_program_load(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int o, + unsigned int s); int riscv_program_sdr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); int riscv_program_swr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); int riscv_program_shr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); int riscv_program_sbr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); +int riscv_program_store(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int o, + unsigned int s); int riscv_program_csrrsi(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr); int riscv_program_csrrci(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr); @@ -63,7 +72,7 @@ int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr); int riscv_program_fence_i(struct riscv_program *p); -int riscv_program_fence(struct riscv_program *p); +int riscv_program_fence_rw_rw(struct riscv_program *p); int riscv_program_ebreak(struct riscv_program *p); int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t i); diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index d999ab3973..88ae14d08c 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Support for RISC-V, debug version 0.11. This was never an officially adopted @@ -24,6 +24,7 @@ #include "riscv.h" #include "asm.h" #include "gdb_regs.h" +#include "field_helpers.h" /** * Since almost everything can be accomplish by scanning the dbus register, all @@ -67,8 +68,7 @@ * to the target. Afterwards use cache_get... to read results. */ -#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) -#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) +static int handle_halt(struct target *target, bool announce); /* Constants for legacy SiFive hardware breakpoints. */ #define CSR_BPCONTROL_X (1<<0) @@ -161,15 +161,6 @@ typedef enum slot { #define DRAM_CACHE_SIZE 16 -struct trigger { - uint64_t address; - uint32_t length; - uint64_t mask; - uint64_t value; - bool read, write, execute; - int unique_id; -}; - struct memory_cache_line { uint32_t data; bool valid; @@ -219,7 +210,8 @@ typedef struct { static int poll_target(struct target *target, bool announce); static int riscv011_poll(struct target *target); -static int get_register(struct target *target, riscv_reg_t *value, int regid); +static int get_register(struct target *target, riscv_reg_t *value, + enum gdb_regno regid); /*** Utility functions. ***/ @@ -227,10 +219,10 @@ static int get_register(struct target *target, riscv_reg_t *value, int regid); static riscv011_info_t *get_info(const struct target *target) { - riscv_info_t *info = (riscv_info_t *) target->arch_info; + struct riscv_info *info = target->arch_info; assert(info); assert(info->version_specific); - return (riscv011_info_t *) info->version_specific; + return info->version_specific; } static unsigned int slot_offset(const struct target *target, slot_t slot) @@ -279,7 +271,7 @@ static uint16_t dram_address(unsigned int index) return 0x40 + index - 0x10; } -static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) +static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr) { struct scan_field field; uint8_t in_value[4]; @@ -306,7 +298,9 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) uint32_t in = buf_get_u32(field.in_value, 0, 32); LOG_DEBUG("DTMCONTROL: 0x%x -> 0x%x", out, in); - return in; + if (in_ptr) + *in_ptr = in; + return ERROR_OK; } static uint32_t idcode_scan(struct target *target) @@ -344,7 +338,7 @@ static void increase_dbus_busy_delay(struct target *target) info->dtmcontrol_idle, info->dbus_busy_delay, info->interrupt_high_delay); - dtmcontrol_scan(target, DTMCONTROL_DBUS_RESET); + dtmcontrol_scan(target, DTMCONTROL_DBUS_RESET, NULL /* discard value */); } static void increase_interrupt_high_delay(struct target *target) @@ -431,8 +425,13 @@ static dbus_status_t dbus_scan(struct target *target, uint16_t *address_in, .out_value = out, .in_value = in }; + if (address_in) + *address_in = 0; - assert(info->addrbits != 0); + if (info->addrbits == 0) { + LOG_TARGET_ERROR(target, "Can't access DMI because addrbits=0."); + return DBUS_STATUS_FAILED; + } buf_set_u64(out, DBUS_OP_START, DBUS_OP_SIZE, op); buf_set_u64(out, DBUS_DATA_START, DBUS_DATA_SIZE, data_out); @@ -686,18 +685,13 @@ static void dram_write32(struct target *target, unsigned int index, uint32_t val } /** Read the haltnot and interrupt bits. */ -static bits_t read_bits(struct target *target) +static int read_bits(struct target *target, bits_t *result) { uint64_t value; dbus_status_t status; uint16_t address_in; riscv011_info_t *info = get_info(target); - bits_t err_result = { - .haltnot = 0, - .interrupt = 0 - }; - do { unsigned i = 0; do { @@ -706,26 +700,23 @@ static bits_t read_bits(struct target *target) if (address_in == (1<<info->addrbits) - 1 && value == (1ULL<<DBUS_DATA_SIZE) - 1) { LOG_ERROR("TDO seems to be stuck high."); - return err_result; + return ERROR_FAIL; } increase_dbus_busy_delay(target); - } else if (status == DBUS_STATUS_FAILED) { - /* TODO: return an actual error */ - return err_result; } } while (status == DBUS_STATUS_BUSY && i++ < 256); - if (i >= 256) { + if (status != DBUS_STATUS_SUCCESS) { LOG_ERROR("Failed to read from 0x%x; status=%d", address_in, status); - return err_result; + return ERROR_FAIL; } } while (address_in > 0x10 && address_in != DMCONTROL); - bits_t result = { - .haltnot = get_field(value, DMCONTROL_HALTNOT), - .interrupt = get_field(value, DMCONTROL_INTERRUPT) - }; - return result; + if (result) { + result->haltnot = get_field(value, DMCONTROL_HALTNOT); + result->interrupt = get_field(value, DMCONTROL_INTERRUPT); + } + return ERROR_OK; } static int wait_for_debugint_clear(struct target *target, bool ignore_first) @@ -736,10 +727,16 @@ static int wait_for_debugint_clear(struct target *target, bool ignore_first) * result of the read that happened just before debugint was set. * (Assuming the last scan before calling this function was one that * sets debugint.) */ - read_bits(target); + read_bits(target, NULL); } while (1) { - bits_t bits = read_bits(target); + bits_t bits = { + .haltnot = 0, + .interrupt = 0 + }; + if (read_bits(target, &bits) != ERROR_OK) + return ERROR_FAIL; + if (!bits.interrupt) return ERROR_OK; if (time(NULL) - start > riscv_command_timeout_sec) { @@ -1048,7 +1045,7 @@ static int read_remote_csr(struct target *target, uint64_t *value, uint32_t csr) uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { LOG_WARNING("Got exception 0x%x when reading %s", exception, - gdb_regno_name(GDB_REGNO_CSR0 + csr)); + gdb_regno_name(target, GDB_REGNO_CSR0 + csr)); *value = ~0; return ERROR_FAIL; } @@ -1109,6 +1106,7 @@ static int maybe_write_tselect(struct target *target) static int execute_resume(struct target *target, bool step) { + RISCV_INFO(r); riscv011_info_t *info = get_info(target); LOG_DEBUG("step=%d", step); @@ -1140,9 +1138,9 @@ static int execute_resume(struct target *target, bool step) } } - info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm); - info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks); - info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku); + info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, r->riscv_ebreakm); + info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, r->riscv_ebreaks); + info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, r->riscv_ebreaku); info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1); info->dcsr &= ~DCSR_HALT; @@ -1192,17 +1190,7 @@ static int full_step(struct target *target, bool announce) return ERROR_FAIL; } } - return ERROR_OK; -} - -static int resume(struct target *target, int debug_execution, bool step) -{ - if (debug_execution) { - LOG_ERROR("TODO: debug_execution is true"); - return ERROR_FAIL; - } - - return execute_resume(target, step); + return handle_halt(target, announce); } static uint64_t reg_cache_get(struct target *target, unsigned int number) @@ -1259,7 +1247,7 @@ static int register_read(struct target *target, riscv_reg_t *value, int regnum) uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { - LOG_WARNING("Got exception 0x%x when reading %s", exception, gdb_regno_name(regnum)); + LOG_WARNING("Got exception 0x%x when reading %s", exception, gdb_regno_name(target, regnum)); *value = ~0; return ERROR_FAIL; } @@ -1334,14 +1322,15 @@ static int register_write(struct target *target, unsigned int number, uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { LOG_WARNING("Got exception 0x%x when writing %s", exception, - gdb_regno_name(number)); + gdb_regno_name(target, number)); return ERROR_FAIL; } return ERROR_OK; } -static int get_register(struct target *target, riscv_reg_t *value, int regid) +static int get_register(struct target *target, riscv_reg_t *value, + enum gdb_regno regid) { riscv011_info_t *info = get_info(target); @@ -1385,7 +1374,8 @@ static int get_register(struct target *target, riscv_reg_t *value, int regid) return ERROR_OK; } -static int set_register(struct target *target, int regid, uint64_t value) +static int set_register(struct target *target, enum gdb_regno regid, + riscv_reg_t value) { return register_write(target, regid, value); } @@ -1411,7 +1401,10 @@ static int halt(struct target *target) static void deinit_target(struct target *target) { LOG_DEBUG("riscv_deinit_target()"); - riscv_info_t *info = (riscv_info_t *) target->arch_info; + struct riscv_info *info = target->arch_info; + if (!info) + return; + free(info->version_specific); info->version_specific = NULL; } @@ -1468,19 +1461,20 @@ static int step(struct target *target, int current, target_addr_t address, static int examine(struct target *target) { /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ - - uint32_t dtmcontrol = dtmcontrol_scan(target, 0); - LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol); - LOG_DEBUG(" addrbits=%d", get_field(dtmcontrol, DTMCONTROL_ADDRBITS)); - LOG_DEBUG(" version=%d", get_field(dtmcontrol, DTMCONTROL_VERSION)); - LOG_DEBUG(" idle=%d", get_field(dtmcontrol, DTMCONTROL_IDLE)); - if (dtmcontrol == 0) { - LOG_ERROR("dtmcontrol is 0. Check JTAG connectivity/board power."); + uint32_t dtmcontrol; + if (dtmcontrol_scan(target, 0, &dtmcontrol) != ERROR_OK || dtmcontrol == 0) { + LOG_ERROR("Could not scan dtmcontrol. Check JTAG connectivity/board power."); return ERROR_FAIL; } + + LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol); + LOG_DEBUG(" addrbits=%d", get_field32(dtmcontrol, DTMCONTROL_ADDRBITS)); + LOG_DEBUG(" version=%d", get_field32(dtmcontrol, DTMCONTROL_VERSION)); + LOG_DEBUG(" idle=%d", get_field32(dtmcontrol, DTMCONTROL_IDLE)); + if (get_field(dtmcontrol, DTMCONTROL_VERSION) != 0) { LOG_ERROR("Unsupported DTM version %d. (dtmcontrol=0x%x)", - get_field(dtmcontrol, DTMCONTROL_VERSION), dtmcontrol); + get_field32(dtmcontrol, DTMCONTROL_VERSION), dtmcontrol); return ERROR_FAIL; } @@ -1498,22 +1492,22 @@ static int examine(struct target *target) uint32_t dminfo = dbus_read(target, DMINFO); LOG_DEBUG("dminfo: 0x%08x", dminfo); - LOG_DEBUG(" abussize=0x%x", get_field(dminfo, DMINFO_ABUSSIZE)); - LOG_DEBUG(" serialcount=0x%x", get_field(dminfo, DMINFO_SERIALCOUNT)); - LOG_DEBUG(" access128=%d", get_field(dminfo, DMINFO_ACCESS128)); - LOG_DEBUG(" access64=%d", get_field(dminfo, DMINFO_ACCESS64)); - LOG_DEBUG(" access32=%d", get_field(dminfo, DMINFO_ACCESS32)); - LOG_DEBUG(" access16=%d", get_field(dminfo, DMINFO_ACCESS16)); - LOG_DEBUG(" access8=%d", get_field(dminfo, DMINFO_ACCESS8)); - LOG_DEBUG(" dramsize=0x%x", get_field(dminfo, DMINFO_DRAMSIZE)); - LOG_DEBUG(" authenticated=0x%x", get_field(dminfo, DMINFO_AUTHENTICATED)); - LOG_DEBUG(" authbusy=0x%x", get_field(dminfo, DMINFO_AUTHBUSY)); - LOG_DEBUG(" authtype=0x%x", get_field(dminfo, DMINFO_AUTHTYPE)); - LOG_DEBUG(" version=0x%x", get_field(dminfo, DMINFO_VERSION)); + LOG_DEBUG(" abussize=0x%x", get_field32(dminfo, DMINFO_ABUSSIZE)); + LOG_DEBUG(" serialcount=0x%x", get_field32(dminfo, DMINFO_SERIALCOUNT)); + LOG_DEBUG(" access128=%d", get_field32(dminfo, DMINFO_ACCESS128)); + LOG_DEBUG(" access64=%d", get_field32(dminfo, DMINFO_ACCESS64)); + LOG_DEBUG(" access32=%d", get_field32(dminfo, DMINFO_ACCESS32)); + LOG_DEBUG(" access16=%d", get_field32(dminfo, DMINFO_ACCESS16)); + LOG_DEBUG(" access8=%d", get_field32(dminfo, DMINFO_ACCESS8)); + LOG_DEBUG(" dramsize=0x%x", get_field32(dminfo, DMINFO_DRAMSIZE)); + LOG_DEBUG(" authenticated=0x%x", get_field32(dminfo, DMINFO_AUTHENTICATED)); + LOG_DEBUG(" authbusy=0x%x", get_field32(dminfo, DMINFO_AUTHBUSY)); + LOG_DEBUG(" authtype=0x%x", get_field32(dminfo, DMINFO_AUTHTYPE)); + LOG_DEBUG(" version=0x%x", get_field32(dminfo, DMINFO_VERSION)); if (get_field(dminfo, DMINFO_VERSION) != 1) { LOG_ERROR("OpenOCD only supports Debug Module version 1, not %d " - "(dminfo=0x%x)", get_field(dminfo, DMINFO_VERSION), dminfo); + "(dminfo=0x%x)", get_field32(dminfo, DMINFO_VERSION), dminfo); return ERROR_FAIL; } @@ -1552,7 +1546,7 @@ static int examine(struct target *target) uint32_t word0 = cache_get32(target, 0); uint32_t word1 = cache_get32(target, 1); - riscv_info_t *generic_info = (riscv_info_t *) target->arch_info; + struct riscv_info *generic_info = riscv_info(target); if (word0 == 1 && word1 == 0) { generic_info->xlen = 32; } else if (word0 == 0xffffffff && word1 == 3) { @@ -1904,7 +1898,13 @@ static int poll_target(struct target *target, bool announce) int old_debug_level = debug_level; if (debug_level >= LOG_LVL_DEBUG) debug_level = LOG_LVL_INFO; - bits_t bits = read_bits(target); + bits_t bits = { + .haltnot = 0, + .interrupt = 0 + }; + if (read_bits(target, &bits) != ERROR_OK) + return ERROR_FAIL; + debug_level = old_debug_level; if (bits.haltnot && bits.interrupt) { @@ -1935,11 +1935,12 @@ static int riscv011_resume(struct target *target, int current, jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); r->prepped = false; - return resume(target, debug_execution, false); + return execute_resume(target, false); } static int assert_reset(struct target *target) { + RISCV_INFO(r); riscv011_info_t *info = get_info(target); /* TODO: Maybe what I implemented here is more like soft_reset_halt()? */ @@ -1953,9 +1954,9 @@ static int assert_reset(struct target *target) /* Not sure what we should do when there are multiple cores. * Here just reset the single hart we're talking to. */ - info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm); - info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks); - info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku); + info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, r->riscv_ebreakm); + info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, r->riscv_ebreaks); + info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, r->riscv_ebreaku); info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1); info->dcsr |= DCSR_HALT; if (target->reset_halt) @@ -2296,7 +2297,7 @@ static int arch_state(struct target *target) return ERROR_OK; } -COMMAND_HELPER(riscv011_print_info, struct target *target) +static COMMAND_HELPER(riscv011_print_info, struct target *target) { /* Abstract description. */ riscv_print_info_line(CMD, "target", "memory.read_while_running8", 0); diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index ea67343ad1..37e5bba5eb 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Support for RISC-V, debug version 0.13, which is currently (2/4/17) the @@ -28,49 +28,56 @@ #include "program.h" #include "asm.h" #include "batch.h" +#include "debug_reg_printer.h" +#include "field_helpers.h" static int riscv013_on_step_or_resume(struct target *target, bool step); static int riscv013_step_or_resume_current_hart(struct target *target, bool step); -static void riscv013_clear_abstract_error(struct target *target); +static int riscv013_clear_abstract_error(struct target *target); -/* Implementations of the functions in riscv_info_t. */ +/* Implementations of the functions in struct riscv_info. */ static int riscv013_get_register(struct target *target, - riscv_reg_t *value, int rid); -static int riscv013_set_register(struct target *target, int regid, uint64_t value); + riscv_reg_t *value, enum gdb_regno rid); +static int riscv013_set_register(struct target *target, enum gdb_regno regid, + riscv_reg_t value); static int dm013_select_hart(struct target *target, int hart_index); static int riscv013_halt_prep(struct target *target); static int riscv013_halt_go(struct target *target); static int riscv013_resume_go(struct target *target); static int riscv013_step_current_hart(struct target *target); -static int riscv013_on_halt(struct target *target); static int riscv013_on_step(struct target *target); static int riscv013_resume_prep(struct target *target); -static bool riscv013_is_halted(struct target *target); static enum riscv_halt_reason riscv013_halt_reason(struct target *target); -static int riscv013_write_debug_buffer(struct target *target, unsigned index, +static int riscv013_write_progbuf(struct target *target, unsigned int index, riscv_insn_t d); -static riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned +static riscv_insn_t riscv013_read_progbuf(struct target *target, unsigned int index); -static int riscv013_invalidate_cached_debug_buffer(struct target *target); -static int riscv013_execute_debug_buffer(struct target *target); -static void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d); -static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a); -static int riscv013_dmi_write_u64_bits(struct target *target); -static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf); -static int register_read_direct(struct target *target, uint64_t *value, uint32_t number); -static int register_write_direct(struct target *target, unsigned number, - uint64_t value); +static int riscv013_invalidate_cached_progbuf(struct target *target); +static int riscv013_execute_progbuf(struct target *target, uint32_t *cmderr); +static void riscv013_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d); +static void riscv013_fill_dmi_read(struct target *target, char *buf, uint64_t a); +static void riscv013_fill_dmi_nop(struct target *target, char *buf); +static int riscv013_get_dmi_scan_length(struct target *target); +static void riscv013_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d); +static void riscv013_fill_dm_read(struct target *target, char *buf, uint64_t a); +static void riscv013_fill_dm_nop(struct target *target, char *buf); +static unsigned int register_size(struct target *target, enum gdb_regno number); +static int register_read_direct(struct target *target, riscv_reg_t *value, + enum gdb_regno number); +static int register_write_direct(struct target *target, enum gdb_regno number, + riscv_reg_t value); static int read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment); static int write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); -static int riscv013_test_sba_config_reg(struct target *target, target_addr_t legal_address, - uint32_t num_words, target_addr_t illegal_address, bool run_sbbusyerror_test); -void write_memory_sba_simple(struct target *target, target_addr_t addr, uint32_t *write_data, - uint32_t write_size, uint32_t sbcs); -void read_memory_sba_simple(struct target *target, target_addr_t addr, - uint32_t *rd_buf, uint32_t read_size, uint32_t sbcs); + +typedef enum { + HALT_GROUP, + RESUME_GROUP +} grouptype_t; +static int set_group(struct target *target, bool *supported, unsigned int group, + grouptype_t grouptype); /** * Since almost everything can be accomplish by scanning the dbus register, all @@ -79,22 +86,19 @@ void read_memory_sba_simple(struct target *target, target_addr_t addr, * currently in IR. They should set IR to dbus explicitly. */ -#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) -#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) - #define RISCV013_INFO(r) riscv013_info_t *r = get_info(target) /*** JTAG registers. ***/ typedef enum { - DMI_OP_NOP = 0, - DMI_OP_READ = 1, - DMI_OP_WRITE = 2 + DMI_OP_NOP = DTM_DMI_OP_NOP, + DMI_OP_READ = DTM_DMI_OP_READ, + DMI_OP_WRITE = DTM_DMI_OP_WRITE } dmi_op_t; typedef enum { - DMI_STATUS_SUCCESS = 0, - DMI_STATUS_FAILED = 2, - DMI_STATUS_BUSY = 3 + DMI_STATUS_SUCCESS = DTM_DMI_OP_SUCCESS, + DMI_STATUS_FAILED = DTM_DMI_OP_FAILED, + DMI_STATUS_BUSY = DTM_DMI_OP_BUSY } dmi_status_t; typedef enum slot { @@ -105,29 +109,13 @@ typedef enum slot { /*** Debug Bus registers. ***/ -#define CMDERR_NONE 0 -#define CMDERR_BUSY 1 -#define CMDERR_NOT_SUPPORTED 2 -#define CMDERR_EXCEPTION 3 -#define CMDERR_HALT_RESUME 4 -#define CMDERR_OTHER 7 - -/*** Info about the core being debugged. ***/ - -struct trigger { - uint64_t address; - uint32_t length; - uint64_t mask; - uint64_t value; - bool read, write, execute; - int unique_id; -}; - -typedef enum { - YNM_MAYBE, - YNM_YES, - YNM_NO -} yes_no_maybe_t; +/* TODO: CMDERR_* defines can removed */ +#define CMDERR_NONE DM_ABSTRACTCS_CMDERR_NONE +#define CMDERR_BUSY DM_ABSTRACTCS_CMDERR_BUSY +#define CMDERR_NOT_SUPPORTED DM_ABSTRACTCS_CMDERR_NOT_SUPPORTED +#define CMDERR_EXCEPTION DM_ABSTRACTCS_CMDERR_EXCEPTION +#define CMDERR_HALT_RESUME DM_ABSTRACTCS_CMDERR_HALT_RESUME +#define CMDERR_OTHER DM_ABSTRACTCS_CMDERR_OTHER #define HART_INDEX_MULTIPLE -1 #define HART_INDEX_UNKNOWN -2 @@ -135,7 +123,8 @@ typedef enum { typedef struct { struct list_head list; int abs_chain_position; - + /* The base address to access this DM on DMI */ + uint32_t base; /* The number of harts connected to this DM. */ int hart_count; /* Indicates we already reset this DM, so don't need to do it again. */ @@ -202,11 +191,6 @@ typedef struct { yes_no_maybe_t has_aampostincrement; - /* When a function returns some error due to a failure indicated by the - * target in cmderr, the caller can look here to see what that error was. - * (Compare with errno.) */ - uint8_t cmderr; - /* Some fields from hartinfo. */ uint8_t datasize; uint8_t dataaccess; @@ -220,16 +204,23 @@ typedef struct { /* This target was selected using hasel. */ bool selected; + + /* When false, we need to set dcsr.ebreak*, halting the target if that's + * necessary. */ + bool dcsr_ebreak_is_set; + + /* This hart was placed into a halt group in examine(). */ + bool haltgroup_supported; } riscv013_info_t; -LIST_HEAD(dm_list); +static LIST_HEAD(dm_list); static riscv013_info_t *get_info(const struct target *target) { - riscv_info_t *info = (riscv_info_t *) target->arch_info; + struct riscv_info *info = target->arch_info; assert(info); assert(info->version_specific); - return (riscv013_info_t *) info->version_specific; + return info->version_specific; } /** @@ -237,7 +228,7 @@ static riscv013_info_t *get_info(const struct target *target) * global list of DMs. If it's not in there, then create one and initialize it * to 0. */ -dm013_info_t *get_dm(struct target *target) +static dm013_info_t *get_dm(struct target *target) { RISCV013_INFO(info); if (info->dm) @@ -248,18 +239,24 @@ dm013_info_t *get_dm(struct target *target) dm013_info_t *entry; dm013_info_t *dm = NULL; list_for_each_entry(entry, &dm_list, list) { - if (entry->abs_chain_position == abs_chain_position) { + if (entry->abs_chain_position == abs_chain_position + && entry->base == target->dbgbase) { dm = entry; break; } } if (!dm) { - LOG_DEBUG("[%d] Allocating new DM", target->coreid); + LOG_TARGET_DEBUG(target, "Coreid [%d] Allocating new DM", target->coreid); dm = calloc(1, sizeof(dm013_info_t)); if (!dm) return NULL; dm->abs_chain_position = abs_chain_position; + + /* Safety check for dbgbase */ + assert(target->dbgbase_set || target->dbgbase == 0); + + dm->base = target->dbgbase; dm->current_hartid = 0; dm->hart_count = -1; INIT_LIST_HEAD(&dm->target_list); @@ -283,6 +280,63 @@ dm013_info_t *get_dm(struct target *target) return dm; } +static void riscv013_dm_free(struct target *target) +{ + RISCV013_INFO(info); + dm013_info_t *dm = info->dm; + if (!dm) + return; + + target_list_t *target_entry; + list_for_each_entry(target_entry, &dm->target_list, list) { + if (target_entry->target == target) { + list_del(&target_entry->list); + free(target_entry); + break; + } + } + + if (list_empty(&dm->target_list)) { + list_del(&dm->list); + free(dm); + } + info->dm = NULL; +} + +static riscv_debug_reg_ctx_t get_riscv_debug_reg_ctx(const struct target *target) +{ + if (!target_was_examined(target)) { + const riscv_debug_reg_ctx_t default_context = {0}; + return default_context; + } + + RISCV013_INFO(info); + const riscv_debug_reg_ctx_t context = { + .XLEN = { .value = riscv_xlen(target), .is_set = true }, + .DXLEN = { .value = riscv_xlen(target), .is_set = true }, + .abits = { .value = info->abits, .is_set = true }, + }; + return context; +} + +static void log_debug_reg(struct target *target, enum riscv_debug_reg_ordinal reg, + riscv_reg_t value, const char *file, unsigned int line, const char *func) +{ + if (debug_level < LOG_LVL_DEBUG) + return; + const riscv_debug_reg_ctx_t context = get_riscv_debug_reg_ctx(target); + char * const buf = malloc(riscv_debug_reg_to_s(NULL, reg, context, value, RISCV_DEBUG_REG_HIDE_UNNAMED_0) + 1); + if (!buf) { + LOG_ERROR("Unable to allocate memory."); + return; + } + riscv_debug_reg_to_s(buf, reg, context, value, RISCV_DEBUG_REG_HIDE_UNNAMED_0); + log_printf_lf(LOG_LVL_DEBUG, file, line, func, "[%s] %s", target_name(target), buf); + free(buf); +} + +#define LOG_DEBUG_REG(t, r, v) log_debug_reg(t, r##_ORDINAL, v, __FILE__, __LINE__, __func__) + static uint32_t set_dmcontrol_hartsel(uint32_t initial, int hart_index) { assert(hart_index != HART_INDEX_UNKNOWN); @@ -304,86 +358,48 @@ static uint32_t set_dmcontrol_hartsel(uint32_t initial, int hart_index) return initial; } -static void decode_dmi(char *text, unsigned address, unsigned data) +static unsigned int decode_dm(char *text, unsigned int address, unsigned int data) { static const struct { - unsigned address; - uint64_t mask; - const char *name; + unsigned int address; + enum riscv_debug_reg_ordinal ordinal; } description[] = { - { DM_DMCONTROL, DM_DMCONTROL_HALTREQ, "haltreq" }, - { DM_DMCONTROL, DM_DMCONTROL_RESUMEREQ, "resumereq" }, - { DM_DMCONTROL, DM_DMCONTROL_HARTRESET, "hartreset" }, - { DM_DMCONTROL, DM_DMCONTROL_HASEL, "hasel" }, - { DM_DMCONTROL, DM_DMCONTROL_HARTSELHI, "hartselhi" }, - { DM_DMCONTROL, DM_DMCONTROL_HARTSELLO, "hartsello" }, - { DM_DMCONTROL, DM_DMCONTROL_NDMRESET, "ndmreset" }, - { DM_DMCONTROL, DM_DMCONTROL_DMACTIVE, "dmactive" }, - { DM_DMCONTROL, DM_DMCONTROL_ACKHAVERESET, "ackhavereset" }, - - { DM_DMSTATUS, DM_DMSTATUS_IMPEBREAK, "impebreak" }, - { DM_DMSTATUS, DM_DMSTATUS_ALLHAVERESET, "allhavereset" }, - { DM_DMSTATUS, DM_DMSTATUS_ANYHAVERESET, "anyhavereset" }, - { DM_DMSTATUS, DM_DMSTATUS_ALLRESUMEACK, "allresumeack" }, - { DM_DMSTATUS, DM_DMSTATUS_ANYRESUMEACK, "anyresumeack" }, - { DM_DMSTATUS, DM_DMSTATUS_ALLNONEXISTENT, "allnonexistent" }, - { DM_DMSTATUS, DM_DMSTATUS_ANYNONEXISTENT, "anynonexistent" }, - { DM_DMSTATUS, DM_DMSTATUS_ALLUNAVAIL, "allunavail" }, - { DM_DMSTATUS, DM_DMSTATUS_ANYUNAVAIL, "anyunavail" }, - { DM_DMSTATUS, DM_DMSTATUS_ALLRUNNING, "allrunning" }, - { DM_DMSTATUS, DM_DMSTATUS_ANYRUNNING, "anyrunning" }, - { DM_DMSTATUS, DM_DMSTATUS_ALLHALTED, "allhalted" }, - { DM_DMSTATUS, DM_DMSTATUS_ANYHALTED, "anyhalted" }, - { DM_DMSTATUS, DM_DMSTATUS_AUTHENTICATED, "authenticated" }, - { DM_DMSTATUS, DM_DMSTATUS_AUTHBUSY, "authbusy" }, - { DM_DMSTATUS, DM_DMSTATUS_HASRESETHALTREQ, "hasresethaltreq" }, - { DM_DMSTATUS, DM_DMSTATUS_CONFSTRPTRVALID, "confstrptrvalid" }, - { DM_DMSTATUS, DM_DMSTATUS_VERSION, "version" }, - - { DM_ABSTRACTCS, DM_ABSTRACTCS_PROGBUFSIZE, "progbufsize" }, - { DM_ABSTRACTCS, DM_ABSTRACTCS_BUSY, "busy" }, - { DM_ABSTRACTCS, DM_ABSTRACTCS_CMDERR, "cmderr" }, - { DM_ABSTRACTCS, DM_ABSTRACTCS_DATACOUNT, "datacount" }, - - { DM_COMMAND, DM_COMMAND_CMDTYPE, "cmdtype" }, - - { DM_SBCS, DM_SBCS_SBVERSION, "sbversion" }, - { DM_SBCS, DM_SBCS_SBBUSYERROR, "sbbusyerror" }, - { DM_SBCS, DM_SBCS_SBBUSY, "sbbusy" }, - { DM_SBCS, DM_SBCS_SBREADONADDR, "sbreadonaddr" }, - { DM_SBCS, DM_SBCS_SBACCESS, "sbaccess" }, - { DM_SBCS, DM_SBCS_SBAUTOINCREMENT, "sbautoincrement" }, - { DM_SBCS, DM_SBCS_SBREADONDATA, "sbreadondata" }, - { DM_SBCS, DM_SBCS_SBERROR, "sberror" }, - { DM_SBCS, DM_SBCS_SBASIZE, "sbasize" }, - { DM_SBCS, DM_SBCS_SBACCESS128, "sbaccess128" }, - { DM_SBCS, DM_SBCS_SBACCESS64, "sbaccess64" }, - { DM_SBCS, DM_SBCS_SBACCESS32, "sbaccess32" }, - { DM_SBCS, DM_SBCS_SBACCESS16, "sbaccess16" }, - { DM_SBCS, DM_SBCS_SBACCESS8, "sbaccess8" }, + {DM_DMCONTROL, DM_DMCONTROL_ORDINAL}, + {DM_DMSTATUS, DM_DMSTATUS_ORDINAL}, + {DM_ABSTRACTCS, DM_ABSTRACTCS_ORDINAL}, + {DM_COMMAND, DM_COMMAND_ORDINAL}, + {DM_SBCS, DM_SBCS_ORDINAL} }; - text[0] = 0; for (unsigned i = 0; i < ARRAY_SIZE(description); i++) { if (description[i].address == address) { - uint64_t mask = description[i].mask; - unsigned value = get_field(data, mask); - if (value) { - if (i > 0) - *(text++) = ' '; - if (mask & (mask >> 1)) { - /* If the field is more than 1 bit wide. */ - sprintf(text, "%s=%d", description[i].name, value); - } else { - strcpy(text, description[i].name); - } - text += strlen(text); - } + const riscv_debug_reg_ctx_t context = { + .XLEN = { .value = 0, .is_set = false }, + .DXLEN = { .value = 0, .is_set = false }, + .abits = { .value = 0, .is_set = false }, + }; + return riscv_debug_reg_to_s(text, description[i].ordinal, + context, data, RISCV_DEBUG_REG_HIDE_ALL_0); } } + if (text) + text[0] = '\0'; + return 0; +} + +static unsigned int decode_dmi(struct target *target, char *text, unsigned int address, + unsigned int data) +{ + dm013_info_t *dm = get_dm(target); + if (!dm) { + if (text) + text[0] = '\0'; + return 0; + } + return decode_dm(text, address - dm->base, data); } -static void dump_field(int idle, const struct scan_field *field) +static void dump_field(struct target *target, int idle, const struct scan_field *field, bool discard_in) { static const char * const op_string[] = {"-", "r", "w", "?"}; static const char * const status_string[] = {"+", "?", "F", "b"}; @@ -401,19 +417,22 @@ static void dump_field(int idle, const struct scan_field *field) unsigned int in_data = get_field(in, DTM_DMI_DATA); unsigned int in_address = in >> DTM_DMI_ADDRESS_OFFSET; - log_printf_lf(LOG_LVL_DEBUG, - __FILE__, __LINE__, "scan", + log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, __func__, "%db %s %08x @%02x -> %s %08x @%02x; %di", field->num_bits, op_string[out_op], out_data, out_address, status_string[in_op], in_data, in_address, idle); - char out_text[500]; - char in_text[500]; - decode_dmi(out_text, out_address, out_data); - decode_dmi(in_text, in_address, in_data); - if (in_text[0] || out_text[0]) { - log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, "scan", "%s -> %s", - out_text, in_text); + if (out_op == DTM_DMI_OP_WRITE) { + char out_decoded[decode_dmi(target, NULL, out_address, out_data) + 1]; + decode_dmi(target, out_decoded, out_address, out_data); + log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, __func__, + "write: %s", out_decoded); + } + if (!discard_in && in_op == DTM_DMI_OP_SUCCESS) { + char in_decoded[decode_dmi(target, NULL, in_address, in_data) + 1]; + decode_dmi(target, in_decoded, in_address, in_data); + log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, __func__, + "read: %s", in_decoded); } } @@ -428,14 +447,14 @@ static void select_dmi(struct target *target) jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); } -static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) +static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr) { struct scan_field field; uint8_t in_value[4]; uint8_t out_value[4] = { 0 }; if (bscan_tunnel_ir_width != 0) - return dtmcontrol_scan_via_bscan(target, out); + return dtmcontrol_scan_via_bscan(target, out, in_ptr); buf_set_u32(out_value, 0, 32, out); @@ -458,18 +477,20 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) uint32_t in = buf_get_u32(field.in_value, 0, 32); LOG_DEBUG("DTMCS: 0x%x -> 0x%x", out, in); - return in; + if (in_ptr) + *in_ptr = in; + return ERROR_OK; } static void increase_dmi_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); info->dmi_busy_delay += info->dmi_busy_delay / 10 + 1; - LOG_DEBUG("dtmcs_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", + LOG_TARGET_DEBUG(target, "dtmcs_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", info->dtmcs_idle, info->dmi_busy_delay, info->ac_busy_delay); - dtmcontrol_scan(target, DTM_DTMCS_DMIRESET); + dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); } /** @@ -496,6 +517,7 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, if (r->reset_delays_wait >= 0) { r->reset_delays_wait--; if (r->reset_delays_wait < 0) { + LOG_TARGET_DEBUG(target, "reset_delays_wait done"); info->dmi_busy_delay = 0; info->ac_busy_delay = 0; } @@ -504,7 +526,10 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, memset(in, 0, num_bytes); memset(out, 0, num_bytes); - assert(info->abits != 0); + if (info->abits == 0) { + LOG_TARGET_ERROR(target, "Can't access DMI because addrbits=0."); + return DMI_STATUS_FAILED; + } buf_set_u32(out, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, op); buf_set_u32(out, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, data_out); @@ -548,7 +573,7 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, if (address_in) *address_in = buf_get_u32(in, DTM_DMI_ADDRESS_OFFSET, info->abits); - dump_field(idle_count, &field); + dump_field(target, idle_count, &field, /*discard_in*/ !data_in); return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); } @@ -558,7 +583,7 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, * @param dmi_busy_encountered * If non-NULL, will be updated to reflect whether DMI busy was * encountered while executing this operation or not. - * @param dmi_op The operation to perform (read/write/nop). + * @param op The operation to perform (read/write/nop). * @param address The address argument to that operation. * @param data_out The data to send to the target. * @param timeout_sec @@ -569,19 +594,18 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, * DMI operation succeeded. */ static int dmi_op_timeout(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int dmi_op, uint32_t address, + bool *dmi_busy_encountered, int op, uint32_t address, uint32_t data_out, int timeout_sec, bool exec, bool ensure_success) { select_dmi(target); dmi_status_t status; - uint32_t address_in; if (dmi_busy_encountered) *dmi_busy_encountered = false; const char *op_name; - switch (dmi_op) { + switch (op) { case DMI_OP_NOP: op_name = "nop"; break; @@ -592,7 +616,7 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in, op_name = "write"; break; default: - LOG_ERROR("Invalid DMI operation: %d", dmi_op); + LOG_ERROR("Invalid DMI operation: %d", op); return ERROR_FAIL; } @@ -602,7 +626,7 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in, /* This first loop performs the request. Note that if for some reason this * stays busy, it is actually due to the previous access. */ while (1) { - status = dmi_scan(target, NULL, NULL, dmi_op, address, data_out, + status = dmi_scan(target, NULL, NULL, op, address, data_out, exec); if (status == DMI_STATUS_BUSY) { increase_dmi_busy_delay(target); @@ -611,15 +635,15 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in, } else if (status == DMI_STATUS_SUCCESS) { break; } else { - LOG_ERROR("failed %s at 0x%x, status=%d", op_name, address, status); - return ERROR_FAIL; + dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); + break; } if (time(NULL) - start > timeout_sec) return ERROR_TIMEOUT_REACHED; } if (status != DMI_STATUS_SUCCESS) { - LOG_ERROR("Failed %s at 0x%x; status=%d", op_name, address, status); + LOG_TARGET_ERROR(target, "Failed DMI %s at 0x%x; status=%d", op_name, address, status); return ERROR_FAIL; } @@ -628,7 +652,7 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in, * Note that NOP can result in a 'busy' result as well, but that would be * noticed on the next DMI access we do. */ while (1) { - status = dmi_scan(target, &address_in, data_in, DMI_OP_NOP, address, 0, + status = dmi_scan(target, NULL, data_in, DMI_OP_NOP, address, 0, false); if (status == DMI_STATUS_BUSY) { increase_dmi_busy_delay(target); @@ -638,12 +662,15 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in, break; } else { if (data_in) { - LOG_ERROR("Failed %s (NOP) at 0x%x; value=0x%x, status=%d", + LOG_TARGET_ERROR(target, + "Failed DMI %s (NOP) at 0x%x; value=0x%x, status=%d", op_name, address, *data_in, status); } else { - LOG_ERROR("Failed %s (NOP) at 0x%x; status=%d", op_name, address, + LOG_TARGET_ERROR(target, + "Failed DMI %s (NOP) at 0x%x; status=%d", op_name, address, status); } + dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); return ERROR_FAIL; } if (time(NULL) - start > timeout_sec) @@ -655,16 +682,16 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in, } static int dmi_op(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int dmi_op, uint32_t address, + bool *dmi_busy_encountered, int op, uint32_t address, uint32_t data_out, bool exec, bool ensure_success) { - int result = dmi_op_timeout(target, data_in, dmi_busy_encountered, dmi_op, + int result = dmi_op_timeout(target, data_in, dmi_busy_encountered, op, address, data_out, riscv_command_timeout_sec, exec, ensure_success); if (result == ERROR_TIMEOUT_REACHED) { - LOG_ERROR("[%s] DMI operation didn't complete in %d seconds. The target is " + LOG_TARGET_ERROR(target, "DMI operation didn't complete in %d seconds. The target is " "either really slow or broken. You could increase the " "timeout with riscv set_command_timeout_sec.", - target_name(target), riscv_command_timeout_sec); + riscv_command_timeout_sec); return ERROR_FAIL; } return result; @@ -691,19 +718,111 @@ static int dmi_write_exec(struct target *target, uint32_t address, return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value, true, ensure_success); } -int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus, +static uint32_t riscv013_get_dmi_address(const struct target *target, uint32_t address) +{ + assert(target); + uint32_t base = 0; + RISCV013_INFO(info); + if (info && info->dm) + base = info->dm->base; + return address + base; +} + +static int dm_op_timeout(struct target *target, uint32_t *data_in, + bool *dmi_busy_encountered, int op, uint32_t address, + uint32_t data_out, int timeout_sec, bool exec, bool ensure_success) +{ + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + return dmi_op_timeout(target, data_in, dmi_busy_encountered, op, address + dm->base, + data_out, timeout_sec, exec, ensure_success); +} + +static int dm_op(struct target *target, uint32_t *data_in, + bool *dmi_busy_encountered, int op, uint32_t address, + uint32_t data_out, bool exec, bool ensure_success) +{ + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + return dmi_op(target, data_in, dmi_busy_encountered, op, address + dm->base, + data_out, exec, ensure_success); +} + +static int dm_read(struct target *target, uint32_t *value, uint32_t address) +{ + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + return dmi_read(target, value, address + dm->base); +} + +static int dm_read_exec(struct target *target, uint32_t *value, uint32_t address) +{ + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + return dmi_read_exec(target, value, address + dm->base); +} + +static int dm_write(struct target *target, uint32_t address, uint32_t value) +{ + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + return dmi_write(target, address + dm->base, value); +} + +static int dm_write_exec(struct target *target, uint32_t address, + uint32_t value, bool ensure_success) +{ + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + return dmi_write_exec(target, address + dm->base, value, ensure_success); +} + +static bool check_dbgbase_exists(struct target *target) +{ + uint32_t next_dm = 0; + unsigned int count = 1; + + LOG_TARGET_DEBUG(target, "Searching for DM with DMI base address (dbgbase) = 0x%x", target->dbgbase); + while (1) { + uint32_t current_dm = next_dm; + if (current_dm == target->dbgbase) + return true; + if (dmi_read(target, &next_dm, DM_NEXTDM + current_dm) != ERROR_OK) + break; + LOG_TARGET_DEBUG(target, "dm @ 0x%x --> nextdm=0x%x", current_dm, next_dm); + /* Check if it's last one in the chain. */ + if (next_dm == 0) { + LOG_TARGET_ERROR(target, "Reached the end of DM chain (detected %u DMs in total).", count); + break; + } + /* Safety: Avoid looping forever in case of buggy nextdm values in the hardware. */ + if (count++ > RISCV_MAX_DMS) { + LOG_TARGET_ERROR(target, "Supporting no more than %d DMs on a DMI bus. Aborting", RISCV_MAX_DMS); + break; + } + } + return false; +} + +static int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus, bool authenticated, unsigned timeout_sec) { - int result = dmi_op_timeout(target, dmstatus, NULL, DMI_OP_READ, + int result = dm_op_timeout(target, dmstatus, NULL, DMI_OP_READ, DM_DMSTATUS, 0, timeout_sec, false, true); if (result != ERROR_OK) return result; int dmstatus_version = get_field(*dmstatus, DM_DMSTATUS_VERSION); if (dmstatus_version != 2 && dmstatus_version != 3) { LOG_ERROR("OpenOCD only supports Debug Module version 2 (0.13) and 3 (1.0), not " - "%d (dmstatus=0x%x). This error might be caused by a JTAG " + "%" PRId32 " (dmstatus=0x%" PRIx32 "). This error might be caused by a JTAG " "signal issue. Try reducing the JTAG clock speed.", - get_field(*dmstatus, DM_DMSTATUS_VERSION), *dmstatus); + get_field32(*dmstatus, DM_DMSTATUS_VERSION), *dmstatus); } else if (authenticated && !get_field(*dmstatus, DM_DMSTATUS_AUTHENTICATED)) { LOG_ERROR("Debugger is not authenticated to target Debug Module. " "(dmstatus=0x%x). Use `riscv authdata_read` and " @@ -713,7 +832,7 @@ int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus, return ERROR_OK; } -int dmstatus_read(struct target *target, uint32_t *dmstatus, +static int dmstatus_read(struct target *target, uint32_t *dmstatus, bool authenticated) { int result = dmstatus_read_timeout(target, dmstatus, authenticated, @@ -730,12 +849,12 @@ static void increase_ac_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); info->ac_busy_delay += info->ac_busy_delay / 10 + 1; - LOG_DEBUG("dtmcs_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", + LOG_TARGET_DEBUG(target, "dtmcs_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", info->dtmcs_idle, info->dmi_busy_delay, info->ac_busy_delay); } -uint32_t abstract_register_size(unsigned width) +static uint32_t __attribute__((unused)) abstract_register_size(unsigned width) { switch (width) { case 32: @@ -752,25 +871,32 @@ uint32_t abstract_register_size(unsigned width) static int wait_for_idle(struct target *target, uint32_t *abstractcs) { - RISCV013_INFO(info); + assert(target); + assert(abstractcs); + time_t start = time(NULL); - while (1) { - if (dmi_read(target, abstractcs, DM_ABSTRACTCS) != ERROR_OK) + do { + if (dm_read(target, abstractcs, DM_ABSTRACTCS) != ERROR_OK) { + /* We couldn't read abstractcs. For safety, overwrite the output value to + * prevent the caller working with a stale value of abstractcs. */ + *abstractcs = 0; + LOG_TARGET_ERROR(target, + "potentially unrecoverable error detected - could not read abstractcs"); return ERROR_FAIL; + } if (get_field(*abstractcs, DM_ABSTRACTCS_BUSY) == 0) return ERROR_OK; - if (time(NULL) - start > riscv_command_timeout_sec) { - info->cmderr = get_field(*abstractcs, DM_ABSTRACTCS_CMDERR); + } while ((time(NULL) - start) < riscv_command_timeout_sec); - LOG_ERROR("Timed out after %ds waiting for busy to go low (abstractcs=0x%x). " - "Increase the timeout with riscv set_command_timeout_sec.", - riscv_command_timeout_sec, - *abstractcs); - return ERROR_FAIL; - } - } + LOG_TARGET_ERROR(target, + "Timed out after %ds waiting for busy to go low (abstractcs=0x%" PRIx32 "). " + "Increase the timeout with riscv set_command_timeout_sec.", + riscv_command_timeout_sec, + *abstractcs); + + return ERROR_TIMEOUT_REACHED; } static int dm013_select_target(struct target *target) @@ -779,38 +905,43 @@ static int dm013_select_target(struct target *target) return dm013_select_hart(target, info->index); } -static int execute_abstract_command(struct target *target, uint32_t command) +static int execute_abstract_command(struct target *target, uint32_t command, + uint32_t *cmderr) { - RISCV013_INFO(info); + assert(cmderr); + *cmderr = CMDERR_NONE; if (debug_level >= LOG_LVL_DEBUG) { switch (get_field(command, DM_COMMAND_CMDTYPE)) { case 0: - LOG_DEBUG("command=0x%x; access register, size=%d, postexec=%d, " - "transfer=%d, write=%d, regno=0x%x", - command, - 8 << get_field(command, AC_ACCESS_REGISTER_AARSIZE), - get_field(command, AC_ACCESS_REGISTER_POSTEXEC), - get_field(command, AC_ACCESS_REGISTER_TRANSFER), - get_field(command, AC_ACCESS_REGISTER_WRITE), - get_field(command, AC_ACCESS_REGISTER_REGNO)); + LOG_DEBUG_REG(target, AC_ACCESS_REGISTER, command); break; default: - LOG_DEBUG("command=0x%x", command); + LOG_TARGET_DEBUG(target, "command=0x%x", command); break; } } - if (dmi_write_exec(target, DM_COMMAND, command, false) != ERROR_OK) + if (dm_write_exec(target, DM_COMMAND, command, false /* ensure success */) != ERROR_OK) return ERROR_FAIL; - uint32_t abstractcs = 0; - int result = wait_for_idle(target, &abstractcs); - - info->cmderr = get_field(abstractcs, DM_ABSTRACTCS_CMDERR); - if (info->cmderr != 0 || result != ERROR_OK) { - LOG_DEBUG("command 0x%x failed; abstractcs=0x%x", command, abstractcs); - /* Clear the error. */ - dmi_write(target, DM_ABSTRACTCS, DM_ABSTRACTCS_CMDERR); + uint32_t abstractcs; + int wait_result = wait_for_idle(target, &abstractcs); + if (wait_result != ERROR_OK) { + /* TODO: can we recover from this? */ + if (wait_result == ERROR_TIMEOUT_REACHED) + LOG_TARGET_DEBUG(target, "command 0x%" PRIx32 " failed (timeout)", command); + else + LOG_TARGET_DEBUG(target, "command 0x%" PRIx32 " failed (unknown fatal error %d)", command, wait_result); + return wait_result; + } + *cmderr = get_field32(abstractcs, DM_ABSTRACTCS_CMDERR); + if (*cmderr != CMDERR_NONE) { + LOG_TARGET_DEBUG(target, "command 0x%" PRIx32 " failed; abstractcs=0x%" PRIx32, + command, abstractcs); + /* Attempt to clear the error. */ + /* TODO: can we add a more substantial recovery if the clear operation fails ? */ + if (dm_write(target, DM_ABSTRACTCS, DM_ABSTRACTCS_CMDERR) != ERROR_OK) + LOG_TARGET_ERROR(target, "could not clear abstractcs error"); return ERROR_FAIL; } @@ -825,15 +956,15 @@ static riscv_reg_t read_abstract_arg(struct target *target, unsigned index, unsigned offset = index * size_bits / 32; switch (size_bits) { default: - LOG_ERROR("Unsupported size: %d bits", size_bits); + LOG_TARGET_ERROR(target, "Unsupported size: %d bits", size_bits); return ~0; case 64: - dmi_read(target, &v, DM_DATA0 + offset + 1); - value |= ((uint64_t) v) << 32; + if (dm_read(target, &v, DM_DATA0 + offset + 1) == ERROR_OK) + value |= ((uint64_t)v) << 32; /* falls through */ case 32: - dmi_read(target, &v, DM_DATA0 + offset); - value |= v; + if (dm_read(target, &v, DM_DATA0 + offset) == ERROR_OK) + value |= v; } return value; } @@ -844,13 +975,13 @@ static int write_abstract_arg(struct target *target, unsigned index, unsigned offset = index * size_bits / 32; switch (size_bits) { default: - LOG_ERROR("Unsupported size: %d bits", size_bits); + LOG_TARGET_ERROR(target, "Unsupported size: %d bits", size_bits); return ERROR_FAIL; case 64: - dmi_write(target, DM_DATA0 + offset + 1, value >> 32); + dm_write(target, DM_DATA0 + offset + 1, (uint32_t)(value >> 32)); /* falls through */ case 32: - dmi_write(target, DM_DATA0 + offset, value); + dm_write(target, DM_DATA0 + offset, (uint32_t)value); } return ERROR_OK; } @@ -870,8 +1001,8 @@ static uint32_t access_register_command(struct target *target, uint32_t number, command = set_field(command, AC_ACCESS_REGISTER_AARSIZE, 3); break; default: - LOG_ERROR("[%s] %d-bit register %s not supported.", - target_name(target), size, gdb_regno_name(number)); + LOG_TARGET_ERROR(target, "%d-bit register %s not supported.", + size, gdb_regno_name(target, number)); assert(0); } @@ -900,8 +1031,8 @@ static uint32_t access_register_command(struct target *target, uint32_t number, return command; } -static int register_read_abstract(struct target *target, uint64_t *value, - uint32_t number, unsigned size) +static int register_read_abstract_with_size(struct target *target, + riscv_reg_t *value, enum gdb_regno number, unsigned int size) { RISCV013_INFO(info); @@ -918,15 +1049,16 @@ static int register_read_abstract(struct target *target, uint64_t *value, uint32_t command = access_register_command(target, number, size, AC_ACCESS_REGISTER_TRANSFER); - int result = execute_abstract_command(target, command); + uint32_t cmderr; + int result = execute_abstract_command(target, command, &cmderr); if (result != ERROR_OK) { - if (info->cmderr == CMDERR_NOT_SUPPORTED) { + if (cmderr == CMDERR_NOT_SUPPORTED) { if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { info->abstract_read_fpr_supported = false; - LOG_INFO("Disabling abstract command reads from FPRs."); + LOG_TARGET_INFO(target, "Disabling abstract command reads from FPRs."); } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { info->abstract_read_csr_supported = false; - LOG_INFO("Disabling abstract command reads from CSRs."); + LOG_TARGET_INFO(target, "Disabling abstract command reads from CSRs."); } } return result; @@ -938,10 +1070,19 @@ static int register_read_abstract(struct target *target, uint64_t *value, return ERROR_OK; } -static int register_write_abstract(struct target *target, uint32_t number, - uint64_t value, unsigned size) +static int register_read_abstract(struct target *target, riscv_reg_t *value, + enum gdb_regno number) +{ + const unsigned int size = register_size(target, number); + + return register_read_abstract_with_size(target, value, number, size); +} + +static int register_write_abstract(struct target *target, enum gdb_regno number, + riscv_reg_t value) { RISCV013_INFO(info); + const unsigned int size = register_size(target, number); if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && !info->abstract_write_fpr_supported) @@ -957,15 +1098,16 @@ static int register_write_abstract(struct target *target, uint32_t number, if (write_abstract_arg(target, 0, value, size) != ERROR_OK) return ERROR_FAIL; - int result = execute_abstract_command(target, command); + uint32_t cmderr; + int result = execute_abstract_command(target, command, &cmderr); if (result != ERROR_OK) { - if (info->cmderr == CMDERR_NOT_SUPPORTED) { + if (cmderr == CMDERR_NOT_SUPPORTED) { if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { info->abstract_write_fpr_supported = false; - LOG_INFO("Disabling abstract command writes to FPRs."); + LOG_TARGET_INFO(target, "Disabling abstract command writes to FPRs."); } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { info->abstract_write_csr_supported = false; - LOG_INFO("Disabling abstract command writes to CSRs."); + LOG_TARGET_INFO(target, "Disabling abstract command writes to CSRs."); } } return result; @@ -1001,14 +1143,14 @@ static uint32_t abstract_memory_size(unsigned width) * Creates a memory access abstract command. */ static uint32_t access_memory_command(struct target *target, bool virtual, - unsigned width, bool postincrement, bool write) + unsigned int width, bool postincrement, bool is_write) { uint32_t command = set_field(0, AC_ACCESS_MEMORY_CMDTYPE, 2); command = set_field(command, AC_ACCESS_MEMORY_AAMVIRTUAL, virtual); command |= abstract_memory_size(width); command = set_field(command, AC_ACCESS_MEMORY_AAMPOSTINCREMENT, postincrement); - command = set_field(command, AC_ACCESS_MEMORY_WRITE, write); + command = set_field(command, AC_ACCESS_MEMORY_WRITE, is_write); return command; } @@ -1024,7 +1166,7 @@ static int examine_progbuf(struct target *target) if (info->progbufsize < 1) { info->progbuf_writable = YNM_NO; - LOG_INFO("No program buffer present."); + LOG_TARGET_INFO(target, "No program buffer present."); return ERROR_OK; } @@ -1052,15 +1194,15 @@ static int examine_progbuf(struct target *target) } uint32_t written; - if (dmi_read(target, &written, DM_PROGBUF0) != ERROR_OK) + if (dm_read(target, &written, DM_PROGBUF0) != ERROR_OK) return ERROR_FAIL; if (written == (uint32_t) info->progbuf_address) { - LOG_INFO("progbuf is writable at 0x%" PRIx64, + LOG_TARGET_INFO(target, "progbuf is writable at 0x%" PRIx64, info->progbuf_address); info->progbuf_writable = YNM_YES; } else { - LOG_INFO("progbuf is not writeable at 0x%" PRIx64, + LOG_TARGET_INFO(target, "progbuf is not writeable at 0x%" PRIx64, info->progbuf_address); info->progbuf_writable = YNM_NO; } @@ -1068,7 +1210,7 @@ static int examine_progbuf(struct target *target) return ERROR_OK; } -static int is_fpu_reg(uint32_t gdb_regno) +static int is_fpu_reg(enum gdb_regno gdb_regno) { return (gdb_regno >= GDB_REGNO_FPR0 && gdb_regno <= GDB_REGNO_FPR31) || (gdb_regno == GDB_REGNO_CSR0 + CSR_FFLAGS) || @@ -1076,46 +1218,66 @@ static int is_fpu_reg(uint32_t gdb_regno) (gdb_regno == GDB_REGNO_CSR0 + CSR_FCSR); } -static int is_vector_reg(uint32_t gdb_regno) +static int is_vector_reg(enum gdb_regno gdb_regno) { return (gdb_regno >= GDB_REGNO_V0 && gdb_regno <= GDB_REGNO_V31) || gdb_regno == GDB_REGNO_VSTART || gdb_regno == GDB_REGNO_VXSAT || gdb_regno == GDB_REGNO_VXRM || + gdb_regno == GDB_REGNO_VCSR || gdb_regno == GDB_REGNO_VL || gdb_regno == GDB_REGNO_VTYPE || gdb_regno == GDB_REGNO_VLENB; } -static int prep_for_register_access(struct target *target, uint64_t *mstatus, - int regno) +static int prep_for_register_access(struct target *target, + riscv_reg_t *orig_mstatus, enum gdb_regno regno) { - if (is_fpu_reg(regno) || is_vector_reg(regno)) { - if (register_read_direct(target, mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) - return ERROR_FAIL; - if (is_fpu_reg(regno) && (*mstatus & MSTATUS_FS) == 0) { - if (register_write_direct(target, GDB_REGNO_MSTATUS, - set_field(*mstatus, MSTATUS_FS, 1)) != ERROR_OK) - return ERROR_FAIL; - } else if (is_vector_reg(regno) && (*mstatus & MSTATUS_VS) == 0) { - if (register_write_direct(target, GDB_REGNO_MSTATUS, - set_field(*mstatus, MSTATUS_VS, 1)) != ERROR_OK) - return ERROR_FAIL; - } - } else { - *mstatus = 0; + assert(orig_mstatus); + + if (!is_fpu_reg(regno) && !is_vector_reg(regno)) { + /* If we don't assign orig_mstatus, clang static analysis + * complains when this value is passed to + * cleanup_after_register_access(). */ + *orig_mstatus = 0; + /* No special preparation needed */ + return ERROR_OK; } + + LOG_TARGET_DEBUG(target, "Preparing mstatus to access %s", + gdb_regno_name(target, regno)); + + assert(target->state == TARGET_HALTED && + "The target must be halted to modify and then restore mstatus"); + + if (riscv_get_register(target, orig_mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) + return ERROR_FAIL; + + riscv_reg_t new_mstatus = *orig_mstatus; + riscv_reg_t field_mask = is_fpu_reg(regno) ? MSTATUS_FS : MSTATUS_VS; + + if ((new_mstatus & field_mask) != 0) + return ERROR_OK; + + new_mstatus = set_field(new_mstatus, field_mask, 1); + + if (riscv_write_register(target, GDB_REGNO_MSTATUS, new_mstatus) != ERROR_OK) + return ERROR_FAIL; + + LOG_TARGET_DEBUG(target, "Prepared to access %s (mstatus=0x%" PRIx64 ")", + gdb_regno_name(target, regno), new_mstatus); return ERROR_OK; } static int cleanup_after_register_access(struct target *target, - uint64_t mstatus, int regno) + riscv_reg_t mstatus, enum gdb_regno regno) { - if ((is_fpu_reg(regno) && (mstatus & MSTATUS_FS) == 0) || - (is_vector_reg(regno) && (mstatus & MSTATUS_VS) == 0)) - if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus) != ERROR_OK) - return ERROR_FAIL; - return ERROR_OK; + if (!is_fpu_reg(regno) && !is_vector_reg(regno)) + /* Mstatus was not changed for this register access. No need to restore it. */ + return ERROR_OK; + + LOG_TARGET_DEBUG(target, "Restoring mstatus to 0x%" PRIx64, mstatus); + return riscv_write_register(target, GDB_REGNO_MSTATUS, mstatus); } typedef enum { @@ -1193,7 +1355,7 @@ static int scratch_reserve(struct target *target, return ERROR_OK; } - LOG_ERROR("Couldn't find %d bytes of scratch RAM to use. Please configure " + LOG_TARGET_ERROR(target, "Couldn't find %d bytes of scratch RAM to use. Please configure " "a work area with 'configure -work-area-phys'.", size_bytes); return ERROR_FAIL; } @@ -1210,18 +1372,18 @@ static int scratch_read64(struct target *target, scratch_mem_t *scratch, uint32_t v; switch (scratch->memory_space) { case SPACE_DM_DATA: - if (dmi_read(target, &v, DM_DATA0 + scratch->debug_address) != ERROR_OK) + if (dm_read(target, &v, DM_DATA0 + scratch->debug_address) != ERROR_OK) return ERROR_FAIL; *value = v; - if (dmi_read(target, &v, DM_DATA1 + scratch->debug_address) != ERROR_OK) + if (dm_read(target, &v, DM_DATA1 + scratch->debug_address) != ERROR_OK) return ERROR_FAIL; *value |= ((uint64_t) v) << 32; break; case SPACE_DMI_PROGBUF: - if (dmi_read(target, &v, DM_PROGBUF0 + scratch->debug_address) != ERROR_OK) + if (dm_read(target, &v, DM_PROGBUF0 + scratch->debug_address) != ERROR_OK) return ERROR_FAIL; *value = v; - if (dmi_read(target, &v, DM_PROGBUF1 + scratch->debug_address) != ERROR_OK) + if (dm_read(target, &v, DM_PROGBUF1 + scratch->debug_address) != ERROR_OK) return ERROR_FAIL; *value |= ((uint64_t) v) << 32; break; @@ -1249,13 +1411,13 @@ static int scratch_write64(struct target *target, scratch_mem_t *scratch, { switch (scratch->memory_space) { case SPACE_DM_DATA: - dmi_write(target, DM_DATA0 + scratch->debug_address, value); - dmi_write(target, DM_DATA1 + scratch->debug_address, value >> 32); + dm_write(target, DM_DATA0 + scratch->debug_address, (uint32_t)value); + dm_write(target, DM_DATA1 + scratch->debug_address, (uint32_t)(value >> 32)); break; case SPACE_DMI_PROGBUF: - dmi_write(target, DM_PROGBUF0 + scratch->debug_address, value); - dmi_write(target, DM_PROGBUF1 + scratch->debug_address, value >> 32); - riscv013_invalidate_cached_debug_buffer(target); + dm_write(target, DM_PROGBUF0 + scratch->debug_address, (uint32_t)value); + dm_write(target, DM_PROGBUF1 + scratch->debug_address, (uint32_t)(value >> 32)); + riscv013_invalidate_cached_progbuf(target); break; case SPACE_DMI_RAM: { @@ -1278,7 +1440,7 @@ static int scratch_write64(struct target *target, scratch_mem_t *scratch, } /** Return register size in bits. */ -static unsigned register_size(struct target *target, unsigned number) +static unsigned int register_size(struct target *target, enum gdb_regno number) { /* If reg_cache hasn't been initialized yet, make a guess. We need this for * when this function is called during examine(). */ @@ -1297,193 +1459,308 @@ static bool has_sufficient_progbuf(struct target *target, unsigned size) } /** - * Immediately write the new value to the requested register. This mechanism - * bypasses any caches. + * This function is used to read a 64-bit value from a register by executing a + * program. + * The program stores a register to address located in S0. + * The caller should save S0. */ -static int register_write_direct(struct target *target, unsigned number, - uint64_t value) +static int internal_register_read64_progbuf_scratch(struct target *target, + struct riscv_program *program, riscv_reg_t *value) { - LOG_TARGET_DEBUG(target, "%s <- 0x%" PRIx64, gdb_regno_name(number), value); - - int result = register_write_abstract(target, number, value, - register_size(target, number)); - if (result == ERROR_OK || !has_sufficient_progbuf(target, 2) || - !riscv_is_halted(target)) - return result; - - struct riscv_program program; - riscv_program_init(&program, target); + scratch_mem_t scratch; - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + if (scratch_reserve(target, &scratch, program, 8) != ERROR_OK) return ERROR_FAIL; - uint64_t mstatus; - if (prep_for_register_access(target, &mstatus, number) != ERROR_OK) + if (register_write_abstract(target, GDB_REGNO_S0, scratch.hart_address) + != ERROR_OK) { + scratch_release(target, &scratch); + return ERROR_FAIL; + } + if (riscv_program_exec(program, target) != ERROR_OK) { + scratch_release(target, &scratch); return ERROR_FAIL; + } - scratch_mem_t scratch; - bool use_scratch = false; - if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && - riscv_supports_extension(target, 'D') && - riscv_xlen(target) < 64) { - /* There are no instructions to move all the bits from a register, so - * we need to use some scratch RAM. */ - use_scratch = true; - if (riscv_program_insert(&program, fld(number - GDB_REGNO_FPR0, S0, 0)) - != ERROR_OK) - return ERROR_FAIL; + int result = scratch_read64(target, &scratch, value); - if (scratch_reserve(target, &scratch, &program, 8) != ERROR_OK) - return ERROR_FAIL; + scratch_release(target, &scratch); + return result; +} - if (register_write_direct(target, GDB_REGNO_S0, scratch.hart_address) - != ERROR_OK) { - scratch_release(target, &scratch); - return ERROR_FAIL; - } +static int fpr_read_progbuf(struct target *target, uint64_t *value, + enum gdb_regno number) +{ + assert(target->state == TARGET_HALTED); + assert(number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31); - if (scratch_write64(target, &scratch, value) != ERROR_OK) { - scratch_release(target, &scratch); - return ERROR_FAIL; - } + const unsigned int freg = number - GDB_REGNO_FPR0; - } else { - if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (riscv_supports_extension(target, 'D')) { - if (riscv_program_insert(&program, - fmv_d_x(number - GDB_REGNO_FPR0, S0)) != ERROR_OK) - return ERROR_FAIL; - } else { - if (riscv_program_insert(&program, - fmv_w_x(number - GDB_REGNO_FPR0, S0)) != ERROR_OK) - return ERROR_FAIL; - } - } else if (number == GDB_REGNO_VTYPE) { - if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(&program, csrr(S1, CSR_VL)) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(&program, vsetvl(ZERO, S1, S0)) != ERROR_OK) - return ERROR_FAIL; - } else if (number == GDB_REGNO_VL) { - /* "The XLEN-bit-wide read-only vl CSR can only be updated by the - * vsetvli and vsetvl instructions, and the fault-only-rst vector - * load instruction variants." */ - if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(&program, csrr(S1, CSR_VTYPE)) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(&program, vsetvl(ZERO, S0, S1)) != ERROR_OK) - return ERROR_FAIL; - } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - if (riscv_program_csrw(&program, S0, number) != ERROR_OK) - return ERROR_FAIL; - } else { - LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); - return ERROR_FAIL; - } - if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK) + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + struct riscv_program program; + riscv_program_init(&program, target); + if (riscv_supports_extension(target, 'D') && riscv_xlen(target) < 64) { + /* There are no instructions to move all the bits from a + * register, so we need to use some scratch RAM. + */ + if (riscv_program_insert(&program, fsd(freg, S0, 0)) != ERROR_OK) return ERROR_FAIL; + return internal_register_read64_progbuf_scratch(target, &program, value); } + if (riscv_program_insert(&program, + riscv_supports_extension(target, 'D') ? + fmv_x_d(S0, freg) : fmv_x_w(S0, freg)) != ERROR_OK) + return ERROR_FAIL; - int exec_out = riscv_program_exec(&program, target); - /* Don't message on error. Probably the register doesn't exist. */ - if (exec_out == ERROR_OK && target->reg_cache) { - struct reg *reg = &target->reg_cache->reg_list[number]; - buf_set_u64(reg->value, 0, reg->size, value); - } + if (riscv_program_exec(&program, target) != ERROR_OK) + return ERROR_FAIL; - if (use_scratch) - scratch_release(target, &scratch); + return register_read_abstract(target, value, GDB_REGNO_S0) != ERROR_OK; +} - if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK) +static int csr_read_progbuf(struct target *target, uint64_t *value, + enum gdb_regno number) +{ + assert(target->state == TARGET_HALTED); + assert(number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095); + + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + struct riscv_program program; + riscv_program_init(&program, target); + if (riscv_program_csrr(&program, S0, number) != ERROR_OK) + return ERROR_FAIL; + if (riscv_program_exec(&program, target) != ERROR_OK) return ERROR_FAIL; - return exec_out; + return register_read_abstract(target, value, GDB_REGNO_S0) != ERROR_OK; } -/** Actually read registers from the target right now. */ -static int register_read_direct(struct target *target, uint64_t *value, uint32_t number) +/** + * This function reads a register by writing a program to program buffer and + * executing it. + */ +static int register_read_progbuf(struct target *target, uint64_t *value, + enum gdb_regno number) { - if (dm013_select_target(target) != ERROR_OK) + assert(target->state == TARGET_HALTED); + + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) + return fpr_read_progbuf(target, value, number); + else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) + return csr_read_progbuf(target, value, number); + + LOG_TARGET_ERROR(target, "Unexpected read of %s via program buffer.", + gdb_regno_name(target, number)); + return ERROR_FAIL; +} + +/** + * This function is used to write a 64-bit value to a register by executing a + * program. + * The program loads a value from address located in S0 to a register. + * The caller should save S0. + */ +static int internal_register_write64_progbuf_scratch(struct target *target, + struct riscv_program *program, riscv_reg_t value) +{ + scratch_mem_t scratch; + + if (scratch_reserve(target, &scratch, program, 8) != ERROR_OK) return ERROR_FAIL; - int result = register_read_abstract(target, value, number, - register_size(target, number)); + if (register_write_abstract(target, GDB_REGNO_S0, scratch.hart_address) + != ERROR_OK) { + scratch_release(target, &scratch); + return ERROR_FAIL; + } + if (scratch_write64(target, &scratch, value) != ERROR_OK) { + scratch_release(target, &scratch); + return ERROR_FAIL; + } + int result = riscv_program_exec(program, target); - if (result != ERROR_OK && - has_sufficient_progbuf(target, 2) && - number > GDB_REGNO_XPR31) { - struct riscv_program program; - riscv_program_init(&program, target); + scratch_release(target, &scratch); + return result; +} - scratch_mem_t scratch; - bool use_scratch = false; +static int fpr_write_progbuf(struct target *target, enum gdb_regno number, + riscv_reg_t value) +{ + assert(target->state == TARGET_HALTED); + assert(number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31); + const unsigned int freg = number - GDB_REGNO_FPR0; - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) - return ERROR_FAIL; + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; - /* Write program to move data into s0. */ + struct riscv_program program; + riscv_program_init(&program, target); - uint64_t mstatus; - if (prep_for_register_access(target, &mstatus, number) != ERROR_OK) + if (riscv_supports_extension(target, 'D') && riscv_xlen(target) < 64) { + /* There are no instructions to move all the bits from a register, + * so we need to use some scratch RAM. + */ + if (riscv_program_insert(&program, fld(freg, S0, 0)) != ERROR_OK) return ERROR_FAIL; + return internal_register_write64_progbuf_scratch(target, &program, value); + } - if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (riscv_supports_extension(target, 'D') - && riscv_xlen(target) < 64) { - /* There are no instructions to move all the bits from a - * register, so we need to use some scratch RAM. */ - if (riscv_program_insert(&program, - fsd(number - GDB_REGNO_FPR0, S0, 0)) != ERROR_OK) - return ERROR_FAIL; - if (scratch_reserve(target, &scratch, &program, 8) != ERROR_OK) - return ERROR_FAIL; - use_scratch = true; + if (register_write_abstract(target, GDB_REGNO_S0, value) != ERROR_OK) + return ERROR_FAIL; - if (register_write_direct(target, GDB_REGNO_S0, - scratch.hart_address) != ERROR_OK) { - scratch_release(target, &scratch); - return ERROR_FAIL; - } - } else if (riscv_supports_extension(target, 'D')) { - if (riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)) != - ERROR_OK) - return ERROR_FAIL; - } else { - if (riscv_program_insert(&program, fmv_x_w(S0, number - GDB_REGNO_FPR0)) != - ERROR_OK) - return ERROR_FAIL; - } - } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - if (riscv_program_csrr(&program, S0, number) != ERROR_OK) - return ERROR_FAIL; - } else { - LOG_ERROR("Unsupported register: %s", gdb_regno_name(number)); - return ERROR_FAIL; - } + if (riscv_program_insert(&program, + riscv_supports_extension(target, 'D') ? + fmv_d_x(freg, S0) : fmv_w_x(freg, S0)) != ERROR_OK) + return ERROR_FAIL; - /* Execute program. */ - result = riscv_program_exec(&program, target); - /* Don't message on error. Probably the register doesn't exist. */ + return riscv_program_exec(&program, target); +} - if (use_scratch) { - result = scratch_read64(target, &scratch, value); - scratch_release(target, &scratch); - if (result != ERROR_OK) - return result; - } else { - /* Read S0 */ - if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK) - return ERROR_FAIL; - } +static int vtype_write_progbuf(struct target *target, riscv_reg_t value) +{ + assert(target->state == TARGET_HALTED); - if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK) - return ERROR_FAIL; - } + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + if (register_write_abstract(target, GDB_REGNO_S0, value) != ERROR_OK) + return ERROR_FAIL; + if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + + struct riscv_program program; + riscv_program_init(&program, target); + if (riscv_program_insert(&program, csrr(S1, CSR_VL)) != ERROR_OK) + return ERROR_FAIL; + if (riscv_program_insert(&program, vsetvl(ZERO, S1, S0)) != ERROR_OK) + return ERROR_FAIL; + + return riscv_program_exec(&program, target); +} + +static int vl_write_progbuf(struct target *target, riscv_reg_t value) +{ + assert(target->state == TARGET_HALTED); + + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + if (register_write_abstract(target, GDB_REGNO_S0, value) != ERROR_OK) + return ERROR_FAIL; + if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + + struct riscv_program program; + riscv_program_init(&program, target); + if (riscv_program_insert(&program, csrr(S1, CSR_VTYPE)) != ERROR_OK) + return ERROR_FAIL; + if (riscv_program_insert(&program, vsetvl(ZERO, S0, S1)) != ERROR_OK) + return ERROR_FAIL; + + return riscv_program_exec(&program, target); +} + +static int csr_write_progbuf(struct target *target, enum gdb_regno number, + riscv_reg_t value) +{ + assert(target->state == TARGET_HALTED); + assert(number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095); + + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + if (register_write_abstract(target, GDB_REGNO_S0, value) != ERROR_OK) + return ERROR_FAIL; + + struct riscv_program program; + riscv_program_init(&program, target); + if (riscv_program_csrw(&program, S0, number) != ERROR_OK) + return ERROR_FAIL; + + return riscv_program_exec(&program, target); +} + +/** + * This function writes a register by writing a program to program buffer and + * executing it. + */ +static int register_write_progbuf(struct target *target, enum gdb_regno number, + riscv_reg_t value) +{ + assert(target->state == TARGET_HALTED); + + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) + return fpr_write_progbuf(target, number, value); + else if (number == GDB_REGNO_VTYPE) + return vtype_write_progbuf(target, value); + else if (number == GDB_REGNO_VL) + return vl_write_progbuf(target, value); + else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) + return csr_write_progbuf(target, number, value); + + LOG_TARGET_ERROR(target, "Unexpected write to %s via program buffer.", + gdb_regno_name(target, number)); + return ERROR_FAIL; +} + +/** + * Immediately write the new value to the requested register. This mechanism + * bypasses any caches. + */ +static int register_write_direct(struct target *target, enum gdb_regno number, + riscv_reg_t value) +{ + LOG_TARGET_DEBUG(target, "Writing 0x%" PRIx64 " to %s", value, + gdb_regno_name(target, number)); + + if (target->state != TARGET_HALTED) + return register_write_abstract(target, number, value); + + riscv_reg_t mstatus; + if (prep_for_register_access(target, &mstatus, number) != ERROR_OK) + return ERROR_FAIL; + + int result = register_write_abstract(target, number, value); + + if (result != ERROR_OK && target->state == TARGET_HALTED) + result = register_write_progbuf(target, number, value); + + if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK) + return ERROR_FAIL; + + if (result == ERROR_OK) + LOG_TARGET_DEBUG(target, "%s <- 0x%" PRIx64, gdb_regno_name(target, number), + value); + + return result; +} + +/** Actually read registers from the target right now. */ +static int register_read_direct(struct target *target, riscv_reg_t *value, + enum gdb_regno number) +{ + LOG_TARGET_DEBUG(target, "Reading %s", gdb_regno_name(target, number)); + + if (target->state != TARGET_HALTED) + return register_read_abstract(target, value, number); + + riscv_reg_t mstatus; + + if (prep_for_register_access(target, &mstatus, number) != ERROR_OK) + return ERROR_FAIL; + + int result = register_read_abstract(target, value, number); + + if (result != ERROR_OK && target->state == TARGET_HALTED) + result = register_read_progbuf(target, value, number); + + if (cleanup_after_register_access(target, mstatus, number) != ERROR_OK) + return ERROR_FAIL; if (result == ERROR_OK) - LOG_TARGET_DEBUG(target, "%s = 0x%" PRIx64, gdb_regno_name(number), *value); + LOG_TARGET_DEBUG(target, "%s = 0x%" PRIx64, gdb_regno_name(target, number), + *value); return result; } @@ -1500,7 +1777,7 @@ static int wait_for_authbusy(struct target *target, uint32_t *dmstatus) if (!get_field(value, DM_DMSTATUS_AUTHBUSY)) break; if (time(NULL) - start > riscv_command_timeout_sec) { - LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dmstatus=0x%x). " + LOG_TARGET_ERROR(target, "Timed out after %ds waiting for authbusy to go low (dmstatus=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", riscv_command_timeout_sec, value); @@ -1511,108 +1788,196 @@ static int wait_for_authbusy(struct target *target, uint32_t *dmstatus) return ERROR_OK; } +static int set_dcsr_ebreak(struct target *target, bool step) +{ + LOG_TARGET_DEBUG(target, "Set dcsr.ebreak*"); + + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; + + RISCV_INFO(r); + RISCV013_INFO(info); + riscv_reg_t original_dcsr, dcsr; + /* We want to twiddle some bits in the debug CSR so debugging works. */ + if (riscv_get_register(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) + return ERROR_FAIL; + original_dcsr = dcsr; + dcsr = set_field(dcsr, CSR_DCSR_STEP, step); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, r->riscv_ebreakm); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, r->riscv_ebreaks && riscv_supports_extension(target, 'S')); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, r->riscv_ebreaku && riscv_supports_extension(target, 'U')); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, r->riscv_ebreaku && riscv_supports_extension(target, 'H')); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, r->riscv_ebreaku && riscv_supports_extension(target, 'H')); + if (dcsr != original_dcsr && + riscv_set_register(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK) + return ERROR_FAIL; + info->dcsr_ebreak_is_set = true; + return ERROR_OK; +} + +static int halt_set_dcsr_ebreak(struct target *target) +{ + RISCV_INFO(r); + RISCV013_INFO(info); + LOG_TARGET_DEBUG(target, "Halt to set DCSR.ebreak*"); + + /* Remove this hart from the halt group. This won't work on all targets + * because the debug spec allows halt groups to be hard-coded, but I + * haven't actually encountered those in the wild yet. + * + * There is a possible race condition when another hart halts, and + * this one is expected to also halt because it's supposed to be in the + * same halt group. Or when this hart is halted when that happens. + * + * A better solution might be to leave the halt groups alone, and track + * why we're halting when a halt occurs. When there are halt groups, + * that leads to extra halting if not all harts need to set dcsr.ebreak + * at the same time. It also makes for more complicated code. + * + * The perfect solution would be Quick Access, but I'm not aware of any + * hardware that implements it. + * + * We don't need a perfect solution, because we only get here when a + * hart spontaneously resets, or when it powers down and back up again. + * Those are both relatively rare. (At least I hope so. Maybe some + * design just powers each hart down for 90ms out of every 100ms) + */ + + + if (info->haltgroup_supported) { + bool supported; + if (set_group(target, &supported, 0, HALT_GROUP) != ERROR_OK) + return ERROR_FAIL; + if (!supported) + LOG_TARGET_ERROR(target, "Couldn't place hart in halt group 0. " + "Some harts may be unexpectedly halted."); + } + + int result = ERROR_OK; + + r->prepped = true; + if (riscv013_halt_go(target) != ERROR_OK || + set_dcsr_ebreak(target, false) != ERROR_OK || + riscv013_step_or_resume_current_hart(target, false) != ERROR_OK) { + result = ERROR_FAIL; + } else { + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + } + + /* Add it back to the halt group. */ + if (info->haltgroup_supported) { + bool supported; + if (set_group(target, &supported, target->smp, HALT_GROUP) != ERROR_OK) + return ERROR_FAIL; + if (!supported) + LOG_TARGET_ERROR(target, "Couldn't place hart back in halt group %d. " + "Some harts may be unexpectedly halted.", target->smp); + } + + return result; +} + /*** OpenOCD target functions. ***/ static void deinit_target(struct target *target) { - LOG_DEBUG("riscv_deinit_target()"); - riscv_info_t *info = (riscv_info_t *) target->arch_info; + LOG_TARGET_DEBUG(target, "Deinitializing target."); + struct riscv_info *info = target->arch_info; + if (!info) + return; + + riscv013_dm_free(target); + free(info->version_specific); /* TODO: free register arch_info */ info->version_specific = NULL; } -typedef enum { - HALTGROUP, - RESUMEGROUP -} grouptype_t; -static int set_group(struct target *target, bool *supported, unsigned group, grouptype_t grouptype) +static int set_group(struct target *target, bool *supported, unsigned int group, + grouptype_t grouptype) { uint32_t write_val = DM_DMCS2_HGWRITE; assert(group <= 31); write_val = set_field(write_val, DM_DMCS2_GROUP, group); - write_val = set_field(write_val, DM_DMCS2_GROUPTYPE, (grouptype == HALTGROUP) ? 0 : 1); - if (dmi_write(target, DM_DMCS2, write_val) != ERROR_OK) + write_val = set_field(write_val, DM_DMCS2_GROUPTYPE, (grouptype == HALT_GROUP) ? 0 : 1); + if (dm_write(target, DM_DMCS2, write_val) != ERROR_OK) return ERROR_FAIL; uint32_t read_val; - if (dmi_read(target, &read_val, DM_DMCS2) != ERROR_OK) + if (dm_read(target, &read_val, DM_DMCS2) != ERROR_OK) return ERROR_FAIL; - *supported = get_field(read_val, DM_DMCS2_GROUP) == group; - return ERROR_OK; -} - -static int discover_vlenb(struct target *target) -{ - RISCV_INFO(r); - riscv_reg_t vlenb; - - if (register_read_direct(target, &vlenb, GDB_REGNO_VLENB) != ERROR_OK) { - LOG_WARNING("Couldn't read vlenb for %s; vector register access won't work.", - target_name(target)); - r->vlenb = 0; - return ERROR_OK; - } - r->vlenb = vlenb; - - LOG_INFO("Vector support with vlenb=%d", r->vlenb); - + if (supported) + *supported = (get_field(read_val, DM_DMCS2_GROUP) == group); return ERROR_OK; } static int examine(struct target *target) { + /* We reset target state in case if something goes wrong during examine: + * DTM/DM scans could fail or hart may fail to halt. */ + target->state = TARGET_UNKNOWN; + target->debug_reason = DBG_REASON_UNDEFINED; + /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ + LOG_TARGET_DEBUG(target, "dbgbase=0x%x", target->dbgbase); - uint32_t dtmcontrol = dtmcontrol_scan(target, 0); - LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol); - LOG_DEBUG(" dmireset=%d", get_field(dtmcontrol, DTM_DTMCS_DMIRESET)); - LOG_DEBUG(" idle=%d", get_field(dtmcontrol, DTM_DTMCS_IDLE)); - LOG_DEBUG(" dmistat=%d", get_field(dtmcontrol, DTM_DTMCS_DMISTAT)); - LOG_DEBUG(" abits=%d", get_field(dtmcontrol, DTM_DTMCS_ABITS)); - LOG_DEBUG(" version=%d", get_field(dtmcontrol, DTM_DTMCS_VERSION)); - if (dtmcontrol == 0) { - LOG_ERROR("dtmcontrol is 0. Check JTAG connectivity/board power."); + uint32_t dtmcontrol; + if (dtmcontrol_scan(target, 0, &dtmcontrol) != ERROR_OK || dtmcontrol == 0) { + LOG_TARGET_ERROR(target, "Could not scan dtmcontrol. Check JTAG connectivity/board power."); return ERROR_FAIL; } + + LOG_TARGET_DEBUG(target, "dtmcontrol=0x%x", dtmcontrol); + LOG_DEBUG_REG(target, DTM_DTMCS, dtmcontrol); + if (get_field(dtmcontrol, DTM_DTMCS_VERSION) != 1) { - LOG_ERROR("[%s] Unsupported DTM version %d. (dtmcontrol=0x%x)", - target_name(target), get_field(dtmcontrol, DTM_DTMCS_VERSION), dtmcontrol); + LOG_TARGET_ERROR(target, "Unsupported DTM version %" PRIu32 ". (dtmcontrol=0x%" PRIx32 ")", + get_field32(dtmcontrol, DTM_DTMCS_VERSION), dtmcontrol); return ERROR_FAIL; } riscv013_info_t *info = get_info(target); - /* TODO: This won't be true if there are multiple DMs. */ + info->index = target->coreid; info->abits = get_field(dtmcontrol, DTM_DTMCS_ABITS); info->dtmcs_idle = get_field(dtmcontrol, DTM_DTMCS_IDLE); + if (!check_dbgbase_exists(target)) { + LOG_TARGET_ERROR(target, "Could not find debug module with DMI base address (dbgbase) = 0x%x", target->dbgbase); + return ERROR_FAIL; + } + /* Reset the Debug Module. */ dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; if (!dm->was_reset) { - dmi_write(target, DM_DMCONTROL, 0); - dmi_write(target, DM_DMCONTROL, DM_DMCONTROL_DMACTIVE); + dm_write(target, DM_DMCONTROL, 0); + dm_write(target, DM_DMCONTROL, DM_DMCONTROL_DMACTIVE); dm->was_reset = true; - - /* The DM gets reset, so forget any cached progbuf entries. */ - riscv013_invalidate_cached_debug_buffer(target); } + /* We're here because we're uncertain about the state of the target. That + * includes our progbuf cache. */ + riscv013_invalidate_cached_progbuf(target); - dmi_write(target, DM_DMCONTROL, DM_DMCONTROL_HARTSELLO | + dm_write(target, DM_DMCONTROL, DM_DMCONTROL_HARTSELLO | DM_DMCONTROL_HARTSELHI | DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HASEL); dm->current_hartid = HART_INDEX_UNKNOWN; uint32_t dmcontrol; - if (dmi_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK) + if (dm_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK) + return ERROR_FAIL; + /* Ensure the HART_INDEX_UNKNOWN is flushed out */ + if (dm013_select_hart(target, 0) != ERROR_OK) return ERROR_FAIL; /* Ensure the HART_INDEX_UNKNOWN is flushed out */ if (dm013_select_hart(target, 0) != ERROR_OK) return ERROR_FAIL; + if (!get_field(dmcontrol, DM_DMCONTROL_DMACTIVE)) { - LOG_ERROR("Debug Module did not become active. dmcontrol=0x%x", + LOG_TARGET_ERROR(target, "Debug Module did not become active. dmcontrol=0x%x", dmcontrol); return ERROR_FAIL; } @@ -1622,7 +1987,7 @@ static int examine(struct target *target) uint32_t dmstatus; if (dmstatus_read(target, &dmstatus, false) != ERROR_OK) return ERROR_FAIL; - LOG_DEBUG("dmstatus: 0x%08x", dmstatus); + LOG_TARGET_DEBUG(target, "dmstatus: 0x%08x", dmstatus); int dmstatus_version = get_field(dmstatus, DM_DMSTATUS_VERSION); if (dmstatus_version != 2 && dmstatus_version != 3) { /* Error was already printed out in dmstatus_read(). */ @@ -1638,10 +2003,10 @@ static int examine(struct target *target) info->hartsellen++; hartsel >>= 1; } - LOG_DEBUG("hartsellen=%d", info->hartsellen); + LOG_TARGET_DEBUG(target, "hartsellen=%d", info->hartsellen); uint32_t hartinfo; - if (dmi_read(target, &hartinfo, DM_HARTINFO) != ERROR_OK) + if (dm_read(target, &hartinfo, DM_HARTINFO) != ERROR_OK) return ERROR_FAIL; info->datasize = get_field(hartinfo, DM_HARTINFO_DATASIZE); @@ -1649,37 +2014,37 @@ static int examine(struct target *target) info->dataaddr = get_field(hartinfo, DM_HARTINFO_DATAADDR); if (!get_field(dmstatus, DM_DMSTATUS_AUTHENTICATED)) { - LOG_ERROR("Debugger is not authenticated to target Debug Module. " + LOG_TARGET_ERROR(target, "Debugger is not authenticated to target Debug Module. " "(dmstatus=0x%x). Use `riscv authdata_read` and " "`riscv authdata_write` commands to authenticate.", dmstatus); return ERROR_FAIL; } - if (dmi_read(target, &info->sbcs, DM_SBCS) != ERROR_OK) + if (dm_read(target, &info->sbcs, DM_SBCS) != ERROR_OK) return ERROR_FAIL; /* Check that abstract data registers are accessible. */ uint32_t abstractcs; - if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) + if (dm_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) return ERROR_FAIL; info->datacount = get_field(abstractcs, DM_ABSTRACTCS_DATACOUNT); info->progbufsize = get_field(abstractcs, DM_ABSTRACTCS_PROGBUFSIZE); - LOG_INFO("[%s] datacount=%d progbufsize=%d", target_name(target), + LOG_TARGET_INFO(target, "datacount=%d progbufsize=%d", info->datacount, info->progbufsize); RISCV_INFO(r); r->impebreak = get_field(dmstatus, DM_DMSTATUS_IMPEBREAK); if (!has_sufficient_progbuf(target, 2)) { - LOG_WARNING("We won't be able to execute fence instructions on this " + LOG_TARGET_WARNING(target, "We won't be able to execute fence instructions on this " "target. Memory may not always appear consistent. " "(progbufsize=%d, impebreak=%d)", info->progbufsize, r->impebreak); } if (info->progbufsize < 4 && riscv_enable_virtual) { - LOG_ERROR("set_enable_virtual is not available on this target. It " + LOG_TARGET_ERROR(target, "set_enable_virtual is not available on this target. It " "requires a program buffer size of at least 4. (progbufsize=%d) " "Use `riscv set_enable_virtual off` to continue." , info->progbufsize); @@ -1699,15 +2064,15 @@ static int examine(struct target *target) dm->hart_count = i + 1; if (get_field(s, DM_DMSTATUS_ANYHAVERESET)) - dmi_write(target, DM_DMCONTROL, + dm_write(target, DM_DMCONTROL, set_dmcontrol_hartsel(DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET, i)); } - LOG_DEBUG("Detected %d harts.", dm->hart_count); + LOG_TARGET_DEBUG(target, "Detected %d harts.", dm->hart_count); } - if (dm->hart_count == 0) { - LOG_ERROR("No harts found!"); + if (dm->hart_count <= 0) { + LOG_TARGET_ERROR(target, "No harts found!"); return ERROR_FAIL; } @@ -1717,22 +2082,28 @@ static int examine(struct target *target) if (dm013_select_hart(target, info->index) != ERROR_OK) return ERROR_FAIL; - bool halted = riscv_is_halted(target); - if (!halted) { + enum riscv_hart_state state_at_examine_start; + if (riscv_get_hart_state(target, &state_at_examine_start) != ERROR_OK) + return ERROR_FAIL; + const bool hart_halted_at_examine_start = state_at_examine_start == RISCV_STATE_HALTED; + if (!hart_halted_at_examine_start) { r->prepped = true; if (riscv013_halt_go(target) != ERROR_OK) { - LOG_TARGET_ERROR(target, "Fatal: Hart %d failed to halt during examine()", - info->index); + LOG_TARGET_ERROR(target, "Fatal: Hart %d failed to halt during %s", + info->index, __func__); return ERROR_FAIL; } target->state = TARGET_HALTED; } + target->state = TARGET_HALTED; + target->debug_reason = hart_halted_at_examine_start ? DBG_REASON_UNDEFINED : DBG_REASON_DBGRQ; + /* Without knowing anything else we can at least mess with the - * program buffer. */ - r->debug_buffer_size = info->progbufsize; + * program buffer. */ + r->progbuf_size = info->progbufsize; - int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64); + int result = register_read_abstract_with_size(target, NULL, GDB_REGNO_S0, 64); if (result == ERROR_OK) r->xlen = 64; else @@ -1741,11 +2112,11 @@ static int examine(struct target *target) /* Save s0 and s1. The register cache hasn't be initialized yet so we * need to take care of this manually. */ uint64_t s0, s1; - if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) { + if (register_read_abstract(target, &s0, GDB_REGNO_S0) != ERROR_OK) { LOG_TARGET_ERROR(target, "Fatal: Failed to read s0."); return ERROR_FAIL; } - if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK) { + if (register_read_abstract(target, &s1, GDB_REGNO_S1) != ERROR_OK) { LOG_TARGET_ERROR(target, "Fatal: Failed to read s1."); return ERROR_FAIL; } @@ -1755,14 +2126,29 @@ static int examine(struct target *target) return ERROR_FAIL; } - if (riscv_supports_extension(target, 'V')) { - if (discover_vlenb(target) != ERROR_OK) - return ERROR_FAIL; + uint64_t value; + if (register_read_direct(target, &value, GDB_REGNO_VLENB) != ERROR_OK) { + if (riscv_supports_extension(target, 'V')) + LOG_TARGET_WARNING(target, "Couldn't read vlenb; vector register access won't work."); + r->vlenb = 0; + } else { + r->vlenb = value; + LOG_TARGET_INFO(target, "Vector support with vlenb=%d", r->vlenb); } - /* Now init registers based on what we discovered. */ - if (riscv_init_registers(target) != ERROR_OK) - return ERROR_FAIL; + if (register_read_direct(target, &value, GDB_REGNO_MTOPI) == ERROR_OK) { + r->mtopi_readable = true; + + if (register_read_direct(target, &value, GDB_REGNO_MTOPEI) == ERROR_OK) { + LOG_TARGET_INFO(target, "S?aia detected with IMSIC"); + r->mtopei_readable = true; + } else { + r->mtopei_readable = false; + LOG_TARGET_INFO(target, "S?aia detected without IMSIC"); + } + } else { + r->mtopi_readable = false; + } /* Display this as early as possible to help people who are using * really slow simulators. */ @@ -1778,26 +2164,37 @@ static int examine(struct target *target) return ERROR_FAIL; } - if (!halted) + /* Now init registers based on what we discovered. */ + if (riscv_init_registers(target) != ERROR_OK) + return ERROR_FAIL; + + if (set_dcsr_ebreak(target, false) != ERROR_OK) + return ERROR_FAIL; + + if (state_at_examine_start == RISCV_STATE_RUNNING) { riscv013_step_or_resume_current_hart(target, false); + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + } else if (state_at_examine_start == RISCV_STATE_HALTED) { + target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_UNDEFINED; + } if (target->smp) { - bool haltgroup_supported; - if (set_group(target, &haltgroup_supported, target->smp, HALTGROUP) != ERROR_OK) + if (set_group(target, &info->haltgroup_supported, target->smp, HALT_GROUP) != ERROR_OK) return ERROR_FAIL; - if (haltgroup_supported) - LOG_INFO("Core %d made part of halt group %d.", target->coreid, + if (info->haltgroup_supported) + LOG_TARGET_INFO(target, "Core %d made part of halt group %d.", info->index, target->smp); else - LOG_INFO("Core %d could not be made part of halt group %d.", - target->coreid, target->smp); + LOG_TARGET_INFO(target, "Core %d could not be made part of halt group %d.", + info->index, target->smp); } /* Some regression suites rely on seeing 'Examined RISC-V core' to know * when they can connect with gdb/telnet. * We will need to update those suites if we want to change that text. */ - LOG_TARGET_INFO(target, "Examined RISC-V core; found %d harts", - riscv_count_harts(target)); + LOG_TARGET_INFO(target, "Examined RISC-V core"); LOG_TARGET_INFO(target, " XLEN=%d, misa=0x%" PRIx64, r->xlen, r->misa); return ERROR_OK; } @@ -1805,20 +2202,20 @@ static int examine(struct target *target) static int riscv013_authdata_read(struct target *target, uint32_t *value, unsigned int index) { if (index > 0) { - LOG_ERROR("Spec 0.13 only has a single authdata register."); + LOG_TARGET_ERROR(target, "Spec 0.13 only has a single authdata register."); return ERROR_FAIL; } if (wait_for_authbusy(target, NULL) != ERROR_OK) return ERROR_FAIL; - return dmi_read(target, value, DM_AUTHDATA); + return dm_read(target, value, DM_AUTHDATA); } static int riscv013_authdata_write(struct target *target, uint32_t value, unsigned int index) { if (index > 0) { - LOG_ERROR("Spec 0.13 only has a single authdata register."); + LOG_TARGET_ERROR(target, "Spec 0.13 only has a single authdata register."); return ERROR_FAIL; } @@ -1826,14 +2223,14 @@ static int riscv013_authdata_write(struct target *target, uint32_t value, unsign if (wait_for_authbusy(target, &before) != ERROR_OK) return ERROR_FAIL; - dmi_write(target, DM_AUTHDATA, value); + dm_write(target, DM_AUTHDATA, value); if (wait_for_authbusy(target, &after) != ERROR_OK) return ERROR_FAIL; if (!get_field(before, DM_DMSTATUS_AUTHENTICATED) && get_field(after, DM_DMSTATUS_AUTHENTICATED)) { - LOG_INFO("authdata_write resulted in successful authentication"); + LOG_TARGET_INFO(target, "authdata_write resulted in successful authentication"); int result = ERROR_OK; dm013_info_t *dm = get_dm(target); if (!dm) @@ -1849,13 +2246,6 @@ static int riscv013_authdata_write(struct target *target, uint32_t value, unsign return ERROR_OK; } -static int riscv013_hart_count(struct target *target) -{ - dm013_info_t *dm = get_dm(target); - assert(dm); - return dm->hart_count; -} - /* Try to find out the widest memory access size depending on the selected memory access methods. */ static unsigned riscv013_data_bits(struct target *target) { @@ -1888,11 +2278,11 @@ static unsigned riscv013_data_bits(struct target *target) /* No further mem access method to try. */ break; } - LOG_ERROR("Unable to determine supported data bits on this target. Assuming 32 bits."); + LOG_TARGET_ERROR(target, "Unable to determine supported data bits on this target. Assuming 32 bits."); return 32; } -COMMAND_HELPER(riscv013_print_info, struct target *target) +static COMMAND_HELPER(riscv013_print_info, struct target *target) { RISCV013_INFO(info); @@ -1926,81 +2316,109 @@ COMMAND_HELPER(riscv013_print_info, struct target *target) return 0; } -static int prep_for_vector_access(struct target *target, uint64_t *vtype, - uint64_t *vl, unsigned *debug_vl) +static int try_set_vsew(struct target *target, unsigned int *debug_vsew) { RISCV_INFO(r); - /* TODO: this continuous save/restore is terrible for performance. */ - /* Write vtype and vl. */ - unsigned encoded_vsew; - switch (riscv_xlen(target)) { - case 32: - encoded_vsew = 2; - break; - case 64: - encoded_vsew = 3; - break; - default: - LOG_ERROR("Unsupported xlen: %d", riscv_xlen(target)); + unsigned int encoded_vsew = + (riscv_xlen(target) == 64 && r->vsew64_supported != YNM_NO) ? 3 : 2; + + /* Set standard element width to match XLEN, for vmv instruction to move + * the least significant bits into a GPR. + */ + if (riscv_write_register(target, GDB_REGNO_VTYPE, encoded_vsew << 3) != ERROR_OK) + return ERROR_FAIL; + + if (encoded_vsew == 3 && r->vsew64_supported == YNM_MAYBE) { + /* Check that it's supported. */ + riscv_reg_t vtype; + + if (riscv_get_register(target, &vtype, GDB_REGNO_VTYPE) != ERROR_OK) return ERROR_FAIL; + if (vtype >> (riscv_xlen(target) - 1)) { + r->vsew64_supported = YNM_NO; + /* Try again. */ + return try_set_vsew(target, debug_vsew); + } + r->vsew64_supported = YNM_YES; } + *debug_vsew = encoded_vsew == 3 ? 64 : 32; + return ERROR_OK; +} - /* Save vtype and vl. */ - if (register_read_direct(target, vtype, GDB_REGNO_VTYPE) != ERROR_OK) +static int prep_for_vector_access(struct target *target, + riscv_reg_t *orig_mstatus, riscv_reg_t *orig_vtype, riscv_reg_t *orig_vl, + unsigned int *debug_vl, unsigned int *debug_vsew) +{ + assert(orig_mstatus); + assert(orig_vtype); + assert(orig_vl); + assert(debug_vl); + assert(debug_vsew); + + RISCV_INFO(r); + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, + "Unable to access vector register: target not halted"); return ERROR_FAIL; - if (register_read_direct(target, vl, GDB_REGNO_VL) != ERROR_OK) + } + if (prep_for_register_access(target, orig_mstatus, GDB_REGNO_VL) != ERROR_OK) return ERROR_FAIL; - if (register_write_direct(target, GDB_REGNO_VTYPE, encoded_vsew << 3) != ERROR_OK) + /* Save vtype and vl. */ + if (riscv_get_register(target, orig_vtype, GDB_REGNO_VTYPE) != ERROR_OK) return ERROR_FAIL; - *debug_vl = DIV_ROUND_UP(r->vlenb * 8, riscv_xlen(target)); - if (register_write_direct(target, GDB_REGNO_VL, *debug_vl) != ERROR_OK) + if (riscv_get_register(target, orig_vl, GDB_REGNO_VL) != ERROR_OK) return ERROR_FAIL; - return ERROR_OK; + if (try_set_vsew(target, debug_vsew) != ERROR_OK) + return ERROR_FAIL; + /* Set the number of elements to be updated with results from a vector + * instruction, for the vslide1down instruction. + * Set it so the entire V register is updated. */ + *debug_vl = DIV_ROUND_UP(r->vlenb * 8, *debug_vsew); + return riscv_write_register(target, GDB_REGNO_VL, *debug_vl); } -static int cleanup_after_vector_access(struct target *target, uint64_t vtype, - uint64_t vl) +static int cleanup_after_vector_access(struct target *target, + riscv_reg_t mstatus, riscv_reg_t vtype, riscv_reg_t vl) { /* Restore vtype and vl. */ - if (register_write_direct(target, GDB_REGNO_VTYPE, vtype) != ERROR_OK) + if (riscv_write_register(target, GDB_REGNO_VTYPE, vtype) != ERROR_OK) return ERROR_FAIL; - if (register_write_direct(target, GDB_REGNO_VL, vl) != ERROR_OK) + if (riscv_write_register(target, GDB_REGNO_VL, vl) != ERROR_OK) return ERROR_FAIL; - return ERROR_OK; + return cleanup_after_register_access(target, mstatus, GDB_REGNO_VL); } static int riscv013_get_register_buf(struct target *target, - uint8_t *value, int regno) + uint8_t *value, enum gdb_regno regno) { assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31); if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) - return ERROR_FAIL; + riscv_reg_t mstatus, vtype, vl; + unsigned int debug_vl, debug_vsew; - uint64_t mstatus; - if (prep_for_register_access(target, &mstatus, regno) != ERROR_OK) + if (prep_for_vector_access(target, &mstatus, &vtype, &vl, + &debug_vl, &debug_vsew) != ERROR_OK) return ERROR_FAIL; - uint64_t vtype, vl; - unsigned debug_vl; - if (prep_for_vector_access(target, &vtype, &vl, &debug_vl) != ERROR_OK) + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; - unsigned vnum = regno - GDB_REGNO_V0; - unsigned xlen = riscv_xlen(target); - - struct riscv_program program; - riscv_program_init(&program, target); - riscv_program_insert(&program, vmv_x_s(S0, vnum)); - riscv_program_insert(&program, vslide1down_vx(vnum, vnum, S0, true)); + unsigned int vnum = regno - GDB_REGNO_V0; int result = ERROR_OK; - for (unsigned i = 0; i < debug_vl; i++) { + for (unsigned int i = 0; i < debug_vl; i++) { + /* Can't reuse the same program because riscv_program_exec() adds + * ebreak to the end every time. */ + struct riscv_program program; + riscv_program_init(&program, target); + riscv_program_insert(&program, vmv_x_s(S0, vnum)); + riscv_program_insert(&program, vslide1down_vx(vnum, vnum, S0, true)); + /* Executing the program might result in an exception if there is some * issue with the vector implementation/instructions we're using. If that * happens, attempt to restore as usual. We may have clobbered the @@ -2009,64 +2427,58 @@ static int riscv013_get_register_buf(struct target *target, * so messed up that attempting to restore isn't going to help. */ result = riscv_program_exec(&program, target); if (result == ERROR_OK) { - uint64_t v; + riscv_reg_t v; if (register_read_direct(target, &v, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; - buf_set_u64(value, xlen * i, xlen, v); + buf_set_u64(value, debug_vsew * i, debug_vsew, v); } else { + LOG_TARGET_ERROR(target, + "Failed to execute vmv/vslide1down while reading %s", + gdb_regno_name(target, regno)); break; } } - if (cleanup_after_vector_access(target, vtype, vl) != ERROR_OK) - return ERROR_FAIL; - - if (cleanup_after_register_access(target, mstatus, regno) != ERROR_OK) + if (cleanup_after_vector_access(target, mstatus, vtype, vl) != ERROR_OK) return ERROR_FAIL; return result; } static int riscv013_set_register_buf(struct target *target, - int regno, const uint8_t *value) + enum gdb_regno regno, const uint8_t *value) { assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31); if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) - return ERROR_FAIL; + riscv_reg_t mstatus, vtype, vl; + unsigned int debug_vl, debug_vsew; - uint64_t mstatus; - if (prep_for_register_access(target, &mstatus, regno) != ERROR_OK) + if (prep_for_vector_access(target, &mstatus, &vtype, &vl, + &debug_vl, &debug_vsew) != ERROR_OK) return ERROR_FAIL; - uint64_t vtype, vl; - unsigned debug_vl; - if (prep_for_vector_access(target, &vtype, &vl, &debug_vl) != ERROR_OK) + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; - unsigned vnum = regno - GDB_REGNO_V0; - unsigned xlen = riscv_xlen(target); + unsigned int vnum = regno - GDB_REGNO_V0; struct riscv_program program; riscv_program_init(&program, target); riscv_program_insert(&program, vslide1down_vx(vnum, vnum, S0, true)); int result = ERROR_OK; - for (unsigned i = 0; i < debug_vl; i++) { + for (unsigned int i = 0; i < debug_vl; i++) { if (register_write_direct(target, GDB_REGNO_S0, - buf_get_u64(value, xlen * i, xlen)) != ERROR_OK) + buf_get_u64(value, debug_vsew * i, debug_vsew)) != ERROR_OK) return ERROR_FAIL; result = riscv_program_exec(&program, target); if (result != ERROR_OK) break; } - if (cleanup_after_vector_access(target, vtype, vl) != ERROR_OK) - return ERROR_FAIL; - - if (cleanup_after_register_access(target, mstatus, regno) != ERROR_OK) + if (cleanup_after_vector_access(target, mstatus, vtype, vl) != ERROR_OK) return ERROR_FAIL; return result; @@ -2097,13 +2509,14 @@ static int sb_write_address(struct target *target, target_addr_t address, unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); /* There currently is no support for >64-bit addresses in OpenOCD. */ if (sbasize > 96) - dmi_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS3, 0, false, false); + dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS3, 0, false, false); if (sbasize > 64) - dmi_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS2, 0, false, false); + dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS2, 0, false, false); if (sbasize > 32) - dmi_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS1, address >> 32, false, false); - return dmi_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS0, address, - false, ensure_success); + dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS1, + (uint32_t)(address >> 32), false, false); + return dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS0, + (uint32_t)address, false, ensure_success); } static int batch_run(const struct target *target, struct riscv_batch *batch) @@ -2148,12 +2561,12 @@ static int sample_memory_bus_v1(struct target *target, RISCV013_INFO(info); unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); if (sbasize > 64) { - LOG_ERROR("Memory sampling is only implemented for sbasize <= 64."); + LOG_TARGET_ERROR(target, "Memory sampling is only implemented for sbasize <= 64."); return ERROR_NOT_IMPLEMENTED; } if (get_field(info->sbcs, DM_SBCS_SBVERSION) != 1) { - LOG_ERROR("Memory sampling is only implemented for SBA version 1."); + LOG_TARGET_ERROR(target, "Memory sampling is only implemented for SBA version 1."); return ERROR_NOT_IMPLEMENTED; } @@ -2191,7 +2604,7 @@ static int sample_memory_bus_v1(struct target *target, for (unsigned int i = 0; i < ARRAY_SIZE(config->bucket); i++) { if (config->bucket[i].enabled) { if (!sba_supports_access(target, config->bucket[i].size_bytes)) { - LOG_ERROR("Hardware does not support SBA access for %d-byte memory sampling.", + LOG_TARGET_ERROR(target, "Hardware does not support SBA access for %d-byte memory sampling.", config->bucket[i].size_bytes); return ERROR_NOT_IMPLEMENTED; } @@ -2201,7 +2614,7 @@ static int sample_memory_bus_v1(struct target *target, sbcs_write |= DM_SBCS_SBREADONDATA; sbcs_write |= sb_sbaccess(config->bucket[i].size_bytes); if (!sbcs_valid || sbcs_write != sbcs) { - riscv_batch_add_dmi_write(batch, DM_SBCS, sbcs_write); + riscv_batch_add_dm_write(batch, DM_SBCS, sbcs_write, true); sbcs = sbcs_write; sbcs_valid = true; } @@ -2210,18 +2623,18 @@ static int sample_memory_bus_v1(struct target *target, (!sbaddress1_valid || sbaddress1 != config->bucket[i].address >> 32)) { sbaddress1 = config->bucket[i].address >> 32; - riscv_batch_add_dmi_write(batch, DM_SBADDRESS1, sbaddress1); + riscv_batch_add_dm_write(batch, DM_SBADDRESS1, sbaddress1, true); sbaddress1_valid = true; } if (!sbaddress0_valid || sbaddress0 != (config->bucket[i].address & 0xffffffff)) { sbaddress0 = config->bucket[i].address; - riscv_batch_add_dmi_write(batch, DM_SBADDRESS0, sbaddress0); + riscv_batch_add_dm_write(batch, DM_SBADDRESS0, sbaddress0, true); sbaddress0_valid = true; } if (config->bucket[i].size_bytes > 4) - riscv_batch_add_dmi_read(batch, DM_SBDATA1); - riscv_batch_add_dmi_read(batch, DM_SBDATA0); + riscv_batch_add_dm_read(batch, DM_SBDATA1); + riscv_batch_add_dm_read(batch, DM_SBDATA0); result_bytes += 1 + config->bucket[i].size_bytes; } } @@ -2232,37 +2645,48 @@ static int sample_memory_bus_v1(struct target *target, break; } - size_t sbcs_key = riscv_batch_add_dmi_read(batch, DM_SBCS); + size_t sbcs_read_index = riscv_batch_add_dm_read(batch, DM_SBCS); int result = batch_run(target, batch); - if (result != ERROR_OK) + if (result != ERROR_OK) { + riscv_batch_free(batch); return result; + } + + /* Discard the batch when we encounter a busy state on the DMI level. + * It's too much hassle to try to recover partial data. We'll try again + * with a larger DMI delay. */ + unsigned int sbcs_read_op = riscv_batch_get_dmi_read_op(batch, sbcs_read_index); + if (sbcs_read_op == DTM_DMI_OP_BUSY) { + increase_dmi_busy_delay(target); + continue; + } - uint32_t sbcs_read = riscv_batch_get_dmi_read_data(batch, sbcs_key); + uint32_t sbcs_read = riscv_batch_get_dmi_read_data(batch, sbcs_read_index); if (get_field(sbcs_read, DM_SBCS_SBBUSYERROR)) { - /* Discard this batch (too much hassle to try to recover partial - * data) and try again with a larger delay. */ + /* Discard this batch when we encounter "busy error" state on the System Bus level. + * We'll try next time with a larger System Bus read delay. */ info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1; - dmi_write(target, DM_SBCS, sbcs_read | DM_SBCS_SBBUSYERROR | DM_SBCS_SBERROR); + dm_write(target, DM_SBCS, sbcs_read | DM_SBCS_SBBUSYERROR | DM_SBCS_SBERROR); riscv_batch_free(batch); continue; } if (get_field(sbcs_read, DM_SBCS_SBERROR)) { /* The memory we're sampling was unreadable, somehow. Give up. */ - dmi_write(target, DM_SBCS, DM_SBCS_SBBUSYERROR | DM_SBCS_SBERROR); + dm_write(target, DM_SBCS, DM_SBCS_SBBUSYERROR | DM_SBCS_SBERROR); riscv_batch_free(batch); return ERROR_FAIL; } - unsigned int read = 0; + unsigned int read_count = 0; for (unsigned int n = 0; n < repeat; n++) { for (unsigned int i = 0; i < ARRAY_SIZE(config->bucket); i++) { if (config->bucket[i].enabled) { assert(i < RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE); uint64_t value = 0; if (config->bucket[i].size_bytes > 4) - value = ((uint64_t)riscv_batch_get_dmi_read_data(batch, read++)) << 32; - value |= riscv_batch_get_dmi_read_data(batch, read++); + value = ((uint64_t)riscv_batch_get_dmi_read_data(batch, read_count++)) << 32; + value |= riscv_batch_get_dmi_read_data(batch, read_count++); buf->buf[buf->used] = i; buf_set_u64(buf->buf + buf->used + 1, 0, config->bucket[i].size_bytes * 8, value); @@ -2288,43 +2712,108 @@ static int sample_memory(struct target *target, return sample_memory_bus_v1(target, buf, config, until_ms); } -static int init_target(struct command_context *cmd_ctx, - struct target *target) +static int riscv013_get_hart_state(struct target *target, enum riscv_hart_state *state) { - LOG_DEBUG("init"); - RISCV_INFO(generic_info); + RISCV013_INFO(info); + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; - generic_info->get_register = &riscv013_get_register; - generic_info->set_register = &riscv013_set_register; - generic_info->get_register_buf = &riscv013_get_register_buf; - generic_info->set_register_buf = &riscv013_set_register_buf; - generic_info->select_target = &dm013_select_target; - generic_info->is_halted = &riscv013_is_halted; - generic_info->resume_go = &riscv013_resume_go; - generic_info->step_current_hart = &riscv013_step_current_hart; - generic_info->on_halt = &riscv013_on_halt; - generic_info->resume_prep = &riscv013_resume_prep; - generic_info->halt_prep = &riscv013_halt_prep; - generic_info->halt_go = &riscv013_halt_go; - generic_info->on_step = &riscv013_on_step; - generic_info->halt_reason = &riscv013_halt_reason; - generic_info->read_debug_buffer = &riscv013_read_debug_buffer; - generic_info->write_debug_buffer = &riscv013_write_debug_buffer; - generic_info->execute_debug_buffer = &riscv013_execute_debug_buffer; - generic_info->invalidate_cached_debug_buffer = &riscv013_invalidate_cached_debug_buffer; - generic_info->fill_dmi_write_u64 = &riscv013_fill_dmi_write_u64; - generic_info->fill_dmi_read_u64 = &riscv013_fill_dmi_read_u64; - generic_info->fill_dmi_nop_u64 = &riscv013_fill_dmi_nop_u64; - generic_info->dmi_write_u64_bits = &riscv013_dmi_write_u64_bits; + uint32_t dmstatus; + if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) + return ERROR_FAIL; + if (get_field(dmstatus, DM_DMSTATUS_ANYHAVERESET)) { + LOG_TARGET_INFO(target, "Hart unexpectedly reset!"); + info->dcsr_ebreak_is_set = false; + /* TODO: Can we make this more obvious to eg. a gdb user? */ + uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | + DM_DMCONTROL_ACKHAVERESET; + dmcontrol = set_dmcontrol_hartsel(dmcontrol, info->index); + /* If we had been halted when we reset, request another halt. If we + * ended up running out of reset, then the user will (hopefully) get a + * message that a reset happened, that the target is running, and then + * that it is halted again once the request goes through. + */ + if (target->state == TARGET_HALTED) + dmcontrol |= DM_DMCONTROL_HALTREQ; + dm_write(target, DM_DMCONTROL, dmcontrol); + } + if (get_field(dmstatus, DM_DMSTATUS_ALLNONEXISTENT)) { + *state = RISCV_STATE_NON_EXISTENT; + return ERROR_OK; + } + if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) { + *state = RISCV_STATE_UNAVAILABLE; + return ERROR_OK; + } + if (get_field(dmstatus, DM_DMSTATUS_ALLHALTED)) { + *state = RISCV_STATE_HALTED; + return ERROR_OK; + } + if (get_field(dmstatus, DM_DMSTATUS_ALLRUNNING)) { + *state = RISCV_STATE_RUNNING; + return ERROR_OK; + } + LOG_TARGET_ERROR(target, "Couldn't determine state. dmstatus=0x%x", dmstatus); + return ERROR_FAIL; +} + +static int handle_became_unavailable(struct target *target, + enum riscv_hart_state previous_riscv_state) +{ + RISCV013_INFO(info); + info->dcsr_ebreak_is_set = false; + return ERROR_OK; +} + +static int tick(struct target *target) +{ + RISCV013_INFO(info); + if (!info->dcsr_ebreak_is_set && + target->state == TARGET_RUNNING && + target_was_examined(target)) + return halt_set_dcsr_ebreak(target); + return ERROR_OK; +} + +static int init_target(struct command_context *cmd_ctx, + struct target *target) +{ + LOG_TARGET_DEBUG(target, "Init."); + RISCV_INFO(generic_info); + + generic_info->get_register = &riscv013_get_register; + generic_info->set_register = &riscv013_set_register; + generic_info->get_register_buf = &riscv013_get_register_buf; + generic_info->set_register_buf = &riscv013_set_register_buf; + generic_info->select_target = &dm013_select_target; + generic_info->get_hart_state = &riscv013_get_hart_state; + generic_info->resume_go = &riscv013_resume_go; + generic_info->step_current_hart = &riscv013_step_current_hart; + generic_info->resume_prep = &riscv013_resume_prep; + generic_info->halt_prep = &riscv013_halt_prep; + generic_info->halt_go = &riscv013_halt_go; + generic_info->on_step = &riscv013_on_step; + generic_info->halt_reason = &riscv013_halt_reason; + generic_info->read_progbuf = &riscv013_read_progbuf; + generic_info->write_progbuf = &riscv013_write_progbuf; + generic_info->execute_progbuf = &riscv013_execute_progbuf; + generic_info->invalidate_cached_progbuf = &riscv013_invalidate_cached_progbuf; + generic_info->fill_dm_write = &riscv013_fill_dm_write; + generic_info->fill_dm_read = &riscv013_fill_dm_read; + generic_info->fill_dm_nop = &riscv013_fill_dm_nop; + generic_info->get_dmi_scan_length = &riscv013_get_dmi_scan_length; generic_info->authdata_read = &riscv013_authdata_read; generic_info->authdata_write = &riscv013_authdata_write; generic_info->dmi_read = &dmi_read; generic_info->dmi_write = &dmi_write; + generic_info->get_dmi_address = &riscv013_get_dmi_address; generic_info->read_memory = read_memory; - generic_info->test_sba_config_reg = &riscv013_test_sba_config_reg; - generic_info->hart_count = &riscv013_hart_count; generic_info->data_bits = &riscv013_data_bits; generic_info->print_info = &riscv013_print_info; + + generic_info->handle_became_unavailable = &handle_became_unavailable; + generic_info->tick = &tick; + if (!generic_info->version_specific) { generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); if (!generic_info->version_specific) @@ -2358,129 +2847,98 @@ static int init_target(struct command_context *cmd_ctx, static int assert_reset(struct target *target) { RISCV013_INFO(info); + int result; select_dmi(target); - uint32_t control_base = set_field(0, DM_DMCONTROL_DMACTIVE, 1); - if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) { /* Run the user-supplied script if there is one. */ target_handle_event(target, TARGET_EVENT_RESET_ASSERT); - } else if (target->rtos) { - /* There's only one target, and OpenOCD thinks each hart is a thread. - * We must reset them all. */ - - /* TODO: Try to use hasel in dmcontrol */ - - /* Set haltreq for each hart. */ - uint32_t control = control_base; - - control = set_dmcontrol_hartsel(control_base, info->index); - control = set_field(control, DM_DMCONTROL_HALTREQ, - target->reset_halt ? 1 : 0); - dmi_write(target, DM_DMCONTROL, control); - - /* Assert ndmreset */ - control = set_field(control, DM_DMCONTROL_NDMRESET, 1); - dmi_write(target, DM_DMCONTROL, control); - } else { - /* Reset just this hart. */ - uint32_t control = set_dmcontrol_hartsel(control_base, info->index); + uint32_t control = set_field(0, DM_DMCONTROL_DMACTIVE, 1); + control = set_dmcontrol_hartsel(control, info->index); control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); control = set_field(control, DM_DMCONTROL_NDMRESET, 1); - dmi_write(target, DM_DMCONTROL, control); + result = dm_write(target, DM_DMCONTROL, control); + if (result != ERROR_OK) + return result; } target->state = TARGET_RESET; - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - /* The DM might have gotten reset if OpenOCD called us in some reset that * involves SRST being toggled. So clear our cache which may be out of * date. */ - riscv013_invalidate_cached_debug_buffer(target); - - return ERROR_OK; + return riscv013_invalidate_cached_progbuf(target); } static int deassert_reset(struct target *target) { RISCV013_INFO(info); - select_dmi(target); + int result; + select_dmi(target); /* Clear the reset, but make sure haltreq is still set */ uint32_t control = 0; - control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); control = set_field(control, DM_DMCONTROL_DMACTIVE, 1); - dmi_write(target, DM_DMCONTROL, set_dmcontrol_hartsel(control, info->index)); + control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); + control = set_dmcontrol_hartsel(control, info->index); + result = dm_write(target, DM_DMCONTROL, control); + if (result != ERROR_OK) + return result; uint32_t dmstatus; - int dmi_busy_delay = info->dmi_busy_delay; + const int orig_dmi_busy_delay = info->dmi_busy_delay; time_t start = time(NULL); - - for (unsigned int i = 0; i < riscv_count_harts(target); ++i) { - unsigned int index = i; - if (target->rtos) { - if (index != info->index) - continue; - dmi_write(target, DM_DMCONTROL, - set_dmcontrol_hartsel(control, index)); - } else { - index = info->index; - } - - LOG_DEBUG("Waiting for hart %d to come out of reset.", index); - while (1) { - int result = dmstatus_read_timeout(target, &dmstatus, true, + LOG_TARGET_DEBUG(target, "Waiting for hart to come out of reset."); + do { + result = dmstatus_read_timeout(target, &dmstatus, true, + riscv_reset_timeout_sec); + if (result == ERROR_TIMEOUT_REACHED) + LOG_TARGET_ERROR(target, "Hart didn't complete a DMI read coming " + "out of reset in %ds; Increase the timeout with riscv " + "set_reset_timeout_sec.", riscv_reset_timeout_sec); - if (result == ERROR_TIMEOUT_REACHED) - LOG_ERROR("Hart %d didn't complete a DMI read coming out of " - "reset in %ds; Increase the timeout with riscv " - "set_reset_timeout_sec.", - index, riscv_reset_timeout_sec); - if (result != ERROR_OK) - return result; - /* Certain debug modules, like the one in GD32VF103 - * MCUs, violate the specification's requirement that - * each hart is in "exactly one of four states" and, - * during reset, report harts as both unavailable and - * halted/running. To work around this, we check for - * the absence of the unavailable state rather than - * the presence of any other state. */ - if (!get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) - break; - if (time(NULL) - start > riscv_reset_timeout_sec) { - LOG_ERROR("Hart %d didn't leave reset in %ds; " - "dmstatus=0x%x; " - "Increase the timeout with riscv set_reset_timeout_sec.", - index, riscv_reset_timeout_sec, dmstatus); - return ERROR_FAIL; - } - } - if (target->reset_halt) { - target->state = TARGET_HALTED; - target->debug_reason = DBG_REASON_DBGRQ; - } else { - target->state = TARGET_RUNNING; - target->debug_reason = DBG_REASON_NOTHALTED; - } + if (result != ERROR_OK) + return result; - if (get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)) { - /* Ack reset. */ - dmi_write(target, DM_DMCONTROL, - set_dmcontrol_hartsel(control, index) | - DM_DMCONTROL_ACKHAVERESET); + if (time(NULL) - start > riscv_reset_timeout_sec) { + LOG_TARGET_ERROR(target, "Hart didn't leave reset in %ds; " + "dmstatus=0x%x (allunavail=%s, allhavereset=%s); " + "Increase the timeout with riscv set_reset_timeout_sec.", + riscv_reset_timeout_sec, dmstatus, + get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL) ? "true" : "false", + get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET) ? "true" : "false"); + return ERROR_TIMEOUT_REACHED; } - - if (!target->rtos) - break; + /* Certain debug modules, like the one in GD32VF103 + * MCUs, violate the specification's requirement that + * each hart is in "exactly one of four states" and, + * during reset, report harts as both unavailable and + * halted/running. To work around this, we check for + * the absence of the unavailable state rather than + * the presence of any other state. */ + } while (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL) && + !get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)); + + info->dmi_busy_delay = orig_dmi_busy_delay; + + if (target->reset_halt) { + target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_DBGRQ; + } else { + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; } - info->dmi_busy_delay = dmi_busy_delay; - return ERROR_OK; + info->dcsr_ebreak_is_set = false; + + /* Ack reset and clear DM_DMCONTROL_HALTREQ if previously set */ + control = 0; + control = set_field(control, DM_DMCONTROL_DMACTIVE, 1); + control = set_field(control, DM_DMCONTROL_ACKHAVERESET, 1); + control = set_dmcontrol_hartsel(control, info->index); + return dm_write(target, DM_DMCONTROL, control); } static int execute_fence(struct target *target) @@ -2491,25 +2949,76 @@ static int execute_fence(struct target *target) /* FIXME: For non-coherent systems we need to flush the caches right * here, but there's no ISA-defined way of doing that. */ struct riscv_program program; - riscv_program_init(&program, target); - riscv_program_fence_i(&program); - riscv_program_fence(&program); - int result = riscv_program_exec(&program, target); - if (result != ERROR_OK) - LOG_TARGET_DEBUG(target, "Unable to execute pre-fence"); - return ERROR_OK; + /* program.execution_result may indicate RISCV_PROGBUF_EXEC_RESULT_EXCEPTION - + * currently, we ignore this error since most likely this is an indication + * that target does not support a fence instruction (execution of an + * unsupported instruction results in "Illegal instruction" exception on + * targets that comply with riscv-privilege spec). + * Currently, RISC-V specification does not provide us with a portable and + * less invasive way to detect if a fence is supported by the target. We may + * revise this code once the spec allows us to do this */ + if (has_sufficient_progbuf(target, 3)) { + riscv_program_init(&program, target); + riscv_program_fence_i(&program); + riscv_program_fence_rw_rw(&program); + if (riscv_program_exec(&program, target) != ERROR_OK) { + if (program.execution_result != RISCV_PROGBUF_EXEC_RESULT_EXCEPTION) { + LOG_TARGET_ERROR(target, "Unexpected error during fence execution"); + return ERROR_FAIL; + } + LOG_TARGET_DEBUG(target, "Unable to execute fence"); + } + return ERROR_OK; + } + + if (has_sufficient_progbuf(target, 2)) { + riscv_program_init(&program, target); + riscv_program_fence_i(&program); + if (riscv_program_exec(&program, target) != ERROR_OK) { + if (program.execution_result != RISCV_PROGBUF_EXEC_RESULT_EXCEPTION) { + LOG_TARGET_ERROR(target, "Unexpected error during fence.i execution"); + return ERROR_FAIL; + } + LOG_TARGET_DEBUG(target, "Unable to execute fence.i"); + } + + riscv_program_init(&program, target); + riscv_program_fence_rw_rw(&program); + if (riscv_program_exec(&program, target) != ERROR_OK) { + if (program.execution_result != RISCV_PROGBUF_EXEC_RESULT_EXCEPTION) { + LOG_TARGET_ERROR(target, "Unexpected error during fence rw, rw execution"); + return ERROR_FAIL; + } + LOG_TARGET_DEBUG(target, "Unable to execute fence rw, rw"); + } + return ERROR_OK; + } + + return ERROR_FAIL; +} + +static void log_memory_access128(target_addr_t address, uint64_t value_h, + uint64_t value_l, bool is_read) +{ + if (debug_level < LOG_LVL_DEBUG) + return; + + char fmt[80]; + sprintf(fmt, "M[0x%" TARGET_PRIxADDR "] %ss 0x%%016" PRIx64 "%%016" PRIx64, + address, is_read ? "read" : "write"); + LOG_DEBUG(fmt, value_h, value_l); } -static void log_memory_access(target_addr_t address, uint64_t value, - unsigned size_bytes, bool read) +static void log_memory_access64(target_addr_t address, uint64_t value, + unsigned int size_bytes, bool is_read) { if (debug_level < LOG_LVL_DEBUG) return; char fmt[80]; sprintf(fmt, "M[0x%" TARGET_PRIxADDR "] %ss 0x%%0%d" PRIx64, - address, read ? "read" : "write", size_bytes * 2); + address, is_read ? "read" : "write", size_bytes * 2); switch (size_bytes) { case 1: value &= 0xff; @@ -2527,23 +3036,35 @@ static void log_memory_access(target_addr_t address, uint64_t value, } LOG_DEBUG(fmt, value); } +static void log_memory_access(target_addr_t address, uint32_t *sbvalue, + unsigned int size_bytes, bool is_read) +{ + if (size_bytes == 16) { + uint64_t value_h = ((uint64_t)sbvalue[3] << 32) | sbvalue[2]; + uint64_t value_l = ((uint64_t)sbvalue[1] << 32) | sbvalue[0]; + log_memory_access128(address, value_h, value_l, is_read); + } else { + uint64_t value = ((uint64_t)sbvalue[1] << 32) | sbvalue[0]; + log_memory_access64(address, value, size_bytes, is_read); + } +} /* Read the relevant sbdata regs depending on size, and put the results into * buffer. */ static int read_memory_bus_word(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { - uint32_t value; int result; + uint32_t sbvalue[4] = { 0 }; static int sbdata[4] = { DM_SBDATA0, DM_SBDATA1, DM_SBDATA2, DM_SBDATA3 }; assert(size <= 16); for (int i = (size - 1) / 4; i >= 0; i--) { - result = dmi_op(target, &value, NULL, DMI_OP_READ, sbdata[i], 0, false, true); + result = dm_read(target, &sbvalue[i], sbdata[i]); if (result != ERROR_OK) return result; - buf_set_u32(buffer + i * 4, 0, 8 * MIN(size, 4), value); - log_memory_access(address + i * 4, value, MIN(size, 4), true); + buf_set_u32(buffer + i * 4, 0, 8 * MIN(size, 4), sbvalue[i]); } + log_memory_access(address, sbvalue, size, true); return ERROR_OK; } @@ -2554,12 +3075,12 @@ static target_addr_t sb_read_address(struct target *target) target_addr_t address = 0; uint32_t v; if (sbasize > 32) { - dmi_read(target, &v, DM_SBADDRESS1); - address |= v; + if (dm_read(target, &v, DM_SBADDRESS1) == ERROR_OK) + address |= v; address <<= 32; } - dmi_read(target, &v, DM_SBADDRESS0); - address |= v; + if (dm_read(target, &v, DM_SBADDRESS0) == ERROR_OK) + address |= v; return address; } @@ -2567,12 +3088,12 @@ static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs) { time_t start = time(NULL); while (1) { - if (dmi_read(target, sbcs, DM_SBCS) != ERROR_OK) + if (dm_read(target, sbcs, DM_SBCS) != ERROR_OK) return ERROR_FAIL; if (!get_field(*sbcs, DM_SBCS_SBBUSY)) return ERROR_OK; if (time(NULL) - start > riscv_command_timeout_sec) { - LOG_ERROR("Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). " + LOG_TARGET_ERROR(target, "Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", riscv_command_timeout_sec, *sbcs); return ERROR_FAIL; @@ -2615,11 +3136,11 @@ static int read_memory_bus_v0(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { if (size != increment) { - LOG_ERROR("sba v0 reads only support size==increment"); + LOG_TARGET_ERROR(target, "sba v0 reads only support size==increment"); return ERROR_NOT_IMPLEMENTED; } - LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" + LOG_TARGET_DEBUG(target, "System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" TARGET_PRIxADDR, size, count, address); uint8_t *t_buffer = buffer; riscv_addr_t cur_addr = address; @@ -2635,19 +3156,19 @@ static int read_memory_bus_v0(struct target *target, target_addr_t address, /* ww favorise one off reading if there is an issue */ if (count == 1) { for (uint32_t i = 0; i < count; i++) { - if (dmi_read(target, &access, DM_SBCS) != ERROR_OK) + if (dm_read(target, &access, DM_SBCS) != ERROR_OK) return ERROR_FAIL; - dmi_write(target, DM_SBADDRESS0, cur_addr); + dm_write(target, DM_SBADDRESS0, cur_addr); /* size/2 matching the bit access of the spec 0.13 */ access = set_field(access, DM_SBCS_SBACCESS, size/2); access = set_field(access, DM_SBCS_SBSINGLEREAD, 1); - LOG_DEBUG("\r\nread_memory: sab: access: 0x%08x", access); - dmi_write(target, DM_SBCS, access); + LOG_TARGET_DEBUG(target, "read_memory: sab: access: 0x%08x", access); + dm_write(target, DM_SBCS, access); /* 3) read */ uint32_t value; - if (dmi_read(target, &value, DM_SBDATA0) != ERROR_OK) + if (dm_read(target, &value, DM_SBDATA0) != ERROR_OK) return ERROR_FAIL; - LOG_DEBUG("\r\nread_memory: sab: value: 0x%08x", value); + LOG_TARGET_DEBUG(target, "read_memory: sab: value: 0x%08x", value); buf_set_u32(t_buffer, 0, 8 * size, value); t_buffer += size; cur_addr += size; @@ -2656,26 +3177,26 @@ static int read_memory_bus_v0(struct target *target, target_addr_t address, } /* has to be the same size if we want to read a block */ - LOG_DEBUG("reading block until final address 0x%" PRIx64, fin_addr); - if (dmi_read(target, &access, DM_SBCS) != ERROR_OK) + LOG_TARGET_DEBUG(target, "Reading block until final address 0x%" PRIx64, fin_addr); + if (dm_read(target, &access, DM_SBCS) != ERROR_OK) return ERROR_FAIL; /* set current address */ - dmi_write(target, DM_SBADDRESS0, cur_addr); + dm_write(target, DM_SBADDRESS0, cur_addr); /* 2) write sbaccess=2, sbsingleread,sbautoread,sbautoincrement * size/2 matching the bit access of the spec 0.13 */ access = set_field(access, DM_SBCS_SBACCESS, size/2); access = set_field(access, DM_SBCS_SBAUTOREAD, 1); access = set_field(access, DM_SBCS_SBSINGLEREAD, 1); access = set_field(access, DM_SBCS_SBAUTOINCREMENT, 1); - LOG_DEBUG("\r\naccess: 0x%08x", access); - dmi_write(target, DM_SBCS, access); + LOG_TARGET_DEBUG(target, "access: 0x%08x", access); + dm_write(target, DM_SBCS, access); while (cur_addr < fin_addr) { - LOG_DEBUG("\r\nsab:autoincrement: \r\n size: %d\tcount:%d\taddress: 0x%08" + LOG_TARGET_DEBUG(target, "sab:autoincrement:\r\n\tsize: %d\tcount:%d\taddress: 0x%08" PRIx64, size, count, cur_addr); /* read */ uint32_t value; - if (dmi_read(target, &value, DM_SBDATA0) != ERROR_OK) + if (dm_read(target, &value, DM_SBDATA0) != ERROR_OK) return ERROR_FAIL; buf_set_u32(t_buffer, 0, 8 * size, value); cur_addr += size; @@ -2683,15 +3204,15 @@ static int read_memory_bus_v0(struct target *target, target_addr_t address, /* if we are reaching last address, we must clear autoread */ if (cur_addr == fin_addr && count != 1) { - dmi_write(target, DM_SBCS, 0); - if (dmi_read(target, &value, DM_SBDATA0) != ERROR_OK) + dm_write(target, DM_SBCS, 0); + if (dm_read(target, &value, DM_SBDATA0) != ERROR_OK) return ERROR_FAIL; buf_set_u32(t_buffer, 0, 8 * size, value); } } uint32_t sbcs; - if (dmi_read(target, &sbcs, DM_SBCS) != ERROR_OK) + if (dm_read(target, &sbcs, DM_SBCS) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; @@ -2704,13 +3225,13 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { if (increment != size && increment != 0) { - LOG_ERROR("sba v1 reads only support increment of size or 0"); + LOG_TARGET_ERROR(target, "sba v1 reads only support increment of size or 0"); return ERROR_NOT_IMPLEMENTED; } RISCV013_INFO(info); target_addr_t next_address = address; - target_addr_t end_address = address + count * size; + target_addr_t end_address = address + (increment ? count : 1) * size; while (next_address < end_address) { uint32_t sbcs_write = set_field(0, DM_SBCS_SBREADONADDR, 1); @@ -2719,7 +3240,7 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, sbcs_write = set_field(sbcs_write, DM_SBCS_SBAUTOINCREMENT, 1); if (count > 1) sbcs_write = set_field(sbcs_write, DM_SBCS_SBREADONDATA, count > 1); - if (dmi_write(target, DM_SBCS, sbcs_write) != ERROR_OK) + if (dm_write(target, DM_SBCS, sbcs_write) != ERROR_OK) return ERROR_FAIL; /* This address write will trigger the first read. */ @@ -2727,32 +3248,48 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, return ERROR_FAIL; if (info->bus_master_read_delay) { + LOG_TARGET_DEBUG(target, "Waiting %d cycles for bus master read delay", + info->bus_master_read_delay); jtag_add_runtest(info->bus_master_read_delay, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { - LOG_ERROR("Failed to scan idle sequence"); + LOG_TARGET_ERROR(target, "Failed to scan idle sequence"); return ERROR_FAIL; } } - /* First value has been read, and is waiting for us to issue a DMI read - * to get it. */ + /* First read has been started. Optimistically assume that it has + * completed. */ static int sbdata[4] = {DM_SBDATA0, DM_SBDATA1, DM_SBDATA2, DM_SBDATA3}; + uint32_t sbvalue[4] = {0}; assert(size <= 16); target_addr_t next_read = address - 1; + uint32_t buffer_offset = 0; + int next_read_j = 0; for (uint32_t i = (next_address - address) / size; i < count - 1; i++) { for (int j = (size - 1) / 4; j >= 0; j--) { - uint32_t value; unsigned attempt = 0; while (1) { if (attempt++ > 100) { - LOG_ERROR("DMI keeps being busy in while reading memory just past " TARGET_ADDR_FMT, - next_read); + LOG_TARGET_ERROR(target, "DMI keeps being busy in while reading memory" + " just past " TARGET_ADDR_FMT, next_read); return ERROR_FAIL; } keep_alive(); - dmi_status_t status = dmi_scan(target, NULL, &value, - DMI_OP_READ, sbdata[j], 0, false); + dmi_status_t status = dmi_scan(target, NULL, &sbvalue[next_read_j], + DMI_OP_READ, sbdata[j], 0, false); + /* By reading from sbdata0, we have just initiated another system bus read. + * If necessary add a delay so the read can finish. */ + if (j == 0 && info->bus_master_read_delay) { + LOG_TARGET_DEBUG(target, "Waiting %d cycles for bus master read delay", + info->bus_master_read_delay); + jtag_add_runtest(info->bus_master_read_delay, TAP_IDLE); + if (jtag_execute_queue() != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to scan idle sequence"); + return ERROR_FAIL; + } + } + if (status == DMI_STATUS_BUSY) increase_dmi_busy_delay(target); else if (status == DMI_STATUS_SUCCESS) @@ -2761,24 +3298,28 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, return ERROR_FAIL; } if (next_read != address - 1) { - buf_set_u32(buffer + next_read - address, 0, 8 * MIN(size, 4), value); - log_memory_access(next_read, value, MIN(size, 4), true); + buf_set_u32(buffer + buffer_offset, 0, 8 * MIN(size, 4), sbvalue[next_read_j]); + if (next_read_j == 0) { + log_memory_access(next_read, sbvalue, size, true); + memset(sbvalue, 0, size); + } } - next_read = address + i * size + j * 4; + next_read_j = j; + next_read = address + i * increment + next_read_j * 4; + buffer_offset = i * size + next_read_j * 4; } } uint32_t sbcs_read = 0; if (count > 1) { - uint32_t value; unsigned attempt = 0; while (1) { if (attempt++ > 100) { - LOG_ERROR("DMI keeps being busy in while reading memory just past " TARGET_ADDR_FMT, - next_read); + LOG_TARGET_ERROR(target, "DMI keeps being busy in while reading memory" + " just past " TARGET_ADDR_FMT, next_read); return ERROR_FAIL; } - dmi_status_t status = dmi_scan(target, NULL, &value, DMI_OP_NOP, 0, 0, false); + dmi_status_t status = dmi_scan(target, NULL, &sbvalue[0], DMI_OP_NOP, 0, 0, false); if (status == DMI_STATUS_BUSY) increase_dmi_busy_delay(target); else if (status == DMI_STATUS_SUCCESS) @@ -2786,8 +3327,8 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, else return ERROR_FAIL; } - buf_set_u32(buffer + next_read - address, 0, 8 * MIN(size, 4), value); - log_memory_access(next_read, value, MIN(size, 4), true); + buf_set_u32(buffer + buffer_offset, 0, 8 * MIN(size, 4), sbvalue[0]); + log_memory_access(next_read, sbvalue, size, true); /* "Writes to sbcs while sbbusy is high result in undefined behavior. * A debugger must not write to sbcs until it reads sbbusy as 0." */ @@ -2795,14 +3336,14 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, return ERROR_FAIL; sbcs_write = set_field(sbcs_write, DM_SBCS_SBREADONDATA, 0); - if (dmi_write(target, DM_SBCS, sbcs_write) != ERROR_OK) + if (dm_write(target, DM_SBCS, sbcs_write) != ERROR_OK) return ERROR_FAIL; } /* Read the last word, after we disabled sbreadondata if necessary. */ if (!get_field(sbcs_read, DM_SBCS_SBERROR) && !get_field(sbcs_read, DM_SBCS_SBBUSYERROR)) { - if (read_memory_bus_word(target, address + (count - 1) * size, size, + if (read_memory_bus_word(target, address + (count - 1) * increment, size, buffer + (count - 1) * size) != ERROR_OK) return ERROR_FAIL; @@ -2811,21 +3352,37 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, } if (get_field(sbcs_read, DM_SBCS_SBBUSYERROR)) { - /* We read while the target was busy. Slow down and try again. */ - if (dmi_write(target, DM_SBCS, sbcs_read | DM_SBCS_SBBUSYERROR) != ERROR_OK) + /* We read while the target was busy. Slow down and try again. + * Clear sbbusyerror, as well as readondata or readonaddr. */ + if (dm_write(target, DM_SBCS, DM_SBCS_SBBUSYERROR) != ERROR_OK) return ERROR_FAIL; - next_address = sb_read_address(target); + + if (get_field(sbcs_read, DM_SBCS_SBERROR) == DM_SBCS_SBERROR_NONE) { + /* Read the address whose read was last completed. */ + next_address = sb_read_address(target); + + /* Read the value for the last address. It's + * sitting in the register for us, but we read it + * too early (sbbusyerror became set). */ + target_addr_t current_address = next_address - (increment ? size : 0); + if (read_memory_bus_word(target, current_address, size, + buffer + current_address - address) != ERROR_OK) + return ERROR_FAIL; + } + info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1; + LOG_TARGET_DEBUG(target, "Increasing bus_master_read_delay to %d.", + info->bus_master_read_delay); continue; } unsigned error = get_field(sbcs_read, DM_SBCS_SBERROR); - if (error == 0) { + if (error == DM_SBCS_SBERROR_NONE) { next_address = end_address; } else { /* Some error indicating the bus access failed, but not because of * something we did wrong. */ - if (dmi_write(target, DM_SBCS, DM_SBCS_SBERROR) != ERROR_OK) + if (dm_write(target, DM_SBCS, DM_SBCS_SBERROR) != ERROR_OK) return ERROR_FAIL; return ERROR_FAIL; } @@ -2834,7 +3391,7 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, return ERROR_OK; } -static void log_mem_access_result(struct target *target, bool success, int method, bool read) +static void log_mem_access_result(struct target *target, bool success, int method, bool is_read) { RISCV_INFO(r); bool warn = false; @@ -2843,7 +3400,7 @@ static void log_mem_access_result(struct target *target, bool success, int metho /* Compose the message */ snprintf(msg, 60, "%s to %s memory via %s.", success ? "Succeeded" : "Failed", - read ? "read" : "write", + is_read ? "read" : "write", (method == RISCV_MEM_ACCESS_PROGBUF) ? "program buffer" : (method == RISCV_MEM_ACCESS_SYSBUS) ? "system bus" : "abstract access"); @@ -2864,43 +3421,43 @@ static void log_mem_access_result(struct target *target, bool success, int metho } if (warn) - LOG_WARNING("%s", msg); + LOG_TARGET_WARNING(target, "%s", msg); else - LOG_DEBUG("%s", msg); + LOG_TARGET_DEBUG(target, "%s", msg); } static bool mem_should_skip_progbuf(struct target *target, target_addr_t address, - uint32_t size, bool read, char **skip_reason) + uint32_t size, bool is_read, char **skip_reason) { assert(skip_reason); if (!has_sufficient_progbuf(target, 3)) { - LOG_DEBUG("Skipping mem %s via progbuf - insufficient progbuf size.", - read ? "read" : "write"); + LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - insufficient progbuf size.", + is_read ? "read" : "write"); *skip_reason = "skipped (insufficient progbuf)"; return true; } if (target->state != TARGET_HALTED) { - LOG_DEBUG("Skipping mem %s via progbuf - target not halted.", - read ? "read" : "write"); + LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - target not halted.", + is_read ? "read" : "write"); *skip_reason = "skipped (target not halted)"; return true; } if (riscv_xlen(target) < size * 8) { - LOG_DEBUG("Skipping mem %s via progbuf - XLEN (%d) is too short for %d-bit memory access.", - read ? "read" : "write", riscv_xlen(target), size * 8); + LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - XLEN (%d) is too short for %d-bit memory access.", + is_read ? "read" : "write", riscv_xlen(target), size * 8); *skip_reason = "skipped (XLEN too short)"; return true; } if (size > 8) { - LOG_DEBUG("Skipping mem %s via progbuf - unsupported size.", - read ? "read" : "write"); + LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - unsupported size.", + is_read ? "read" : "write"); *skip_reason = "skipped (unsupported size)"; return true; } if ((sizeof(address) * 8 > riscv_xlen(target)) && (address >> riscv_xlen(target))) { - LOG_DEBUG("Skipping mem %s via progbuf - progbuf only supports %u-bit address.", - read ? "read" : "write", riscv_xlen(target)); + LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - progbuf only supports %u-bit address.", + is_read ? "read" : "write", riscv_xlen(target)); *skip_reason = "skipped (too large address)"; return true; } @@ -2909,26 +3466,26 @@ static bool mem_should_skip_progbuf(struct target *target, target_addr_t address } static bool mem_should_skip_sysbus(struct target *target, target_addr_t address, - uint32_t size, uint32_t increment, bool read, char **skip_reason) + uint32_t size, uint32_t increment, bool is_read, char **skip_reason) { assert(skip_reason); RISCV013_INFO(info); if (!sba_supports_access(target, size)) { - LOG_DEBUG("Skipping mem %s via system bus - unsupported size.", - read ? "read" : "write"); + LOG_TARGET_DEBUG(target, "Skipping mem %s via system bus - unsupported size.", + is_read ? "read" : "write"); *skip_reason = "skipped (unsupported size)"; return true; } unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); if ((sizeof(address) * 8 > sbasize) && (address >> sbasize)) { - LOG_DEBUG("Skipping mem %s via system bus - sba only supports %u-bit address.", - read ? "read" : "write", sbasize); + LOG_TARGET_DEBUG(target, "Skipping mem %s via system bus - sba only supports %u-bit address.", + is_read ? "read" : "write", sbasize); *skip_reason = "skipped (too large address)"; return true; } - if (read && increment != size && (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0 || increment != 0)) { - LOG_DEBUG("Skipping mem read via system bus - " + if (is_read && increment != size && (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0 || increment != 0)) { + LOG_TARGET_DEBUG(target, "Skipping mem read via system bus - " "sba reads only support size==increment or also size==0 for sba v1."); *skip_reason = "skipped (unsupported increment)"; return true; @@ -2938,26 +3495,26 @@ static bool mem_should_skip_sysbus(struct target *target, target_addr_t address, } static bool mem_should_skip_abstract(struct target *target, target_addr_t address, - uint32_t size, uint32_t increment, bool read, char **skip_reason) + uint32_t size, uint32_t increment, bool is_read, char **skip_reason) { assert(skip_reason); if (size > 8) { /* TODO: Add 128b support if it's ever used. Involves modifying read/write_abstract_arg() to work on two 64b values. */ - LOG_DEBUG("Skipping mem %s via abstract access - unsupported size: %d bits", - read ? "read" : "write", size * 8); + LOG_TARGET_DEBUG(target, "Skipping mem %s via abstract access - unsupported size: %d bits", + is_read ? "read" : "write", size * 8); *skip_reason = "skipped (unsupported size)"; return true; } if ((sizeof(address) * 8 > riscv_xlen(target)) && (address >> riscv_xlen(target))) { - LOG_DEBUG("Skipping mem %s via abstract access - abstract access only supports %u-bit address.", - read ? "read" : "write", riscv_xlen(target)); + LOG_TARGET_DEBUG(target, "Skipping mem %s via abstract access - abstract access only supports %u-bit address.", + is_read ? "read" : "write", riscv_xlen(target)); *skip_reason = "skipped (too large address)"; return true; } - if (read && size != increment) { - LOG_ERROR("Skipping mem read via abstract access - " + if (is_read && size != increment) { + LOG_TARGET_ERROR(target, "Skipping mem read via abstract access - " "abstract command reads only support size==increment."); *skip_reason = "skipped (unsupported increment)"; return true; @@ -2979,7 +3536,7 @@ static int read_memory_abstract(struct target *target, target_addr_t address, int result = ERROR_OK; bool use_aampostincrement = info->has_aampostincrement != YNM_NO; - LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, + LOG_TARGET_DEBUG(target, "Reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, size, address); memset(buffer, 0, count * size); @@ -3000,31 +3557,34 @@ static int read_memory_abstract(struct target *target, target_addr_t address, /* Set arg1 to the address: address + c * size */ result = write_abstract_arg(target, 1, address + c * size, riscv_xlen(target)); if (result != ERROR_OK) { - LOG_ERROR("Failed to write arg1 during read_memory_abstract()."); + LOG_TARGET_ERROR(target, "Failed to write arg1."); return result; } } /* Execute the command */ - result = execute_abstract_command(target, command); + uint32_t cmderr; + result = execute_abstract_command(target, command, &cmderr); + /* TODO: we need to modify error handling here. */ + /* NOTE: in case of timeout cmderr is set to CMDERR_NONE */ if (info->has_aampostincrement == YNM_MAYBE) { if (result == ERROR_OK) { /* Safety: double-check that the address was really auto-incremented */ riscv_reg_t new_address = read_abstract_arg(target, 1, riscv_xlen(target)); if (new_address == address + size) { - LOG_DEBUG("aampostincrement is supported on this target."); + LOG_TARGET_DEBUG(target, "aampostincrement is supported on this target."); info->has_aampostincrement = YNM_YES; } else { - LOG_WARNING("Buggy aampostincrement! Address not incremented correctly."); + LOG_TARGET_WARNING(target, "Buggy aampostincrement! Address not incremented correctly."); info->has_aampostincrement = YNM_NO; } } else { /* Try the same access but with postincrement disabled. */ command = access_memory_command(target, false, width, false, false); - result = execute_abstract_command(target, command); + result = execute_abstract_command(target, command, &cmderr); if (result == ERROR_OK) { - LOG_DEBUG("aampostincrement is not supported on this target."); + LOG_TARGET_DEBUG(target, "aampostincrement is not supported on this target."); info->has_aampostincrement = YNM_NO; } } @@ -3057,7 +3617,7 @@ static int write_memory_abstract(struct target *target, target_addr_t address, int result = ERROR_OK; bool use_aampostincrement = info->has_aampostincrement != YNM_NO; - LOG_DEBUG("writing %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, + LOG_TARGET_DEBUG(target, "writing %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, size, address); /* Convert the size (bytes) to width (bits) */ @@ -3074,7 +3634,7 @@ static int write_memory_abstract(struct target *target, target_addr_t address, riscv_reg_t value = buf_get_u64(p, 0, 8 * size); result = write_abstract_arg(target, 0, value, riscv_xlen(target)); if (result != ERROR_OK) { - LOG_ERROR("Failed to write arg0 during write_memory_abstract()."); + LOG_TARGET_ERROR(target, "Failed to write arg0."); return result; } @@ -3083,31 +3643,34 @@ static int write_memory_abstract(struct target *target, target_addr_t address, /* Set arg1 to the address: address + c * size */ result = write_abstract_arg(target, 1, address + c * size, riscv_xlen(target)); if (result != ERROR_OK) { - LOG_ERROR("Failed to write arg1 during write_memory_abstract()."); + LOG_TARGET_ERROR(target, "Failed to write arg1."); return result; } } /* Execute the command */ - result = execute_abstract_command(target, command); + uint32_t cmderr; + result = execute_abstract_command(target, command, &cmderr); + /* TODO: we need to modify error handling here. */ + /* NOTE: in case of timeout cmderr is set to CMDERR_NONE */ if (info->has_aampostincrement == YNM_MAYBE) { if (result == ERROR_OK) { /* Safety: double-check that the address was really auto-incremented */ riscv_reg_t new_address = read_abstract_arg(target, 1, riscv_xlen(target)); if (new_address == address + size) { - LOG_DEBUG("aampostincrement is supported on this target."); + LOG_TARGET_DEBUG(target, "aampostincrement is supported on this target."); info->has_aampostincrement = YNM_YES; } else { - LOG_WARNING("Buggy aampostincrement! Address not incremented correctly."); + LOG_TARGET_WARNING(target, "Buggy aampostincrement! Address not incremented correctly."); info->has_aampostincrement = YNM_NO; } } else { /* Try the same access but with postincrement disabled. */ command = access_memory_command(target, false, width, false, true); - result = execute_abstract_command(target, command); + result = execute_abstract_command(target, command, &cmderr); if (result == ERROR_OK) { - LOG_DEBUG("aampostincrement is not supported on this target."); + LOG_TARGET_DEBUG(target, "aampostincrement is not supported on this target."); info->has_aampostincrement = YNM_NO; } } @@ -3125,424 +3688,557 @@ static int write_memory_abstract(struct target *target, target_addr_t address, } /** - * Read the requested memory, taking care to execute every read exactly once, - * even if cmderr=busy is encountered. + * This function is used to start the memory-reading pipeline. + * The pipeline looks like this: + * memory -> s1 -> dm_data[0:1] -> debugger + * Prior to calling it, the program buffer should contain the appropriate + * program. + * This function sets DM_ABSTRACTAUTO_AUTOEXECDATA to trigger second stage of the + * pipeline (s1 -> dm_data[0:1]) whenever dm_data is read. */ -static int read_memory_progbuf_inner(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +static int read_memory_progbuf_inner_startup(struct target *target, + target_addr_t address, uint32_t increment, uint32_t index) { - RISCV013_INFO(info); - - int result = ERROR_OK; - - /* Write address to S0. */ - result = register_write_direct(target, GDB_REGNO_S0, address); - if (result != ERROR_OK) - return result; + /* s0 holds the next address to read from. + * s1 holds the next data value read. + * a0 is a counter in case increment is 0. + */ + if (register_write_direct(target, GDB_REGNO_S0, address + index * increment) + != ERROR_OK) + return ERROR_FAIL; - if (increment == 0 && - register_write_direct(target, GDB_REGNO_S2, 0) != ERROR_OK) + if (/*is_repeated_read*/ increment == 0 && + register_write_direct(target, GDB_REGNO_A0, index) != ERROR_OK) return ERROR_FAIL; - uint32_t command = access_register_command(target, GDB_REGNO_S1, - riscv_xlen(target), + /* AC_ACCESS_REGISTER_POSTEXEC is used to trigger first stage of the + * pipeline (memory -> s1) whenever this command is executed. + */ + const uint32_t startup_command = access_register_command(target, + GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); - if (execute_abstract_command(target, command) != ERROR_OK) + uint32_t cmderr; + if (execute_abstract_command(target, startup_command, &cmderr) != ERROR_OK) return ERROR_FAIL; + /* TODO: we need to modify error handling here. */ + /* NOTE: in case of timeout cmderr is set to CMDERR_NONE */ - /* First read has just triggered. Result is in s1. */ - if (count == 1) { - uint64_t value; - if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK) - return ERROR_FAIL; - buf_set_u64(buffer, 0, 8 * size, value); - log_memory_access(address, value, size, true); - return ERROR_OK; - } - - if (dmi_write(target, DM_ABSTRACTAUTO, - 1 << DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET) != ERROR_OK) - goto error; - /* Read garbage from dmi_data0, which triggers another execution of the - * program. Now dmi_data0 contains the first good result, and s1 the next - * memory value. */ - if (dmi_read_exec(target, NULL, DM_DATA0) != ERROR_OK) - goto error; - - /* read_addr is the next address that the hart will read from, which is the - * value in s0. */ - unsigned index = 2; - while (index < count) { - riscv_addr_t read_addr = address + index * increment; - LOG_DEBUG("i=%d, count=%d, read_addr=0x%" PRIx64, index, count, read_addr); - /* The pipeline looks like this: - * memory -> s1 -> dm_data0 -> debugger - * Right now: - * s0 contains read_addr - * s1 contains mem[read_addr-size] - * dm_data0 contains[read_addr-size*2] - */ + /* First read has just triggered. Result is in s1. + * dm_data registers contain the previous value of s1 (garbage). + */ + if (dm_write(target, DM_ABSTRACTAUTO, + set_field(0, DM_ABSTRACTAUTO_AUTOEXECDATA, 1)) != ERROR_OK) + return ERROR_FAIL; - struct riscv_batch *batch = riscv_batch_alloc(target, RISCV_BATCH_ALLOC_SIZE, - info->dmi_busy_delay + info->ac_busy_delay); - if (!batch) - return ERROR_FAIL; + /* Read garbage from dm_data0, which triggers another execution of the + * program. Now dm_data contains the first good result (from s1), + * and s1 the next memory value. + */ + if (dm_read_exec(target, NULL, DM_DATA0) != ERROR_OK) + goto clear_abstractauto_and_fail; - unsigned reads = 0; - for (unsigned j = index; j < count; j++) { - if (size > 4) - riscv_batch_add_dmi_read(batch, DM_DATA1); - riscv_batch_add_dmi_read(batch, DM_DATA0); + uint32_t abstractcs; + if (wait_for_idle(target, &abstractcs) != ERROR_OK) + goto clear_abstractauto_and_fail; - reads++; - if (riscv_batch_full(batch)) - break; - } + cmderr = get_field32(abstractcs, DM_ABSTRACTCS_CMDERR); + switch (cmderr) { + case CMDERR_NONE: + return ERROR_OK; + case CMDERR_BUSY: + LOG_TARGET_ERROR(target, "Unexpected busy error. This is probably a hardware bug."); + /* fall through */ + default: + LOG_TARGET_DEBUG(target, "error when reading memory, cmderr=0x%" PRIx32, cmderr); + riscv013_clear_abstract_error(target); + goto clear_abstractauto_and_fail; + } +clear_abstractauto_and_fail: + dm_write(target, DM_ABSTRACTAUTO, 0); + return ERROR_FAIL; +} - batch_run(target, batch); +struct memory_access_info { + uint8_t *buffer_address; + target_addr_t target_address; + uint32_t element_size; + uint32_t increment; +}; - /* Wait for the target to finish performing the last abstract command, - * and update our copy of cmderr. If we see that DMI is busy here, - * dmi_busy_delay will be incremented. */ - uint32_t abstractcs; - if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) - return ERROR_FAIL; - while (get_field(abstractcs, DM_ABSTRACTCS_BUSY)) - if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) - return ERROR_FAIL; - info->cmderr = get_field(abstractcs, DM_ABSTRACTCS_CMDERR); - - unsigned next_index; - unsigned ignore_last = 0; - switch (info->cmderr) { - case CMDERR_NONE: - LOG_DEBUG("successful (partial?) memory read"); - next_index = index + reads; - break; - case CMDERR_BUSY: - LOG_DEBUG("memory read resulted in busy response"); +/** + * This function attempts to restore the pipeline after a busy on abstract + * access. + * Target's state is as follows: + * s0 contains address + index_on_target * increment + * s1 contains mem[address + (index_on_target - 1) * increment] + * dm_data[0:1] contains mem[address + (index_on_target - 2) * increment] + */ +static int read_memory_progbuf_inner_on_ac_busy(struct target *target, + uint32_t start_index, uint32_t *elements_read, + struct memory_access_info access) +{ + increase_ac_busy_delay(target); + riscv013_clear_abstract_error(target); - increase_ac_busy_delay(target); - riscv013_clear_abstract_error(target); + if (dm_write(target, DM_ABSTRACTAUTO, 0) != ERROR_OK) + return ERROR_FAIL; - dmi_write(target, DM_ABSTRACTAUTO, 0); + /* See how far we got by reading s0/a0 */ + uint32_t index_on_target; - uint32_t dmi_data0, dmi_data1 = 0; - /* This is definitely a good version of the value that we - * attempted to read when we discovered that the target was - * busy. */ - if (dmi_read(target, &dmi_data0, DM_DATA0) != ERROR_OK) { - riscv_batch_free(batch); - goto error; - } - if (size > 4 && dmi_read(target, &dmi_data1, DM_DATA1) != ERROR_OK) { - riscv_batch_free(batch); - goto error; - } + if (/*is_repeated_read*/ access.increment == 0) { + /* s0 is constant, a0 is incremented by one each execution */ + riscv_reg_t counter; - /* See how far we got, clobbering dmi_data0. */ - if (increment == 0) { - uint64_t counter; - result = register_read_direct(target, &counter, GDB_REGNO_S2); - next_index = counter; - } else { - uint64_t next_read_addr; - result = register_read_direct(target, &next_read_addr, - GDB_REGNO_S0); - next_index = (next_read_addr - address) / increment; - } - if (result != ERROR_OK) { - riscv_batch_free(batch); - goto error; - } + if (register_read_direct(target, &counter, GDB_REGNO_A0) != ERROR_OK) + return ERROR_FAIL; + index_on_target = counter; + } else { + target_addr_t address_on_target; - uint64_t value64 = (((uint64_t)dmi_data1) << 32) | dmi_data0; - buf_set_u64(buffer + (next_index - 2) * size, 0, 8 * size, value64); - log_memory_access(address + (next_index - 2) * size, value64, size, true); + if (register_read_direct(target, &address_on_target, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + index_on_target = (address_on_target - access.target_address) / + access.increment; + } - /* Restore the command, and execute it. - * Now DM_DATA0 contains the next value just as it would if no - * error had occurred. */ - dmi_write_exec(target, DM_COMMAND, command, true); - next_index++; + /* According to the spec, if an abstract command fails, one can't make any + * assumptions about dm_data registers, so all the values in the pipeline + * are clobbered now and need to be reread. + */ + const uint32_t min_index_on_target = start_index + 2; + if (index_on_target < min_index_on_target) { + LOG_TARGET_ERROR(target, "Arithmetic does not work correctly on the target"); + return ERROR_FAIL; + } else if (index_on_target == min_index_on_target) { + LOG_TARGET_DEBUG(target, "No forward progress"); + } + const uint32_t next_index = (index_on_target - 2); + *elements_read = next_index - start_index; + LOG_TARGET_WARNING(target, "Re-reading memory from addresses 0x%" + TARGET_PRIxADDR " and 0x%" TARGET_PRIxADDR ".", + access.target_address + access.increment * next_index, + access.target_address + access.increment * (next_index + 1)); + return read_memory_progbuf_inner_startup(target, access.target_address, + access.increment, next_index); +} - dmi_write(target, DM_ABSTRACTAUTO, - 1 << DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); +/** + * This function attempts to restore the pipeline after a dmi busy. + */ +static int read_memory_progbuf_inner_on_dmi_busy(struct target *target, + uint32_t start_index, uint32_t next_start_index, + struct memory_access_info access) +{ + LOG_TARGET_DEBUG(target, "DMI_STATUS_BUSY encountered in batch. Memory read [%" + PRIu32 ", %" PRIu32 ")", start_index, next_start_index); + if (start_index == next_start_index) + LOG_TARGET_DEBUG(target, "No forward progress"); - ignore_last = 1; + if (dm_write(target, DM_ABSTRACTAUTO, 0) != ERROR_OK) + return ERROR_FAIL; + return read_memory_progbuf_inner_startup(target, access.target_address, + access.increment, next_start_index); +} - break; - default: - LOG_DEBUG("error when reading memory, abstractcs=0x%08lx", (long)abstractcs); - riscv013_clear_abstract_error(target); - riscv_batch_free(batch); - result = ERROR_FAIL; - goto error; +/** + * This function extracts the data from the batch. + */ +static int read_memory_progbuf_inner_extract_batch_data(struct target *target, + const struct riscv_batch *batch, + uint32_t start_index, uint32_t elements_to_read, uint32_t *elements_read, + struct memory_access_info access) +{ + const bool two_reads_per_element = access.element_size > 4; + const uint32_t reads_per_element = (two_reads_per_element ? 2 : 1); + assert(!two_reads_per_element || riscv_xlen(target) == 64); + assert(elements_to_read <= UINT32_MAX / reads_per_element); + const uint32_t nreads = elements_to_read * reads_per_element; + for (uint32_t curr_idx = start_index, read = 0; read < nreads; ++read) { + switch (riscv_batch_get_dmi_read_op(batch, read)) { + case DMI_STATUS_BUSY: + *elements_read = curr_idx - start_index; + return read_memory_progbuf_inner_on_dmi_busy(target, start_index, curr_idx + , access); + case DMI_STATUS_FAILED: + LOG_TARGET_DEBUG(target, + "Batch memory read encountered DMI_STATUS_FAILED on read %" + PRIu32, read); + return ERROR_FAIL; + case DMI_STATUS_SUCCESS: + break; + default: + assert(0); } - - /* Now read whatever we got out of the batch. */ - dmi_status_t status = DMI_STATUS_SUCCESS; - unsigned read = 0; - assert(index >= 2); - for (unsigned j = index - 2; j < index + reads; j++) { - assert(j < count); - LOG_DEBUG("index=%d, reads=%d, next_index=%d, ignore_last=%d, j=%d", - index, reads, next_index, ignore_last, j); - if (j + 3 + ignore_last > next_index) - break; - - status = riscv_batch_get_dmi_read_op(batch, read); - uint64_t value = riscv_batch_get_dmi_read_data(batch, read); - read++; - if (status != DMI_STATUS_SUCCESS) { - /* If we're here because of busy count, dmi_busy_delay will - * already have been increased and busy state will have been - * cleared in dmi_read(). */ - /* In at least some implementations, we issue a read, and then - * can get busy back when we try to scan out the read result, - * and the actual read value is lost forever. Since this is - * rare in any case, we return error here and rely on our - * caller to reread the entire block. */ - LOG_WARNING("Batch memory read encountered DMI error %d. " - "Falling back on slower reads.", status); - riscv_batch_free(batch); - result = ERROR_FAIL; - goto error; - } - if (size > 4) { - status = riscv_batch_get_dmi_read_op(batch, read); - if (status != DMI_STATUS_SUCCESS) { - LOG_WARNING("Batch memory read encountered DMI error %d. " - "Falling back on slower reads.", status); - riscv_batch_free(batch); - result = ERROR_FAIL; - goto error; - } - value <<= 32; - value |= riscv_batch_get_dmi_read_data(batch, read); - read++; - } - riscv_addr_t offset = j * size; - buf_set_u64(buffer + offset, 0, 8 * size, value); - log_memory_access(address + j * increment, value, size, true); + const uint32_t value = riscv_batch_get_dmi_read_data(batch, read); + uint8_t * const curr_buff = access.buffer_address + + curr_idx * access.element_size; + const target_addr_t curr_addr = access.target_address + + curr_idx * access.increment; + const uint32_t size = access.element_size; + + assert(size <= 8); + const bool is_odd_read = read % 2; + + if (two_reads_per_element && !is_odd_read) { + buf_set_u32(curr_buff + 4, 0, (size * 8) - 32, value); + continue; } + const bool is_second_read = two_reads_per_element; - index = next_index; - - riscv_batch_free(batch); + buf_set_u32(curr_buff, 0, is_second_read ? 32 : (size * 8), value); + log_memory_access64(curr_addr, buf_get_u64(curr_buff, 0, size * 8), + size, /*is_read*/ true); + ++curr_idx; } + *elements_read = elements_to_read; + return ERROR_OK; +} + +/** + * This function reads a batch of elements from memory. + * Prior to calling this function the folowing conditions should be met: + * - Appropriate program loaded to program buffer. + * - DM_ABSTRACTAUTO_AUTOEXECDATA is set. + */ +static int read_memory_progbuf_inner_run_and_process_batch(struct target *target, + struct riscv_batch *batch, struct memory_access_info access, + uint32_t start_index, uint32_t elements_to_read, uint32_t *elements_read) +{ + if (batch_run(target, batch) != ERROR_OK) + return ERROR_FAIL; - dmi_write(target, DM_ABSTRACTAUTO, 0); + uint32_t abstractcs; + if (wait_for_idle(target, &abstractcs) != ERROR_OK) + return ERROR_FAIL; - if (count > 1) { - /* Read the penultimate word. */ - uint32_t dmi_data0, dmi_data1 = 0; - if (dmi_read(target, &dmi_data0, DM_DATA0) != ERROR_OK) - return ERROR_FAIL; - if (size > 4 && dmi_read(target, &dmi_data1, DM_DATA1) != ERROR_OK) + uint32_t elements_to_extract_from_batch; + + uint32_t cmderr = get_field32(abstractcs, DM_ABSTRACTCS_CMDERR); + switch (cmderr) { + case CMDERR_NONE: + LOG_TARGET_DEBUG(target, "successful (partial?) memory read [%" + PRIu32 ", %" PRIu32 ")", start_index, start_index + elements_to_read); + elements_to_extract_from_batch = elements_to_read; + break; + case CMDERR_BUSY: + LOG_TARGET_DEBUG(target, "memory read resulted in busy response"); + if (read_memory_progbuf_inner_on_ac_busy(target, start_index, + &elements_to_extract_from_batch, access) + != ERROR_OK) return ERROR_FAIL; - uint64_t value64 = (((uint64_t)dmi_data1) << 32) | dmi_data0; - buf_set_u64(buffer + size * (count - 2), 0, 8 * size, value64); - log_memory_access(address + size * (count - 2), value64, size, true); + break; + default: + LOG_TARGET_DEBUG(target, "error when reading memory, cmderr=0x%" PRIx32, cmderr); + riscv013_clear_abstract_error(target); + return ERROR_FAIL; } - /* Read the last word. */ - uint64_t value; - result = register_read_direct(target, &value, GDB_REGNO_S1); - if (result != ERROR_OK) - goto error; - buf_set_u64(buffer + size * (count-1), 0, 8 * size, value); - log_memory_access(address + size * (count-1), value, size, true); + if (read_memory_progbuf_inner_extract_batch_data(target, batch, start_index, + elements_to_extract_from_batch, elements_read, access) != ERROR_OK) + return ERROR_FAIL; return ERROR_OK; +} -error: - dmi_write(target, DM_ABSTRACTAUTO, 0); - - return result; +static uint32_t read_memory_progbuf_inner_fill_batch(struct riscv_batch *batch, + uint32_t count, uint32_t size) +{ + assert(size <= 8); + const uint32_t two_regs_used[] = {DM_DATA1, DM_DATA0}; + const uint32_t one_reg_used[] = {DM_DATA0}; + const uint32_t reads_per_element = size > 4 ? 2 : 1; + const uint32_t * const used_regs = size > 4 ? two_regs_used : one_reg_used; + const uint32_t batch_capacity = riscv_batch_available_scans(batch) / reads_per_element; + const uint32_t end = MIN(batch_capacity, count); + + for (uint32_t j = 0; j < end; ++j) + for (uint32_t i = 0; i < reads_per_element; ++i) + riscv_batch_add_dm_read(batch, used_regs[i]); + return end; } -/* Only need to save/restore one GPR to read a single word, and the progbuf - * program doesn't need to increment. */ -static int read_memory_progbuf_one(struct target *target, target_addr_t address, - uint32_t size, uint8_t *buffer) +static int read_memory_progbuf_inner_try_to_read(struct target *target, + struct memory_access_info access, uint32_t *elements_read, + uint32_t index, uint32_t loop_count) { - uint64_t mstatus = 0; - uint64_t mstatus_old = 0; - if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) + RISCV013_INFO(info); + struct riscv_batch *batch = riscv_batch_alloc(target, RISCV_BATCH_ALLOC_SIZE, + info->dmi_busy_delay + info->ac_busy_delay); + if (!batch) return ERROR_FAIL; - int result = ERROR_FAIL; - - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) - goto restore_mstatus; - - /* Write the program (load, increment) */ - struct riscv_program program; - riscv_program_init(&program, target); - if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) - riscv_program_csrrsi(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); - switch (size) { - case 1: - riscv_program_lbr(&program, GDB_REGNO_S0, GDB_REGNO_S0, 0); - break; - case 2: - riscv_program_lhr(&program, GDB_REGNO_S0, GDB_REGNO_S0, 0); - break; - case 4: - riscv_program_lwr(&program, GDB_REGNO_S0, GDB_REGNO_S0, 0); - break; - case 8: - riscv_program_ldr(&program, GDB_REGNO_S0, GDB_REGNO_S0, 0); - break; - default: - LOG_ERROR("Unsupported size: %d", size); - goto restore_mstatus; - } - if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) - riscv_program_csrrci(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); - - if (riscv_program_ebreak(&program) != ERROR_OK) - goto restore_mstatus; - if (riscv_program_write(&program) != ERROR_OK) - goto restore_mstatus; - - /* Write address to S0, and execute buffer. */ - if (write_abstract_arg(target, 0, address, riscv_xlen(target)) != ERROR_OK) - goto restore_mstatus; - uint32_t command = access_register_command(target, GDB_REGNO_S0, - riscv_xlen(target), AC_ACCESS_REGISTER_WRITE | - AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); - if (execute_abstract_command(target, command) != ERROR_OK) - goto restore_mstatus; - - uint64_t value; - if (register_read_direct(target, &value, GDB_REGNO_S0) != ERROR_OK) - goto restore_mstatus; - buf_set_u64(buffer, 0, 8 * size, value); - log_memory_access(address, value, size, true); - result = ERROR_OK; - -restore_mstatus: - if (mstatus != mstatus_old) - if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) - result = ERROR_FAIL; + const uint32_t elements_to_read = read_memory_progbuf_inner_fill_batch(batch, + loop_count - index, access.element_size); + int result = read_memory_progbuf_inner_run_and_process_batch(target, batch, + access, index, elements_to_read, elements_read); + riscv_batch_free(batch); return result; } /** - * Read the requested memory, silently handling memory access errors. + * read_memory_progbuf_inner_startup() must be called before calling this function + * with the address argument equal to curr_target_address. */ -static int read_memory_progbuf(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +static int read_memory_progbuf_inner_ensure_forward_progress(struct target *target, + struct memory_access_info access, uint32_t start_index) { - if (riscv_xlen(target) < size * 8) { - LOG_ERROR("XLEN (%d) is too short for %d-bit memory read.", - riscv_xlen(target), size * 8); + LOG_TARGET_DEBUG(target, + "Executing one loop iteration to ensure forward progress (index=%" + PRIu32 ")", start_index); + const target_addr_t curr_target_address = access.target_address + + start_index * access.increment; + uint8_t * const curr_buffer_address = access.buffer_address + + start_index * access.element_size; + const struct memory_access_info curr_access = { + .buffer_address = curr_buffer_address, + .target_address = curr_target_address, + .element_size = access.element_size, + .increment = access.increment, + }; + uint32_t elements_read; + if (read_memory_progbuf_inner_try_to_read(target, curr_access, &elements_read, + /*index*/ 0, /*loop_count*/ 1) != ERROR_OK) + return ERROR_FAIL; + + if (elements_read != 1) { + assert(elements_read == 0); + LOG_TARGET_DEBUG(target, "Can not ensure forward progress"); + /* FIXME: Here it would be better to retry the read and fail only if the + * delay is greater then some threshold. + */ return ERROR_FAIL; } + return ERROR_OK; +} - int result = ERROR_OK; +static void set_buffer_and_log_read(struct memory_access_info access, + uint32_t index, uint64_t value) +{ + uint8_t * const buffer = access.buffer_address; + const uint32_t size = access.element_size; + const uint32_t increment = access.increment; + const target_addr_t address = access.target_address; + + assert(size <= 8); + buf_set_u64(buffer + index * size, 0, 8 * size, value); + log_memory_access64(address + index * increment, value, size, + /*is_read*/ true); +} - LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, - size, address); +static int read_word_from_dm_data_regs(struct target *target, + struct memory_access_info access, uint32_t index) +{ + assert(access.element_size <= 8); + const uint64_t value = read_abstract_arg(target, /*index*/ 0, + access.element_size > 4 ? 64 : 32); + set_buffer_and_log_read(access, index, value); + return ERROR_OK; +} - if (dm013_select_target(target) != ERROR_OK) +static int read_word_from_s1(struct target *target, + struct memory_access_info access, uint32_t index) +{ + uint64_t value; + + if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; + set_buffer_and_log_read(access, index, value); + return ERROR_OK; +} - select_dmi(target); +static int riscv_program_load_mprv(struct riscv_program *p, enum gdb_regno d, + enum gdb_regno b, int offset, unsigned int size, bool mprven) +{ + if (mprven && riscv_program_csrrsi(p, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, + GDB_REGNO_DCSR) != ERROR_OK) + return ERROR_FAIL; - memset(buffer, 0, count*size); + if (riscv_program_load(p, d, b, offset, size) != ERROR_OK) + return ERROR_FAIL; - if (execute_fence(target) != ERROR_OK) + if (mprven && riscv_program_csrrci(p, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, + GDB_REGNO_DCSR) != ERROR_OK) return ERROR_FAIL; - if (count == 1) - return read_memory_progbuf_one(target, address, size, buffer); + return ERROR_OK; +} - uint64_t mstatus = 0; - uint64_t mstatus_old = 0; - if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) - return ERROR_FAIL; +static int read_memory_progbuf_inner_fill_progbuf(struct target *target, + uint32_t increment, uint32_t size, bool mprven) +{ + const bool is_repeated_read = increment == 0; - /* s0 holds the next address to read from - * s1 holds the next data value read - * s2 is a counter in case increment is 0 - */ if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; - if (increment == 0 && riscv_save_register(target, GDB_REGNO_S2) != ERROR_OK) + if (is_repeated_read && riscv_save_register(target, GDB_REGNO_A0) != ERROR_OK) return ERROR_FAIL; - /* Write the program (load, increment) */ struct riscv_program program; + riscv_program_init(&program, target); - if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) - riscv_program_csrrsi(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); + if (riscv_program_load_mprv(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0, size, + mprven) != ERROR_OK) + return ERROR_FAIL; + if (is_repeated_read) { + if (riscv_program_addi(&program, GDB_REGNO_A0, GDB_REGNO_A0, 1) + != ERROR_OK) + return ERROR_FAIL; + } else { + if (riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, + increment) + != ERROR_OK) + return ERROR_FAIL; + } + if (riscv_program_ebreak(&program) != ERROR_OK) + return ERROR_FAIL; + if (riscv_program_write(&program) != ERROR_OK) + return ERROR_FAIL; - switch (size) { - case 1: - riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); - break; - case 2: - riscv_program_lhr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); - break; - case 4: - riscv_program_lwr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); - break; - case 8: - riscv_program_ldr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); - break; - default: - LOG_ERROR("Unsupported size: %d", size); + return ERROR_OK; +} + +/** + * Read the requested memory, taking care to minimize the number of reads and + * re-read the data only if `abstract command busy` or `DMI busy` + * is encountered in the process. + */ +static int read_memory_progbuf_inner(struct target *target, + struct memory_access_info access, uint32_t count, bool mprven) +{ + assert(count > 1 && "If count == 1, read_memory_progbuf_inner_one must be called"); + + if (read_memory_progbuf_inner_fill_progbuf(target, access.increment, + access.element_size, mprven) != ERROR_OK) + return ERROR_FAIL; + + if (read_memory_progbuf_inner_startup(target, access.target_address, + access.increment, /*index*/ 0) + != ERROR_OK) + return ERROR_FAIL; + /* The program in program buffer is executed twice during + * read_memory_progbuf_inner_startup(). + * Here: + * dm_data[0:1] == M[address] + * s1 == M[address + increment] + * s0 == address + increment * 2 + * `count - 2` program executions are performed in this loop. + * No need to execute the program any more, since S1 will already contain + * M[address + increment * (count - 1)] and we can read it directly. + */ + const uint32_t loop_count = count - 2; + + for (uint32_t index = 0; index < loop_count;) { + uint32_t elements_read; + if (read_memory_progbuf_inner_try_to_read(target, access, &elements_read, + index, loop_count) != ERROR_OK) { + dm_write(target, DM_ABSTRACTAUTO, 0); return ERROR_FAIL; + } + if (elements_read == 0) { + if (read_memory_progbuf_inner_ensure_forward_progress(target, access, + index) != ERROR_OK) { + dm_write(target, DM_ABSTRACTAUTO, 0); + return ERROR_FAIL; + } + elements_read = 1; + } + index += elements_read; + assert(index <= loop_count); } + if (dm_write(target, DM_ABSTRACTAUTO, 0) != ERROR_OK) + return ERROR_FAIL; - if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) - riscv_program_csrrci(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); - if (increment == 0) - riscv_program_addi(&program, GDB_REGNO_S2, GDB_REGNO_S2, 1); - else - riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, increment); + /* Read the penultimate word. */ + if (read_word_from_dm_data_regs(target, access, count - 2) + != ERROR_OK) + return ERROR_FAIL; + /* Read the last word. */ + return read_word_from_s1(target, access, count - 1); +} + +/** + * Only need to save/restore one GPR to read a single word, and the progbuf + * program doesn't need to increment. + */ +static int read_memory_progbuf_inner_one(struct target *target, + struct memory_access_info access, bool mprven) +{ + if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + + struct riscv_program program; + riscv_program_init(&program, target); + if (riscv_program_load_mprv(&program, GDB_REGNO_S1, GDB_REGNO_S1, 0, + access.element_size, mprven) != ERROR_OK) + return ERROR_FAIL; if (riscv_program_ebreak(&program) != ERROR_OK) return ERROR_FAIL; if (riscv_program_write(&program) != ERROR_OK) return ERROR_FAIL; - result = read_memory_progbuf_inner(target, address, size, count, buffer, increment); + /* Write address to S1, and execute buffer. */ + if (write_abstract_arg(target, 0, access.target_address, riscv_xlen(target)) + != ERROR_OK) + return ERROR_FAIL; + uint32_t command = access_register_command(target, GDB_REGNO_S1, + riscv_xlen(target), AC_ACCESS_REGISTER_WRITE | + AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); + uint32_t cmderr; + if (execute_abstract_command(target, command, &cmderr) != ERROR_OK) + return ERROR_FAIL; - if (result != ERROR_OK) { - /* The full read did not succeed, so we will try to read each word individually. */ - /* This will not be fast, but reading outside actual memory is a special case anyway. */ - /* It will make the toolchain happier, especially Eclipse Memory View as it reads ahead. */ - target_addr_t address_i = address; - uint32_t count_i = 1; - uint8_t *buffer_i = buffer; - - for (uint32_t i = 0; i < count; i++, address_i += increment, buffer_i += size) { - /* TODO: This is much slower than it needs to be because we end up - * writing the address to read for every word we read. */ - result = read_memory_progbuf_inner(target, address_i, size, count_i, buffer_i, increment); - - /* The read of a single word failed, so we will just return 0 for that instead */ - if (result != ERROR_OK) { - LOG_DEBUG("error reading single word of %d bytes from 0x%" TARGET_PRIxADDR, - size, address_i); + return read_word_from_s1(target, access, 0); +} - buf_set_u64(buffer_i, 0, 8 * size, 0); - } - } - result = ERROR_OK; +/** + * Read the requested memory, silently handling memory access errors. + */ +static int read_memory_progbuf(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +{ + if (riscv_xlen(target) < size * 8) { + LOG_TARGET_ERROR(target, "XLEN (%d) is too short for %" + PRIu32 "-bit memory read.", riscv_xlen(target), size * 8); + return ERROR_FAIL; } - /* Restore MSTATUS */ - if (mstatus != mstatus_old) - if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) - return ERROR_FAIL; + LOG_TARGET_DEBUG(target, "reading %" PRIu32 " elements of %" PRIu32 + " bytes from 0x%" TARGET_PRIxADDR, count, size, address); + + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; + + select_dmi(target); + + memset(buffer, 0, count*size); + + if (execute_fence(target) != ERROR_OK) + return ERROR_FAIL; + + uint64_t mstatus = 0; + uint64_t mstatus_old = 0; + if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) + return ERROR_FAIL; + + const bool mprven = riscv_enable_virtual && get_field(mstatus, MSTATUS_MPRV); + const struct memory_access_info access = { + .target_address = address, + .increment = increment, + .buffer_address = buffer, + .element_size = size, + }; + int result = (count == 1) ? + read_memory_progbuf_inner_one(target, access, mprven) : + read_memory_progbuf_inner(target, access, count, mprven); + + if (mstatus != mstatus_old && + register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old) != ERROR_OK) + return ERROR_FAIL; return result; } @@ -3554,7 +4250,7 @@ static int read_memory(struct target *target, target_addr_t address, return ERROR_OK; if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) { - LOG_ERROR("BUG: Unsupported size for memory read: %d", size); + LOG_TARGET_ERROR(target, "BUG: Unsupported size for memory read: %d", size); return ERROR_FAIL; } @@ -3606,8 +4302,8 @@ static int read_memory(struct target *target, target_addr_t address, return ret; } - LOG_ERROR("Target %s: Failed to read memory (addr=0x%" PRIx64 ")", target_name(target), address); - LOG_ERROR(" progbuf=%s, sysbus=%s, abstract=%s", progbuf_result, sysbus_result, abstract_result); + LOG_TARGET_ERROR(target, "Failed to read memory (addr=0x%" PRIx64 ")", address); + LOG_TARGET_ERROR(target, " progbuf=%s, sysbus=%s, abstract=%s", progbuf_result, sysbus_result, abstract_result); return ret; } @@ -3615,9 +4311,9 @@ static int write_memory_bus_v0(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { /*1) write sbaddress: for singlewrite and autoincrement, we need to write the address once*/ - LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" + LOG_TARGET_DEBUG(target, "System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" TARGET_PRIxADDR, size, count, address); - dmi_write(target, DM_SBADDRESS0, address); + dm_write(target, DM_SBADDRESS0, address); int64_t value = 0; int64_t access = 0; riscv_addr_t offset = 0; @@ -3630,10 +4326,10 @@ static int write_memory_bus_v0(struct target *target, target_addr_t address, access = 0; access = set_field(access, DM_SBCS_SBACCESS, size/2); - dmi_write(target, DM_SBCS, access); - LOG_DEBUG("\r\naccess: 0x%08" PRIx64, access); - LOG_DEBUG("\r\nwrite_memory:SAB: ONE OFF: value 0x%08" PRIx64, value); - dmi_write(target, DM_SBDATA0, value); + dm_write(target, DM_SBCS, access); + LOG_TARGET_DEBUG(target, " access: 0x%08" PRIx64, access); + LOG_TARGET_DEBUG(target, " write_memory:SAB: ONE OFF: value 0x%08" PRIx64, value); + dm_write(target, DM_SBDATA0, value); return ERROR_OK; } @@ -3642,8 +4338,8 @@ static int write_memory_bus_v0(struct target *target, target_addr_t address, access = 0; access = set_field(access, DM_SBCS_SBACCESS, size/2); access = set_field(access, DM_SBCS_SBAUTOINCREMENT, 1); - LOG_DEBUG("\r\naccess: 0x%08" PRIx64, access); - dmi_write(target, DM_SBCS, access); + LOG_TARGET_DEBUG(target, " access: 0x%08" PRIx64, access); + dm_write(target, DM_SBCS, access); /*2)set the value according to the size required and write*/ for (riscv_addr_t i = 0; i < count; ++i) { @@ -3653,13 +4349,13 @@ static int write_memory_bus_v0(struct target *target, target_addr_t address, t_buffer = buffer + offset; value = buf_get_u64(t_buffer, 0, 8 * size); - LOG_DEBUG("SAB:autoincrement: expected address: 0x%08x value: 0x%08x" + LOG_TARGET_DEBUG(target, "SAB:autoincrement: expected address: 0x%08x value: 0x%08x" PRIx64, (uint32_t)t_addr, (uint32_t)value); - dmi_write(target, DM_SBDATA0, value); + dm_write(target, DM_SBDATA0, value); } /*reset the autoincrement when finished (something weird is happening if this is not done at the end*/ access = set_field(access, DM_SBCS_SBAUTOINCREMENT, 0); - dmi_write(target, DM_SBCS, access); + dm_write(target, DM_SBCS, access); return ERROR_OK; } @@ -3670,7 +4366,7 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, RISCV013_INFO(info); uint32_t sbcs = sb_sbaccess(size); sbcs = set_field(sbcs, DM_SBCS_SBAUTOINCREMENT, 1); - dmi_write(target, DM_SBCS, sbcs); + dm_write(target, DM_SBCS, sbcs); target_addr_t next_address = address; target_addr_t end_address = address + count * size; @@ -3679,7 +4375,7 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, sb_write_address(target, next_address, true); while (next_address < end_address) { - LOG_DEBUG("transferring burst starting at address 0x%" TARGET_PRIxADDR, + LOG_TARGET_DEBUG(target, "Transferring burst starting at address 0x%" TARGET_PRIxADDR, next_address); struct riscv_batch *batch = riscv_batch_alloc( @@ -3695,35 +4391,42 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, if (riscv_batch_available_scans(batch) < (size + 3) / 4) break; - if (size > 12) - riscv_batch_add_dmi_write(batch, DM_SBDATA3, - ((uint32_t) p[12]) | - (((uint32_t) p[13]) << 8) | - (((uint32_t) p[14]) << 16) | - (((uint32_t) p[15]) << 24)); - - if (size > 8) - riscv_batch_add_dmi_write(batch, DM_SBDATA2, - ((uint32_t) p[8]) | - (((uint32_t) p[9]) << 8) | - (((uint32_t) p[10]) << 16) | - (((uint32_t) p[11]) << 24)); - if (size > 4) - riscv_batch_add_dmi_write(batch, DM_SBDATA1, - ((uint32_t) p[4]) | - (((uint32_t) p[5]) << 8) | - (((uint32_t) p[6]) << 16) | - (((uint32_t) p[7]) << 24)); - uint32_t value = p[0]; + uint32_t sbvalue[4] = { 0 }; + if (size > 12) { + sbvalue[3] = ((uint32_t)p[12]) | + (((uint32_t)p[13]) << 8) | + (((uint32_t)p[14]) << 16) | + (((uint32_t)p[15]) << 24); + riscv_batch_add_dm_write(batch, DM_SBDATA3, sbvalue[3], false); + } + + if (size > 8) { + sbvalue[2] = ((uint32_t)p[8]) | + (((uint32_t)p[9]) << 8) | + (((uint32_t)p[10]) << 16) | + (((uint32_t)p[11]) << 24); + riscv_batch_add_dm_write(batch, DM_SBDATA2, sbvalue[2], false); + } + if (size > 4) { + sbvalue[1] = ((uint32_t)p[4]) | + (((uint32_t)p[5]) << 8) | + (((uint32_t)p[6]) << 16) | + (((uint32_t)p[7]) << 24); + riscv_batch_add_dm_write(batch, DM_SBDATA1, sbvalue[1], false); + } + + sbvalue[0] = p[0]; if (size > 2) { - value |= ((uint32_t) p[2]) << 16; - value |= ((uint32_t) p[3]) << 24; + sbvalue[0] |= ((uint32_t)p[2]) << 16; + sbvalue[0] |= ((uint32_t)p[3]) << 24; } if (size > 1) - value |= ((uint32_t) p[1]) << 8; - riscv_batch_add_dmi_write(batch, DM_SBDATA0, value); + sbvalue[0] |= ((uint32_t)p[1]) << 8; + + riscv_batch_add_dm_write(batch, DM_SBDATA0, sbvalue[0], false); + + log_memory_access(address + i * size, sbvalue, size, false); - log_memory_access(address + i * size, value, size, false); next_address += size; } @@ -3736,30 +4439,30 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, /* Read sbcs value. * At the same time, detect if DMI busy has occurred during the batch write. */ bool dmi_busy_encountered; - if (dmi_op(target, &sbcs, &dmi_busy_encountered, DMI_OP_READ, + if (dm_op(target, &sbcs, &dmi_busy_encountered, DMI_OP_READ, DM_SBCS, 0, false, true) != ERROR_OK) return ERROR_FAIL; if (dmi_busy_encountered) - LOG_DEBUG("DMI busy encountered during system bus write."); + LOG_TARGET_DEBUG(target, "DMI busy encountered during system bus write."); /* Wait until sbbusy goes low */ time_t start = time(NULL); while (get_field(sbcs, DM_SBCS_SBBUSY)) { if (time(NULL) - start > riscv_command_timeout_sec) { - LOG_ERROR("Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). " + LOG_TARGET_ERROR(target, "Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", riscv_command_timeout_sec, sbcs); return ERROR_FAIL; } - if (dmi_read(target, &sbcs, DM_SBCS) != ERROR_OK) + if (dm_read(target, &sbcs, DM_SBCS) != ERROR_OK) return ERROR_FAIL; } if (get_field(sbcs, DM_SBCS_SBBUSYERROR)) { /* We wrote while the target was busy. */ - LOG_DEBUG("Sbbusyerror encountered during system bus write."); + LOG_TARGET_DEBUG(target, "Sbbusyerror encountered during system bus write."); /* Clear the sticky error flag. */ - dmi_write(target, DM_SBCS, sbcs | DM_SBCS_SBBUSYERROR); + dm_write(target, DM_SBCS, sbcs | DM_SBCS_SBBUSYERROR); /* Slow down before trying again. */ info->bus_master_write_delay += info->bus_master_write_delay / 10 + 1; } @@ -3770,7 +4473,7 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, next_address = sb_read_address(target); if (next_address < address) { /* This should never happen, probably buggy hardware. */ - LOG_DEBUG("unexpected sbaddress=0x%" TARGET_PRIxADDR + LOG_TARGET_DEBUG(target, "unexpected sbaddress=0x%" TARGET_PRIxADDR " - buggy sbautoincrement in hw?", next_address); /* Fail the whole operation. */ return ERROR_FAIL; @@ -3786,16 +4489,16 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, * (unless sbautoincrement in the HW is buggy). */ target_addr_t sbaddress = sb_read_address(target); - LOG_DEBUG("System bus access failed with sberror=%u (sbaddress=0x%" TARGET_PRIxADDR ")", + LOG_TARGET_DEBUG(target, "System bus access failed with sberror=%u (sbaddress=0x%" TARGET_PRIxADDR ")", sberror, sbaddress); if (sbaddress < address) { /* This should never happen, probably buggy hardware. * Make a note to the user not to trust the sbaddress value. */ - LOG_DEBUG("unexpected sbaddress=0x%" TARGET_PRIxADDR + LOG_TARGET_DEBUG(target, "unexpected sbaddress=0x%" TARGET_PRIxADDR " - buggy sbautoincrement in hw?", next_address); } /* Clear the sticky error flag */ - dmi_write(target, DM_SBCS, DM_SBCS_SBERROR); + dm_write(target, DM_SBCS, DM_SBCS_SBERROR); /* Fail the whole operation */ return ERROR_FAIL; } @@ -3804,178 +4507,278 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, return ERROR_OK; } -static int write_memory_progbuf(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer) +/** + * This function is used to start the memory-writing pipeline. + * As part of the process, the function writes the first item and waits for completion, + * so forward progress is ensured. + * The pipeline looks like this: + * debugger -> dm_data[0:1] -> s1 -> memory + * Prior to calling it, the program buffer should contain the appropriate + * program. + * This function sets DM_ABSTRACTAUTO_AUTOEXECDATA to trigger second stage of the + * pipeline (dm_data[0:1] -> s1) whenever dm_data is written. + */ +static int write_memory_progbuf_startup(struct target *target, target_addr_t *address_p, + const uint8_t *buffer, uint32_t size) { - RISCV013_INFO(info); - - if (riscv_xlen(target) < size * 8) { - LOG_ERROR("XLEN (%d) is too short for %d-bit memory write.", - riscv_xlen(target), size * 8); + /* TODO: There is potential to gain some performance if the operations below are + * executed inside the first DMI batch (not separately). */ + if (register_write_direct(target, GDB_REGNO_S0, *address_p) != ERROR_OK) return ERROR_FAIL; - } - LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address); + /* Write the first item to data0 [, data1] */ + assert(size <= 8); + const uint64_t value = buf_get_u64(buffer, 0, 8 * size); + if (write_abstract_arg(target, /*index*/ 0, value, size > 4 ? 64 : 32) + != ERROR_OK) + return ERROR_FAIL; - select_dmi(target); + /* Write and execute command that moves the value from data0 [, data1] + * into S1 and executes program buffer. */ + uint32_t command = access_register_command(target, + GDB_REGNO_S1, riscv_xlen(target), + AC_ACCESS_REGISTER_POSTEXEC | + AC_ACCESS_REGISTER_TRANSFER | + AC_ACCESS_REGISTER_WRITE); - uint64_t mstatus = 0; - uint64_t mstatus_old = 0; - if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) + uint32_t cmderr; + if (execute_abstract_command(target, command, &cmderr) != ERROR_OK) return ERROR_FAIL; - /* s0 holds the next address to write to - * s1 holds the next data value to write + log_memory_access64(*address_p, value, size, /*is_read*/ false); + + /* The execution of the command succeeded, which means: + * - write of the first item to memory succeeded + * - address on the target (S0) was incremented */ + *address_p += size; - int result = ERROR_OK; - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + /* TODO: Setting abstractauto.autoexecdata is not necessary for a write + * of one element. */ + return dm_write(target, DM_ABSTRACTAUTO, + 1 << DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); +} + +/** + * This function reverts the changes made by `write_memory_progbuf_startup()` + */ +static int write_memory_progbuf_teardown(struct target *target) +{ + return dm_write(target, DM_ABSTRACTAUTO, 0); +} + +/** + * This function attempts to restore the pipeline after a busy on abstract + * access or a DMI busy by reading the content of s0 -- the address of the + * failed write. + */ +static int write_memory_progbuf_handle_busy(struct target *target, + target_addr_t *address_p, uint32_t size, const uint8_t *buffer) +{ + riscv013_clear_abstract_error(target); + increase_ac_busy_delay(target); + + if (write_memory_progbuf_teardown(target) != ERROR_OK) return ERROR_FAIL; - if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) + + target_addr_t address_on_target; + if (register_read_direct(target, &address_on_target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; + const uint8_t * const curr_buff = buffer + (address_on_target - *address_p); + LOG_TARGET_DEBUG(target, "Restarting from 0x%" TARGET_PRIxADDR, *address_p); + *address_p = address_on_target; + /* This restores the pipeline and ensures one item gets reliably written */ + return write_memory_progbuf_startup(target, address_p, curr_buff, size); +} - /* Write the program (store, increment) */ - struct riscv_program program; - riscv_program_init(&program, target); - if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) - riscv_program_csrrsi(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); +/** + * This function fills the batch with DMI writes (but does not execute the batch). + * It returns the next address -- the address that will be the start of the next batch. + */ +static target_addr_t write_memory_progbuf_fill_batch(struct riscv_batch *batch, + target_addr_t start_address, target_addr_t end_address, uint32_t size, + const uint8_t *buffer) +{ + assert(size <= 8); + const unsigned int writes_per_element = size > 4 ? 2 : 1; + const size_t batch_capacity = riscv_batch_available_scans(batch) / writes_per_element; + /* This is safe even for the edge case when writing at the very top of + * the 64-bit address space (in which case end_address overflows to 0). + */ + const target_addr_t batch_end_address = start_address + + MIN((target_addr_t)batch_capacity * size, + end_address - start_address); + for (target_addr_t address = start_address; address != batch_end_address; + address += size, buffer += size) { + assert(size <= 8); + const uint64_t value = buf_get_u64(buffer, 0, 8 * size); + log_memory_access64(address, value, size, /*is_read*/ false); + if (writes_per_element == 2) + riscv_batch_add_dm_write(batch, DM_DATA1, + (uint32_t)(value >> 32), false); + riscv_batch_add_dm_write(batch, DM_DATA0, (uint32_t)value, false); + } + return batch_end_address; +} - switch (size) { - case 1: - riscv_program_sbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); - break; - case 2: - riscv_program_shr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); - break; - case 4: - riscv_program_swr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); - break; - case 8: - riscv_program_sdr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); - break; - default: - LOG_ERROR("write_memory_progbuf(): Unsupported size: %d", size); - result = ERROR_FAIL; - goto error; +/** + * This function runs the batch of writes and updates address_p with the + * address of the next write. + */ +static int write_memory_progbuf_run_batch(struct target *target, struct riscv_batch *batch, + target_addr_t *address_p, target_addr_t end_address, uint32_t size, + const uint8_t *buffer) +{ + if (batch_run(target, batch) != ERROR_OK) + return ERROR_FAIL; + + /* Note that if the scan resulted in a Busy DMI response, it + * is this call to wait_for_idle() that will cause the dmi_busy_delay + * to be incremented if necessary. */ + uint32_t abstractcs; + + if (wait_for_idle(target, &abstractcs) != ERROR_OK) + return ERROR_FAIL; + + uint32_t cmderr = get_field32(abstractcs, DM_ABSTRACTCS_CMDERR); + const bool dmi_busy_encountered = riscv_batch_dmi_busy_encountered(batch); + if (cmderr == CMDERR_NONE && !dmi_busy_encountered) { + LOG_TARGET_DEBUG(target, "Successfully written memory block M[0x%" TARGET_PRIxADDR + ".. 0x%" TARGET_PRIxADDR ")", *address_p, end_address); + *address_p = end_address; + return ERROR_OK; + } else if (cmderr == CMDERR_BUSY || dmi_busy_encountered) { + if (cmderr == CMDERR_BUSY) + LOG_TARGET_DEBUG(target, "Encountered abstract command busy response while writing block M[0x%" + TARGET_PRIxADDR ".. 0x%" TARGET_PRIxADDR ")", *address_p, end_address); + if (dmi_busy_encountered) + LOG_TARGET_DEBUG(target, "Encountered DMI busy response while writing block M[0x%" + TARGET_PRIxADDR ".. 0x%" TARGET_PRIxADDR ")", *address_p, end_address); + /* TODO: If dmi busy is encountered, the address of the last + * successful write can be deduced by analysing the batch. + */ + return write_memory_progbuf_handle_busy(target, address_p, size, buffer); } + LOG_TARGET_ERROR(target, "Error when writing memory, abstractcs=0x%" PRIx32, + abstractcs); + riscv013_clear_abstract_error(target); + return ERROR_FAIL; +} - if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV)) - riscv_program_csrrci(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR); - riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); +static int write_memory_progbuf_try_to_write(struct target *target, + target_addr_t *address_p, target_addr_t end_address, uint32_t size, + const uint8_t *buffer) +{ + RISCV013_INFO(info); + struct riscv_batch * const batch = riscv_batch_alloc(target, RISCV_BATCH_ALLOC_SIZE, + info->dmi_busy_delay + info->ac_busy_delay); + if (!batch) + return ERROR_FAIL; - result = riscv_program_ebreak(&program); - if (result != ERROR_OK) - goto error; - riscv_program_write(&program); + const target_addr_t batch_end_addr = write_memory_progbuf_fill_batch(batch, + *address_p, end_address, size, buffer); - riscv_addr_t cur_addr = address; - riscv_addr_t distance = (riscv_addr_t)count * size; - bool setup_needed = true; - LOG_DEBUG("writing until final address 0x%016" PRIx64, cur_addr + distance); - while (cur_addr - address < distance) { - LOG_DEBUG("transferring burst starting at address 0x%016" PRIx64, - cur_addr); + int result = write_memory_progbuf_run_batch(target, batch, address_p, + batch_end_addr, size, buffer); + riscv_batch_free(batch); + return result; +} - struct riscv_batch *batch = riscv_batch_alloc( - target, - RISCV_BATCH_ALLOC_SIZE, - info->dmi_busy_delay + info->ac_busy_delay); - if (!batch) - goto error; +static int riscv_program_store_mprv(struct riscv_program *p, enum gdb_regno d, + enum gdb_regno b, int offset, unsigned int size, bool mprven) +{ + if (mprven && riscv_program_csrrsi(p, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, + GDB_REGNO_DCSR) != ERROR_OK) + return ERROR_FAIL; - /* To write another word, we put it in S1 and execute the program. */ - for (riscv_addr_t offset = cur_addr - address; offset < distance; offset += size) { - const uint8_t *t_buffer = buffer + offset; + if (riscv_program_store(p, d, b, offset, size) != ERROR_OK) + return ERROR_FAIL; - uint64_t value = buf_get_u64(t_buffer, 0, 8 * size); + if (mprven && riscv_program_csrrci(p, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, + GDB_REGNO_DCSR) != ERROR_OK) + return ERROR_FAIL; - log_memory_access(cur_addr, value, size, false); - cur_addr += size; + return ERROR_OK; +} - if (setup_needed) { - result = register_write_direct(target, GDB_REGNO_S0, - address + offset); - if (result != ERROR_OK) { - riscv_batch_free(batch); - goto error; - } +static int write_memory_progbuf_fill_progbuf(struct target *target, + uint32_t size, bool mprven) +{ + if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; - /* Write value. */ - if (size > 4) - dmi_write(target, DM_DATA1, value >> 32); - dmi_write(target, DM_DATA0, value); - - /* Write and execute command that moves value into S1 and - * executes program buffer. */ - uint32_t command = access_register_command(target, - GDB_REGNO_S1, riscv_xlen(target), - AC_ACCESS_REGISTER_POSTEXEC | - AC_ACCESS_REGISTER_TRANSFER | - AC_ACCESS_REGISTER_WRITE); - result = execute_abstract_command(target, command); - if (result != ERROR_OK) { - riscv_batch_free(batch); - goto error; - } + struct riscv_program program; - /* Turn on autoexec */ - dmi_write(target, DM_ABSTRACTAUTO, - 1 << DM_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); + riscv_program_init(&program, target); + if (riscv_program_store_mprv(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0, size, + mprven) != ERROR_OK) + return ERROR_FAIL; - setup_needed = false; - } else { - if (size > 4) - riscv_batch_add_dmi_write(batch, DM_DATA1, value >> 32); - riscv_batch_add_dmi_write(batch, DM_DATA0, value); - if (riscv_batch_full(batch)) - break; - } - } + if (riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size) != ERROR_OK) + return ERROR_FAIL; - result = batch_run(target, batch); - riscv_batch_free(batch); - if (result != ERROR_OK) - goto error; + if (riscv_program_ebreak(&program) != ERROR_OK) + return ERROR_FAIL; - /* Note that if the scan resulted in a Busy DMI response, it - * is this read to abstractcs that will cause the dmi_busy_delay - * to be incremented if necessary. */ + return riscv_program_write(&program); +} - uint32_t abstractcs; - bool dmi_busy_encountered; - result = dmi_op(target, &abstractcs, &dmi_busy_encountered, - DMI_OP_READ, DM_ABSTRACTCS, 0, false, true); - if (result != ERROR_OK) - goto error; - while (get_field(abstractcs, DM_ABSTRACTCS_BUSY)) - if (dmi_read(target, &abstractcs, DM_ABSTRACTCS) != ERROR_OK) - return ERROR_FAIL; - info->cmderr = get_field(abstractcs, DM_ABSTRACTCS_CMDERR); - if (info->cmderr == CMDERR_NONE && !dmi_busy_encountered) { - LOG_DEBUG("successful (partial?) memory write"); - } else if (info->cmderr == CMDERR_BUSY || dmi_busy_encountered) { - if (info->cmderr == CMDERR_BUSY) - LOG_DEBUG("Memory write resulted in abstract command busy response."); - else if (dmi_busy_encountered) - LOG_DEBUG("Memory write resulted in DMI busy response."); - riscv013_clear_abstract_error(target); - increase_ac_busy_delay(target); - - dmi_write(target, DM_ABSTRACTAUTO, 0); - result = register_read_direct(target, &cur_addr, GDB_REGNO_S0); - if (result != ERROR_OK) - goto error; - setup_needed = true; - } else { - LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs); - riscv013_clear_abstract_error(target); - result = ERROR_FAIL; - goto error; +static int write_memory_progbuf_inner(struct target *target, target_addr_t start_addr, + uint32_t size, uint32_t count, const uint8_t *buffer, bool mprven) +{ + if (write_memory_progbuf_fill_progbuf(target, size, + mprven) != ERROR_OK) + return ERROR_FAIL; + + target_addr_t addr_on_target = start_addr; + if (write_memory_progbuf_startup(target, &addr_on_target, buffer, size) != ERROR_OK) + return ERROR_FAIL; + + const target_addr_t end_addr = start_addr + (target_addr_t)size * count; + + for (target_addr_t next_addr_on_target = addr_on_target; addr_on_target != end_addr; + addr_on_target = next_addr_on_target) { + const uint8_t * const curr_buff = buffer + (addr_on_target - start_addr); + if (write_memory_progbuf_try_to_write(target, &next_addr_on_target, + end_addr, size, curr_buff) != ERROR_OK) { + write_memory_progbuf_teardown(target); + return ERROR_FAIL; } + /* write_memory_progbuf_try_to_write() ensures that at least one item + * gets successfully written even when busy condition is encountered. + * These assertions shuld hold when next_address_on_target overflows. */ + assert(next_addr_on_target - addr_on_target > 0); + assert(next_addr_on_target - start_addr <= (target_addr_t)size * count); } -error: - dmi_write(target, DM_ABSTRACTAUTO, 0); + return write_memory_progbuf_teardown(target); +} + +static int write_memory_progbuf(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + if (riscv_xlen(target) < size * 8) { + LOG_TARGET_ERROR(target, "XLEN (%u) is too short for %" PRIu32 "-bit memory write.", + riscv_xlen(target), size * 8); + return ERROR_FAIL; + } + + LOG_TARGET_DEBUG(target, "writing %" PRIu32 " words of %" PRIu32 + " bytes to 0x%" TARGET_PRIxADDR, count, size, address); + + if (dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; + + uint64_t mstatus = 0; + uint64_t mstatus_old = 0; + if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) + return ERROR_FAIL; + + const bool mprven = riscv_enable_virtual && get_field(mstatus, MSTATUS_MPRV); + + int result = write_memory_progbuf_inner(target, address, size, count, buffer, mprven); /* Restore MSTATUS */ if (mstatus != mstatus_old) @@ -3992,7 +4795,7 @@ static int write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) { - LOG_ERROR("BUG: Unsupported size for memory write: %d", size); + LOG_TARGET_ERROR(target, "BUG: Unsupported size for memory write: %d", size); return ERROR_FAIL; } @@ -4044,8 +4847,8 @@ static int write_memory(struct target *target, target_addr_t address, return ret; } - LOG_ERROR("Target %s: Failed to write memory (addr=0x%" PRIx64 ")", target_name(target), address); - LOG_ERROR(" progbuf=%s, sysbus=%s, abstract=%s", progbuf_result, sysbus_result, abstract_result); + LOG_TARGET_ERROR(target, "Target %s: Failed to write memory (addr=0x%" PRIx64 ")", target_name(target), address); + LOG_TARGET_ERROR(target, " progbuf=%s, sysbus=%s, abstract=%s", progbuf_result, sysbus_result, abstract_result); return ret; } @@ -4075,65 +4878,44 @@ struct target_type riscv013_target = { /*** 0.13-specific implementations of various RISC-V helper functions. ***/ static int riscv013_get_register(struct target *target, - riscv_reg_t *value, int rid) + riscv_reg_t *value, enum gdb_regno rid) { - LOG_DEBUG("[%s] reading register %s", target_name(target), - gdb_regno_name(rid)); + /* It would be beneficial to move this redirection to the + * version-independent section, but there is a conflict: + * `dcsr[5]` is `dcsr.v` in current spec, but it is `dcsr.debugint` in 0.11. + */ + if (rid == GDB_REGNO_PRIV) { + uint64_t dcsr; + if (riscv_get_register(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) + return ERROR_FAIL; + *value = set_field(0, VIRT_PRIV_V, get_field(dcsr, CSR_DCSR_V)); + *value = set_field(*value, VIRT_PRIV_PRV, get_field(dcsr, CSR_DCSR_PRV)); + return ERROR_OK; + } + + LOG_TARGET_DEBUG(target, "reading register %s", gdb_regno_name(target, rid)); if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; - int result = ERROR_OK; - if (rid == GDB_REGNO_PC) { - /* TODO: move this into riscv.c. */ - result = register_read_direct(target, value, GDB_REGNO_DPC); - LOG_TARGET_DEBUG(target, "read PC from DPC: 0x%" PRIx64, *value); - } else if (rid == GDB_REGNO_PRIV) { - uint64_t dcsr; - /* TODO: move this into riscv.c. */ - result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR); - *value = set_field(0, VIRT_PRIV_V, get_field(dcsr, CSR_DCSR_V)); - *value = set_field(*value, VIRT_PRIV_PRV, get_field(dcsr, CSR_DCSR_PRV)); - } else { - result = register_read_direct(target, value, rid); - if (result != ERROR_OK) - *value = -1; + if (register_read_direct(target, value, rid) != ERROR_OK) { + *value = -1; + return ERROR_FAIL; } - return result; + return ERROR_OK; } -static int riscv013_set_register(struct target *target, int rid, uint64_t value) +static int riscv013_set_register(struct target *target, enum gdb_regno rid, + riscv_reg_t value) { + LOG_TARGET_DEBUG(target, "writing 0x%" PRIx64 " to register %s", + value, gdb_regno_name(target, rid)); + if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; - LOG_TARGET_DEBUG(target, "writing 0x%" PRIx64 " to register %s", - value, gdb_regno_name(rid)); - - if (rid <= GDB_REGNO_XPR31) { - return register_write_direct(target, rid, value); - } else if (rid == GDB_REGNO_PC) { - LOG_TARGET_DEBUG(target, "writing PC to DPC: 0x%" PRIx64, value); - register_write_direct(target, GDB_REGNO_DPC, value); - uint64_t actual_value; - register_read_direct(target, &actual_value, GDB_REGNO_DPC); - LOG_TARGET_DEBUG(target, " actual DPC written: 0x%016" PRIx64, actual_value); - if (value != actual_value) { - LOG_ERROR("Written PC (0x%" PRIx64 ") does not match read back " - "value (0x%" PRIx64 ")", value, actual_value); - return ERROR_FAIL; - } - } else if (rid == GDB_REGNO_PRIV) { - uint64_t dcsr; - register_read_direct(target, &dcsr, GDB_REGNO_DCSR); - dcsr = set_field(dcsr, CSR_DCSR_PRV, get_field(value, VIRT_PRIV_PRV)); - dcsr = set_field(dcsr, CSR_DCSR_V, get_field(value, VIRT_PRIV_V)); - return register_write_direct(target, GDB_REGNO_DCSR, dcsr); - } else { - return register_write_direct(target, rid, value); - } - return ERROR_OK; + return register_write_direct(target, rid, value); } static int dm013_select_hart(struct target *target, int hart_index) @@ -4146,7 +4928,7 @@ static int dm013_select_hart(struct target *target, int hart_index) uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE; dmcontrol = set_dmcontrol_hartsel(dmcontrol, hart_index); - if (dmi_write(target, DM_DMCONTROL, dmcontrol) != ERROR_OK) { + if (dm_write(target, DM_DMCONTROL, dmcontrol) != ERROR_OK) { /* Who knows what the state is? */ dm->current_hartid = HART_INDEX_UNKNOWN; return ERROR_FAIL; @@ -4165,25 +4947,24 @@ static int select_prepped_harts(struct target *target) return ERROR_FAIL; if (!dm->hasel_supported) { r->prepped = false; - dm013_select_target(target); - return ERROR_OK; + return dm013_select_target(target); } assert(dm->hart_count); unsigned hawindow_count = (dm->hart_count + 31) / 32; - uint32_t hawindow[hawindow_count]; - - memset(hawindow, 0, sizeof(uint32_t) * hawindow_count); + uint32_t *hawindow = calloc(hawindow_count, sizeof(uint32_t)); + if (!hawindow) + return ERROR_FAIL; target_list_t *entry; unsigned total_selected = 0; unsigned int selected_index = 0; list_for_each_entry(entry, &dm->target_list, list) { struct target *t = entry->target; - riscv_info_t *info = riscv_info(t); + struct riscv_info *info = riscv_info(t); riscv013_info_t *info_013 = get_info(t); - unsigned index = info_013->index; - LOG_DEBUG("index=%d, coreid=%d, prepped=%d", index, t->coreid, info->prepped); + unsigned int index = info_013->index; + LOG_TARGET_DEBUG(target, "index=%d, prepped=%d", index, info->prepped); if (info->prepped) { info_013->selected = true; hawindow[index / 32] |= 1 << (index % 32); @@ -4195,22 +4976,31 @@ static int select_prepped_harts(struct target *target) if (total_selected == 0) { LOG_TARGET_ERROR(target, "No harts were prepped!"); + free(hawindow); return ERROR_FAIL; } else if (total_selected == 1) { /* Don't use hasel if we only need to talk to one hart. */ + free(hawindow); return dm013_select_hart(target, selected_index); } - if (dm013_select_hart(target, HART_INDEX_MULTIPLE) != ERROR_OK) + if (dm013_select_hart(target, HART_INDEX_MULTIPLE) != ERROR_OK) { + free(hawindow); return ERROR_FAIL; + } for (unsigned i = 0; i < hawindow_count; i++) { - if (dmi_write(target, DM_HAWINDOWSEL, i) != ERROR_OK) + if (dm_write(target, DM_HAWINDOWSEL, i) != ERROR_OK) { + free(hawindow); return ERROR_FAIL; - if (dmi_write(target, DM_HAWINDOW, hawindow[i]) != ERROR_OK) + } + if (dm_write(target, DM_HAWINDOW, hawindow[i]) != ERROR_OK) { + free(hawindow); return ERROR_FAIL; + } } + free(hawindow); return ERROR_OK; } @@ -4233,13 +5023,13 @@ static int riscv013_halt_go(struct target *target) /* Issue the halt command, and then wait for the current hart to halt. */ uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HALTREQ; dmcontrol = set_dmcontrol_hartsel(dmcontrol, dm->current_hartid); - dmi_write(target, DM_DMCONTROL, dmcontrol); + dm_write(target, DM_DMCONTROL, dmcontrol); uint32_t dmstatus; for (size_t i = 0; i < 256; ++i) { if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; /* When no harts are running, there's no point in continuing this loop. */ - if (!get_field(dmstatus, DM_DMSTATUS_ALLRUNNING)) + if (!get_field(dmstatus, DM_DMSTATUS_ANYRUNNING)) break; } @@ -4247,7 +5037,7 @@ static int riscv013_halt_go(struct target *target) * unavailable, though. */ if ((get_field(dmstatus, DM_DMSTATUS_ANYRUNNING))) { - if (dmi_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK) + if (dm_read(target, &dmcontrol, DM_DMCONTROL) != ERROR_OK) return ERROR_FAIL; LOG_TARGET_ERROR(target, "Unable to halt. dmcontrol=0x%08x, dmstatus=0x%08x", @@ -4256,18 +5046,50 @@ static int riscv013_halt_go(struct target *target) } dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HALTREQ, 0); - dmi_write(target, DM_DMCONTROL, dmcontrol); + dm_write(target, DM_DMCONTROL, dmcontrol); if (dm->current_hartid == HART_INDEX_MULTIPLE) { target_list_t *entry; list_for_each_entry(entry, &dm->target_list, list) { struct target *t = entry->target; - t->state = TARGET_HALTED; - if (t->debug_reason == DBG_REASON_NOTHALTED) - t->debug_reason = DBG_REASON_DBGRQ; + uint32_t t_dmstatus; + if (get_field(dmstatus, DM_DMSTATUS_ALLHALTED) || + get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) { + /* All harts are either halted or unavailable. No + * need to read dmstatus for each hart. */ + t_dmstatus = dmstatus; + } else { + /* Only some harts were halted/unavailable. Read + * dmstatus for this one to see what its status + * is. */ + riscv013_info_t *info = get_info(t); + dmcontrol = set_dmcontrol_hartsel(dmcontrol, info->index); + if (dm_write(target, DM_DMCONTROL, dmcontrol) != ERROR_OK) + return ERROR_FAIL; + dm->current_hartid = info->index; + if (dm_read(target, &t_dmstatus, DM_DMSTATUS) != ERROR_OK) + return ERROR_FAIL; + } + /* Set state for the current target based on its dmstatus. */ + if (get_field(t_dmstatus, DM_DMSTATUS_ALLHALTED)) { + t->state = TARGET_HALTED; + if (t->debug_reason == DBG_REASON_NOTHALTED) + t->debug_reason = DBG_REASON_DBGRQ; + } else if (get_field(t_dmstatus, DM_DMSTATUS_ALLUNAVAIL)) { + t->state = TARGET_UNAVAILABLE; + } + } + + } else { + /* Set state for the current target based on its dmstatus. */ + if (get_field(dmstatus, DM_DMSTATUS_ALLHALTED)) { + target->state = TARGET_HALTED; + if (target->debug_reason == DBG_REASON_NOTHALTED) + target->debug_reason = DBG_REASON_DBGRQ; + } else if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) { + target->state = TARGET_UNAVAILABLE; } } - /* The "else" case is handled in halt_go(). */ return ERROR_OK; } @@ -4287,6 +5109,7 @@ static int riscv013_step_current_hart(struct target *target) static int riscv013_resume_prep(struct target *target) { + assert(target->state == TARGET_HALTED); return riscv013_on_step_or_resume(target, false); } @@ -4295,42 +5118,6 @@ static int riscv013_on_step(struct target *target) return riscv013_on_step_or_resume(target, true); } -static int riscv013_on_halt(struct target *target) -{ - return ERROR_OK; -} - -static bool riscv013_is_halted(struct target *target) -{ - RISCV013_INFO(info); - - uint32_t dmstatus; - if (dm013_select_target(target) != ERROR_OK) - return false; - if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) - return false; - if (get_field(dmstatus, DM_DMSTATUS_ANYUNAVAIL)) - LOG_TARGET_ERROR(target, "Hart is unavailable."); - if (get_field(dmstatus, DM_DMSTATUS_ANYNONEXISTENT)) - LOG_TARGET_ERROR(target, "Hart doesn't exist."); - if (get_field(dmstatus, DM_DMSTATUS_ANYHAVERESET)) { - LOG_TARGET_INFO(target, "Hart unexpectedly reset!"); - /* TODO: Can we make this more obvious to eg. a gdb user? */ - uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | - DM_DMCONTROL_ACKHAVERESET; - dmcontrol = set_dmcontrol_hartsel(dmcontrol, info->index); - /* If we had been halted when we reset, request another halt. If we - * ended up running out of reset, then the user will (hopefully) get a - * message that a reset happened, that the target is running, and then - * that it is halted again once the request goes through. - */ - if (target->state == TARGET_HALTED) - dmcontrol |= DM_DMCONTROL_HALTREQ; - dmi_write(target, DM_DMCONTROL, dmcontrol); - } - return get_field(dmstatus, DM_DMSTATUS_ALLHALTED); -} - static enum riscv_halt_reason riscv013_halt_reason(struct target *target) { riscv_reg_t dcsr; @@ -4342,13 +5129,13 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) switch (get_field(dcsr, CSR_DCSR_CAUSE)) { case CSR_DCSR_CAUSE_EBREAK: - return RISCV_HALT_BREAKPOINT; + return RISCV_HALT_EBREAK; case CSR_DCSR_CAUSE_TRIGGER: /* We could get here before triggers are enumerated if a trigger was * already set when we connected. Force enumeration now, which has the * side effect of clearing any triggers we did not set. */ riscv_enumerate_triggers(target); - LOG_DEBUG("{%d} halted because of trigger", target->coreid); + LOG_TARGET_DEBUG(target, "halted because of trigger"); return RISCV_HALT_TRIGGER; case CSR_DCSR_CAUSE_STEP: return RISCV_HALT_SINGLESTEP; @@ -4359,38 +5146,42 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) return RISCV_HALT_GROUP; } - LOG_ERROR("Unknown DCSR cause field: 0x%" PRIx64, get_field(dcsr, CSR_DCSR_CAUSE)); - LOG_ERROR(" dcsr=0x%" PRIx32, (uint32_t) dcsr); + LOG_TARGET_ERROR(target, "Unknown DCSR cause field: 0x%" PRIx64, get_field(dcsr, CSR_DCSR_CAUSE)); + LOG_TARGET_ERROR(target, " dcsr=0x%" PRIx32, (uint32_t)dcsr); return RISCV_HALT_UNKNOWN; } -int riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) +static int riscv013_write_progbuf(struct target *target, unsigned int index, riscv_insn_t data) { dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; if (dm->progbuf_cache[index] != data) { - if (dmi_write(target, DM_PROGBUF0 + index, data) != ERROR_OK) + if (dm_write(target, DM_PROGBUF0 + index, data) != ERROR_OK) return ERROR_FAIL; dm->progbuf_cache[index] = data; } else { - LOG_DEBUG("cache hit for 0x%" PRIx32 " @%d", data, index); + LOG_TARGET_DEBUG(target, "Cache hit for 0x%" PRIx32 " @%d", data, index); } return ERROR_OK; } -riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index) +static riscv_insn_t riscv013_read_progbuf(struct target *target, unsigned int index) { uint32_t value; - dmi_read(target, &value, DM_PROGBUF0 + index); - return value; + if (dm_read(target, &value, DM_PROGBUF0 + index) == ERROR_OK) + return value; + else + return 0; } -int riscv013_invalidate_cached_debug_buffer(struct target *target) +static int riscv013_invalidate_cached_progbuf(struct target *target) { dm013_info_t *dm = get_dm(target); - if (!dm) + if (!dm) { + LOG_TARGET_DEBUG(target, "No DM is specified for the target"); return ERROR_FAIL; + } LOG_TARGET_DEBUG(target, "Invalidating progbuf cache"); for (unsigned int i = 0; i < 15; i++) @@ -4398,7 +5189,7 @@ int riscv013_invalidate_cached_debug_buffer(struct target *target) return ERROR_OK; } -int riscv013_execute_debug_buffer(struct target *target) +static int riscv013_execute_progbuf(struct target *target, uint32_t *cmderr) { uint32_t run_program = 0; run_program = set_field(run_program, AC_ACCESS_REGISTER_AARSIZE, 2); @@ -4406,10 +5197,10 @@ int riscv013_execute_debug_buffer(struct target *target) run_program = set_field(run_program, AC_ACCESS_REGISTER_TRANSFER, 0); run_program = set_field(run_program, AC_ACCESS_REGISTER_REGNO, 0x1000); - return execute_abstract_command(target, run_program); + return execute_abstract_command(target, run_program, cmderr); } -void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d) +static void riscv013_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d) { RISCV013_INFO(info); buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_WRITE); @@ -4417,7 +5208,7 @@ void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64 buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, a); } -void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a) +static void riscv013_fill_dmi_read(struct target *target, char *buf, uint64_t a) { RISCV013_INFO(info); buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_READ); @@ -4425,7 +5216,7 @@ void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a) buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, a); } -void riscv013_fill_dmi_nop_u64(struct target *target, char *buf) +static void riscv013_fill_dmi_nop(struct target *target, char *buf) { RISCV013_INFO(info); buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_NOP); @@ -4433,367 +5224,36 @@ void riscv013_fill_dmi_nop_u64(struct target *target, char *buf) buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, 0); } -/* Helper function for riscv013_test_sba_config_reg */ -static int get_max_sbaccess(struct target *target) -{ - RISCV013_INFO(info); - - uint32_t sbaccess128 = get_field(info->sbcs, DM_SBCS_SBACCESS128); - uint32_t sbaccess64 = get_field(info->sbcs, DM_SBCS_SBACCESS64); - uint32_t sbaccess32 = get_field(info->sbcs, DM_SBCS_SBACCESS32); - uint32_t sbaccess16 = get_field(info->sbcs, DM_SBCS_SBACCESS16); - uint32_t sbaccess8 = get_field(info->sbcs, DM_SBCS_SBACCESS8); - - if (sbaccess128) - return 4; - else if (sbaccess64) - return 3; - else if (sbaccess32) - return 2; - else if (sbaccess16) - return 1; - else if (sbaccess8) - return 0; - else - return -1; -} - -static uint32_t get_num_sbdata_regs(struct target *target) +static int riscv013_get_dmi_scan_length(struct target *target) { RISCV013_INFO(info); - - uint32_t sbaccess128 = get_field(info->sbcs, DM_SBCS_SBACCESS128); - uint32_t sbaccess64 = get_field(info->sbcs, DM_SBCS_SBACCESS64); - uint32_t sbaccess32 = get_field(info->sbcs, DM_SBCS_SBACCESS32); - - if (sbaccess128) - return 4; - else if (sbaccess64) - return 2; - else if (sbaccess32) - return 1; - else - return 0; -} - -static int riscv013_test_sba_config_reg(struct target *target, - target_addr_t legal_address, uint32_t num_words, - target_addr_t illegal_address, bool run_sbbusyerror_test) -{ - LOG_INFO("Testing System Bus Access as defined by RISC-V Debug Spec v0.13"); - - uint32_t tests_failed = 0; - - uint32_t rd_val; - uint32_t sbcs_orig; - dmi_read(target, &sbcs_orig, DM_SBCS); - - uint32_t sbcs = sbcs_orig; - bool test_passed; - - int max_sbaccess = get_max_sbaccess(target); - - if (max_sbaccess == -1) { - LOG_ERROR("System Bus Access not supported in this config."); - return ERROR_FAIL; - } - - if (get_field(sbcs, DM_SBCS_SBVERSION) != 1) { - LOG_ERROR("System Bus Access unsupported SBVERSION (%d). Only version 1 is supported.", - get_field(sbcs, DM_SBCS_SBVERSION)); - return ERROR_FAIL; - } - - uint32_t num_sbdata_regs = get_num_sbdata_regs(target); - assert(num_sbdata_regs); - - uint32_t rd_buf[num_sbdata_regs]; - - /* Test 1: Simple write/read test */ - test_passed = true; - sbcs = set_field(sbcs_orig, DM_SBCS_SBAUTOINCREMENT, 0); - dmi_write(target, DM_SBCS, sbcs); - - uint32_t test_patterns[4] = {0xdeadbeef, 0xfeedbabe, 0x12345678, 0x08675309}; - for (uint32_t sbaccess = 0; sbaccess <= (uint32_t)max_sbaccess; sbaccess++) { - sbcs = set_field(sbcs, DM_SBCS_SBACCESS, sbaccess); - dmi_write(target, DM_SBCS, sbcs); - - uint32_t compare_mask = (sbaccess == 0) ? 0xff : (sbaccess == 1) ? 0xffff : 0xffffffff; - - for (uint32_t i = 0; i < num_words; i++) { - uint32_t addr = legal_address + (i << sbaccess); - uint32_t wr_data[num_sbdata_regs]; - for (uint32_t j = 0; j < num_sbdata_regs; j++) - wr_data[j] = test_patterns[j] + i; - write_memory_sba_simple(target, addr, wr_data, num_sbdata_regs, sbcs); - } - - for (uint32_t i = 0; i < num_words; i++) { - uint32_t addr = legal_address + (i << sbaccess); - read_memory_sba_simple(target, addr, rd_buf, num_sbdata_regs, sbcs); - for (uint32_t j = 0; j < num_sbdata_regs; j++) { - if (((test_patterns[j]+i)&compare_mask) != (rd_buf[j]&compare_mask)) { - LOG_ERROR("System Bus Access Test 1: Error reading non-autoincremented address %x," - "expected val = %x, read val = %x", addr, test_patterns[j]+i, rd_buf[j]); - test_passed = false; - tests_failed++; - } - } - } - } - if (test_passed) - LOG_INFO("System Bus Access Test 1: Simple write/read test PASSED."); - - /* Test 2: Address autoincrement test */ - target_addr_t curr_addr; - target_addr_t prev_addr; - test_passed = true; - sbcs = set_field(sbcs_orig, DM_SBCS_SBAUTOINCREMENT, 1); - dmi_write(target, DM_SBCS, sbcs); - - for (uint32_t sbaccess = 0; sbaccess <= (uint32_t)max_sbaccess; sbaccess++) { - sbcs = set_field(sbcs, DM_SBCS_SBACCESS, sbaccess); - dmi_write(target, DM_SBCS, sbcs); - - dmi_write(target, DM_SBADDRESS0, legal_address); - read_sbcs_nonbusy(target, &sbcs); - curr_addr = legal_address; - for (uint32_t i = 0; i < num_words; i++) { - prev_addr = curr_addr; - read_sbcs_nonbusy(target, &sbcs); - curr_addr = sb_read_address(target); - if ((curr_addr - prev_addr != (uint32_t)(1 << sbaccess)) && (i != 0)) { - LOG_ERROR("System Bus Access Test 2: Error with address auto-increment, sbaccess = %x.", sbaccess); - test_passed = false; - tests_failed++; - } - dmi_write(target, DM_SBDATA0, i); - } - - read_sbcs_nonbusy(target, &sbcs); - - dmi_write(target, DM_SBADDRESS0, legal_address); - - uint32_t val; - sbcs = set_field(sbcs, DM_SBCS_SBREADONDATA, 1); - dmi_write(target, DM_SBCS, sbcs); - dmi_read(target, &val, DM_SBDATA0); /* Dummy read to trigger first system bus read */ - curr_addr = legal_address; - for (uint32_t i = 0; i < num_words; i++) { - prev_addr = curr_addr; - read_sbcs_nonbusy(target, &sbcs); - curr_addr = sb_read_address(target); - if ((curr_addr - prev_addr != (uint32_t)(1 << sbaccess)) && (i != 0)) { - LOG_ERROR("System Bus Access Test 2: Error with address auto-increment, sbaccess = %x", sbaccess); - test_passed = false; - tests_failed++; - } - dmi_read(target, &val, DM_SBDATA0); - read_sbcs_nonbusy(target, &sbcs); - if (i != val) { - LOG_ERROR("System Bus Access Test 2: Error reading auto-incremented address," - "expected val = %x, read val = %x.", i, val); - test_passed = false; - tests_failed++; - } - } - } - if (test_passed) - LOG_INFO("System Bus Access Test 2: Address auto-increment test PASSED."); - - /* Test 3: Read from illegal address */ - read_memory_sba_simple(target, illegal_address, rd_buf, 1, sbcs_orig); - - dmi_read(target, &rd_val, DM_SBCS); - if (get_field(rd_val, DM_SBCS_SBERROR) == 2) { - sbcs = set_field(sbcs_orig, DM_SBCS_SBERROR, 2); - dmi_write(target, DM_SBCS, sbcs); - dmi_read(target, &rd_val, DM_SBCS); - if (get_field(rd_val, DM_SBCS_SBERROR) == 0) - LOG_INFO("System Bus Access Test 3: Illegal address read test PASSED."); - else - LOG_ERROR("System Bus Access Test 3: Illegal address read test FAILED, unable to clear to 0."); - } else { - LOG_ERROR("System Bus Access Test 3: Illegal address read test FAILED, unable to set error code."); - } - - /* Test 4: Write to illegal address */ - write_memory_sba_simple(target, illegal_address, test_patterns, 1, sbcs_orig); - - dmi_read(target, &rd_val, DM_SBCS); - if (get_field(rd_val, DM_SBCS_SBERROR) == 2) { - sbcs = set_field(sbcs_orig, DM_SBCS_SBERROR, 2); - dmi_write(target, DM_SBCS, sbcs); - dmi_read(target, &rd_val, DM_SBCS); - if (get_field(rd_val, DM_SBCS_SBERROR) == 0) - LOG_INFO("System Bus Access Test 4: Illegal address write test PASSED."); - else { - LOG_ERROR("System Bus Access Test 4: Illegal address write test FAILED, unable to clear to 0."); - tests_failed++; - } - } else { - LOG_ERROR("System Bus Access Test 4: Illegal address write test FAILED, unable to set error code."); - tests_failed++; - } - - /* Test 5: Write with unsupported sbaccess size */ - uint32_t sbaccess128 = get_field(sbcs_orig, DM_SBCS_SBACCESS128); - - if (sbaccess128) { - LOG_INFO("System Bus Access Test 5: SBCS sbaccess error test PASSED, all sbaccess sizes supported."); - } else { - sbcs = set_field(sbcs_orig, DM_SBCS_SBACCESS, 4); - - write_memory_sba_simple(target, legal_address, test_patterns, 1, sbcs); - - dmi_read(target, &rd_val, DM_SBCS); - if (get_field(rd_val, DM_SBCS_SBERROR) == 4) { - sbcs = set_field(sbcs_orig, DM_SBCS_SBERROR, 4); - dmi_write(target, DM_SBCS, sbcs); - dmi_read(target, &rd_val, DM_SBCS); - if (get_field(rd_val, DM_SBCS_SBERROR) == 0) - LOG_INFO("System Bus Access Test 5: SBCS sbaccess error test PASSED."); - else { - LOG_ERROR("System Bus Access Test 5: SBCS sbaccess error test FAILED, unable to clear to 0."); - tests_failed++; - } - } else { - LOG_ERROR("System Bus Access Test 5: SBCS sbaccess error test FAILED, unable to set error code."); - tests_failed++; - } - } - - /* Test 6: Write to misaligned address */ - sbcs = set_field(sbcs_orig, DM_SBCS_SBACCESS, 1); - - write_memory_sba_simple(target, legal_address+1, test_patterns, 1, sbcs); - - dmi_read(target, &rd_val, DM_SBCS); - if (get_field(rd_val, DM_SBCS_SBERROR) == 3) { - sbcs = set_field(sbcs_orig, DM_SBCS_SBERROR, 3); - dmi_write(target, DM_SBCS, sbcs); - dmi_read(target, &rd_val, DM_SBCS); - if (get_field(rd_val, DM_SBCS_SBERROR) == 0) - LOG_INFO("System Bus Access Test 6: SBCS address alignment error test PASSED"); - else { - LOG_ERROR("System Bus Access Test 6: SBCS address alignment error test FAILED, unable to clear to 0."); - tests_failed++; - } - } else { - LOG_ERROR("System Bus Access Test 6: SBCS address alignment error test FAILED, unable to set error code."); - tests_failed++; - } - - /* Test 7: Set sbbusyerror, only run this case in simulation as it is likely - * impossible to hit otherwise */ - if (run_sbbusyerror_test) { - sbcs = set_field(sbcs_orig, DM_SBCS_SBREADONADDR, 1); - dmi_write(target, DM_SBCS, sbcs); - - for (int i = 0; i < 16; i++) - dmi_write(target, DM_SBDATA0, 0xdeadbeef); - - for (int i = 0; i < 16; i++) - dmi_write(target, DM_SBADDRESS0, legal_address); - - dmi_read(target, &rd_val, DM_SBCS); - if (get_field(rd_val, DM_SBCS_SBBUSYERROR)) { - sbcs = set_field(sbcs_orig, DM_SBCS_SBBUSYERROR, 1); - dmi_write(target, DM_SBCS, sbcs); - dmi_read(target, &rd_val, DM_SBCS); - if (get_field(rd_val, DM_SBCS_SBBUSYERROR) == 0) - LOG_INFO("System Bus Access Test 7: SBCS sbbusyerror test PASSED."); - else { - LOG_ERROR("System Bus Access Test 7: SBCS sbbusyerror test FAILED, unable to clear to 0."); - tests_failed++; - } - } else { - LOG_ERROR("System Bus Access Test 7: SBCS sbbusyerror test FAILED, unable to set error code."); - tests_failed++; - } - } - - if (tests_failed == 0) { - LOG_INFO("ALL TESTS PASSED"); - return ERROR_OK; - } else { - LOG_ERROR("%d TESTS FAILED", tests_failed); - return ERROR_FAIL; - } - + return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH; } -void write_memory_sba_simple(struct target *target, target_addr_t addr, - uint32_t *write_data, uint32_t write_size, uint32_t sbcs) +void riscv013_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d) { - RISCV013_INFO(info); - - uint32_t rd_sbcs; - uint32_t masked_addr; - - uint32_t sba_size = get_field(info->sbcs, DM_SBCS_SBASIZE); - - read_sbcs_nonbusy(target, &rd_sbcs); - - uint32_t sbcs_no_readonaddr = set_field(sbcs, DM_SBCS_SBREADONADDR, 0); - dmi_write(target, DM_SBCS, sbcs_no_readonaddr); - - for (uint32_t i = 0; i < sba_size/32; i++) { - masked_addr = (addr >> 32*i) & 0xffffffff; - - if (i != 3) - dmi_write(target, DM_SBADDRESS0+i, masked_addr); - else - dmi_write(target, DM_SBADDRESS3, masked_addr); - } - - /* Write SBDATA registers starting with highest address, since write to - * SBDATA0 triggers write */ - for (int i = write_size-1; i >= 0; i--) - dmi_write(target, DM_SBDATA0+i, write_data[i]); + dm013_info_t *dm = get_dm(target); + if (!dm) + return; + riscv013_fill_dmi_write(target, buf, a + dm->base, d); } -void read_memory_sba_simple(struct target *target, target_addr_t addr, - uint32_t *rd_buf, uint32_t read_size, uint32_t sbcs) +void riscv013_fill_dm_read(struct target *target, char *buf, uint64_t a) { - RISCV013_INFO(info); - - uint32_t rd_sbcs; - uint32_t masked_addr; - - uint32_t sba_size = get_field(info->sbcs, DM_SBCS_SBASIZE); - - read_sbcs_nonbusy(target, &rd_sbcs); - - uint32_t sbcs_readonaddr = set_field(sbcs, DM_SBCS_SBREADONADDR, 1); - dmi_write(target, DM_SBCS, sbcs_readonaddr); - - /* Write addresses starting with highest address register */ - for (int i = sba_size/32-1; i >= 0; i--) { - masked_addr = (addr >> 32*i) & 0xffffffff; - - if (i != 3) - dmi_write(target, DM_SBADDRESS0+i, masked_addr); - else - dmi_write(target, DM_SBADDRESS3, masked_addr); - } - - read_sbcs_nonbusy(target, &rd_sbcs); - - for (uint32_t i = 0; i < read_size; i++) - dmi_read(target, &(rd_buf[i]), DM_SBDATA0+i); + dm013_info_t *dm = get_dm(target); + if (!dm) + return; + riscv013_fill_dmi_read(target, buf, a + dm->base); } -int riscv013_dmi_write_u64_bits(struct target *target) +void riscv013_fill_dm_nop(struct target *target, char *buf) { - RISCV013_INFO(info); - return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH; + riscv013_fill_dmi_nop(target, buf); } static int maybe_execute_fence_i(struct target *target) { - if (has_sufficient_progbuf(target, 3)) + if (has_sufficient_progbuf(target, 2)) return execute_fence(target); return ERROR_OK; } @@ -4804,17 +5264,9 @@ static int riscv013_on_step_or_resume(struct target *target, bool step) if (maybe_execute_fence_i(target) != ERROR_OK) return ERROR_FAIL; - /* We want to twiddle some bits in the debug CSR so debugging works. */ - riscv_reg_t dcsr; - int result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR); - if (result != ERROR_OK) - return result; - dcsr = set_field(dcsr, CSR_DCSR_STEP, step); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, riscv_ebreakm); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, riscv_ebreaks); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, riscv_ebreaku); - if (riscv_set_register(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK) + if (set_dcsr_ebreak(target, step) != ERROR_OK) return ERROR_FAIL; + if (riscv_flush_registers(target) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; @@ -4836,7 +5288,7 @@ static int riscv013_step_or_resume_current_hart(struct target *target, /* Issue the resume command, and then wait for the current hart to resume. */ uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ; dmcontrol = set_dmcontrol_hartsel(dmcontrol, dm->current_hartid); - dmi_write(target, DM_DMCONTROL, dmcontrol); + dm_write(target, DM_DMCONTROL, dmcontrol); dmcontrol = set_field(dmcontrol, DM_DMCONTROL_RESUMEREQ, 0); @@ -4845,16 +5297,18 @@ static int riscv013_step_or_resume_current_hart(struct target *target, usleep(10); if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; + if (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL)) + return ERROR_FAIL; if (get_field(dmstatus, DM_DMSTATUS_ALLRESUMEACK) == 0) continue; if (step && get_field(dmstatus, DM_DMSTATUS_ALLHALTED) == 0) continue; - dmi_write(target, DM_DMCONTROL, dmcontrol); + dm_write(target, DM_DMCONTROL, dmcontrol); return ERROR_OK; } - dmi_write(target, DM_DMCONTROL, dmcontrol); + dm_write(target, DM_DMCONTROL, dmcontrol); LOG_TARGET_ERROR(target, "unable to resume"); if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) @@ -4862,7 +5316,7 @@ static int riscv013_step_or_resume_current_hart(struct target *target, LOG_TARGET_ERROR(target, " dmstatus=0x%08x", dmstatus); if (step) { - LOG_ERROR(" was stepping, halting"); + LOG_TARGET_ERROR(target, " was stepping, halting"); riscv_halt(target); return ERROR_OK; } @@ -4870,24 +5324,12 @@ static int riscv013_step_or_resume_current_hart(struct target *target, return ERROR_FAIL; } -void riscv013_clear_abstract_error(struct target *target) +static int riscv013_clear_abstract_error(struct target *target) { - /* Wait for busy to go away. */ - time_t start = time(NULL); uint32_t abstractcs; - dmi_read(target, &abstractcs, DM_ABSTRACTCS); - while (get_field(abstractcs, DM_ABSTRACTCS_BUSY)) { - dmi_read(target, &abstractcs, DM_ABSTRACTCS); - - if (time(NULL) - start > riscv_command_timeout_sec) { - LOG_ERROR("abstractcs.busy is not going low after %d seconds " - "(abstractcs=0x%x). The target is either really slow or " - "broken. You could increase the timeout with riscv " - "set_command_timeout_sec.", - riscv_command_timeout_sec, abstractcs); - break; - } - } - /* Clear the error status. */ - dmi_write(target, DM_ABSTRACTCS, DM_ABSTRACTCS_CMDERR); + int result = wait_for_idle(target, &abstractcs); + /* Clear the error status, even if busy is still set. */ + if (dm_write(target, DM_ABSTRACTCS, DM_ABSTRACTCS_CMDERR) != ERROR_OK) + result = ERROR_FAIL; + return result; } diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index dfc22af1f1..b323b4db49 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later #include <assert.h> #include <stdlib.h> @@ -20,13 +20,12 @@ #include "helper/base64.h" #include "helper/time_support.h" #include "riscv.h" +#include "program.h" #include "gdb_regs.h" #include "rtos/rtos.h" #include "debug_defines.h" #include <helper/bits.h> - -#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) -#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) +#include "field_helpers.h" /*** JTAG registers. ***/ @@ -35,38 +34,38 @@ #define DBUS 0x11 -uint8_t ir_dtmcontrol[4] = {DTMCONTROL}; +static uint8_t ir_dtmcontrol[4] = {DTMCONTROL}; struct scan_field select_dtmcontrol = { .in_value = NULL, .out_value = ir_dtmcontrol }; -uint8_t ir_dbus[4] = {DBUS}; +static uint8_t ir_dbus[4] = {DBUS}; struct scan_field select_dbus = { .in_value = NULL, .out_value = ir_dbus }; -uint8_t ir_idcode[4] = {0x1}; +static uint8_t ir_idcode[4] = {0x1}; struct scan_field select_idcode = { .in_value = NULL, .out_value = ir_idcode }; -bscan_tunnel_type_t bscan_tunnel_type; +static bscan_tunnel_type_t bscan_tunnel_type; int bscan_tunnel_ir_width; /* if zero, then tunneling is not present/active */ static int bscan_tunnel_ir_id; /* IR ID of the JTAG TAP to access the tunnel. Valid when not 0 */ static const uint8_t bscan_zero[4] = {0}; static const uint8_t bscan_one[4] = {1}; -uint8_t ir_user4[4]; -struct scan_field select_user4 = { +static uint8_t ir_user4[4]; +static struct scan_field select_user4 = { .in_value = NULL, .out_value = ir_user4 }; -uint8_t bscan_tunneled_ir_width[4] = {5}; /* overridden by assignment in riscv_init_target */ -struct scan_field _bscan_tunnel_data_register_select_dmi[] = { +static uint8_t bscan_tunneled_ir_width[4] = {5}; /* overridden by assignment in riscv_init_target */ +static struct scan_field _bscan_tunnel_data_register_select_dmi[] = { { .num_bits = 3, .out_value = bscan_zero, @@ -89,7 +88,7 @@ struct scan_field _bscan_tunnel_data_register_select_dmi[] = { } }; -struct scan_field _bscan_tunnel_nested_tap_select_dmi[] = { +static struct scan_field _bscan_tunnel_nested_tap_select_dmi[] = { { .num_bits = 1, .out_value = bscan_zero, @@ -111,31 +110,39 @@ struct scan_field _bscan_tunnel_nested_tap_select_dmi[] = { .in_value = NULL, } }; -struct scan_field *bscan_tunnel_nested_tap_select_dmi = _bscan_tunnel_nested_tap_select_dmi; -uint32_t bscan_tunnel_nested_tap_select_dmi_num_fields = ARRAY_SIZE(_bscan_tunnel_nested_tap_select_dmi); +static struct scan_field *bscan_tunnel_nested_tap_select_dmi = _bscan_tunnel_nested_tap_select_dmi; +static uint32_t bscan_tunnel_nested_tap_select_dmi_num_fields = ARRAY_SIZE(_bscan_tunnel_nested_tap_select_dmi); -struct scan_field *bscan_tunnel_data_register_select_dmi = _bscan_tunnel_data_register_select_dmi; -uint32_t bscan_tunnel_data_register_select_dmi_num_fields = ARRAY_SIZE(_bscan_tunnel_data_register_select_dmi); +static struct scan_field *bscan_tunnel_data_register_select_dmi = _bscan_tunnel_data_register_select_dmi; +static uint32_t bscan_tunnel_data_register_select_dmi_num_fields = ARRAY_SIZE(_bscan_tunnel_data_register_select_dmi); struct trigger { uint64_t address; uint32_t length; uint64_t mask; uint64_t value; - bool read, write, execute; + bool is_read, is_write, is_execute; int unique_id; }; +struct tdata2_cache { + struct list_head elem_tdata2; + riscv_reg_t tdata2; +}; + +struct tdata1_cache { + riscv_reg_t tdata1; + struct list_head tdata2_cache_head; + struct list_head elem_tdata1; +}; + /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ int riscv_command_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC; /* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC; -bool riscv_enable_virt2phys = true; -bool riscv_ebreakm = true; -bool riscv_ebreaks = true; -bool riscv_ebreaku = true; +static bool riscv_enable_virt2phys = true; bool riscv_enable_virtual; @@ -144,7 +151,7 @@ static enum { RO_REVERSED } resume_order; -const virt2phys_info_t sv32 = { +static const virt2phys_info_t sv32 = { .name = "Sv32", .va_bits = 32, .level = 2, @@ -157,7 +164,20 @@ const virt2phys_info_t sv32 = { .pa_ppn_mask = {0x3ff, 0xfff}, }; -const virt2phys_info_t sv39 = { +static const virt2phys_info_t sv32x4 = { + .name = "Sv32x4", + .va_bits = 34, + .level = 2, + .pte_shift = 2, + .vpn_shift = {12, 22}, + .vpn_mask = {0x3ff, 0xfff}, + .pte_ppn_shift = {10, 20}, + .pte_ppn_mask = {0x3ff, 0xfff}, + .pa_ppn_shift = {12, 22}, + .pa_ppn_mask = {0x3ff, 0xfff}, +}; + +static const virt2phys_info_t sv39 = { .name = "Sv39", .va_bits = 39, .level = 3, @@ -170,7 +190,20 @@ const virt2phys_info_t sv39 = { .pa_ppn_mask = {0x1ff, 0x1ff, 0x3ffffff}, }; -const virt2phys_info_t sv48 = { +static const virt2phys_info_t sv39x4 = { + .name = "Sv39x4", + .va_bits = 41, + .level = 3, + .pte_shift = 3, + .vpn_shift = {12, 21, 30}, + .vpn_mask = {0x1ff, 0x1ff, 0x7ff}, + .pte_ppn_shift = {10, 19, 28}, + .pte_ppn_mask = {0x1ff, 0x1ff, 0x3ffffff}, + .pa_ppn_shift = {12, 21, 30}, + .pa_ppn_mask = {0x1ff, 0x1ff, 0x3ffffff}, +}; + +static const virt2phys_info_t sv48 = { .name = "Sv48", .va_bits = 48, .level = 4, @@ -183,7 +216,51 @@ const virt2phys_info_t sv48 = { .pa_ppn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ffff}, }; -void riscv_sample_buf_maybe_add_timestamp(struct target *target, bool before) +static const virt2phys_info_t sv48x4 = { + .name = "Sv48x4", + .va_bits = 50, + .level = 4, + .pte_shift = 3, + .vpn_shift = {12, 21, 30, 39}, + .vpn_mask = {0x1ff, 0x1ff, 0x1ff, 0x7ff}, + .pte_ppn_shift = {10, 19, 28, 37}, + .pte_ppn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ffff}, + .pa_ppn_shift = {12, 21, 30, 39}, + .pa_ppn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ffff}, +}; + +static const virt2phys_info_t sv57 = { + .name = "Sv57", + .va_bits = 57, + .level = 5, + .pte_shift = 3, + .vpn_shift = {12, 21, 30, 39, 48}, + .vpn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ff, 0x1ff}, + .pte_ppn_shift = {10, 19, 28, 37, 46}, + .pte_ppn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ff, 0xff}, + .pa_ppn_shift = {12, 21, 30, 39, 48}, + .pa_ppn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ff, 0xff}, +}; + +static const virt2phys_info_t sv57x4 = { + .name = "Sv57x4", + .va_bits = 59, + .level = 5, + .pte_shift = 3, + .vpn_shift = {12, 21, 30, 39, 48}, + .vpn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ff, 0x7ff}, + .pte_ppn_shift = {10, 19, 28, 37, 46}, + .pte_ppn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ff, 0xff}, + .pa_ppn_shift = {12, 21, 30, 39, 48}, + .pa_ppn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ff, 0xff}, +}; + +static enum riscv_halt_reason riscv_halt_reason(struct target *target); +static void riscv_info_init(struct target *target, struct riscv_info *r); +static void riscv_invalidate_register_cache(struct target *target); +static int riscv_step_rtos_hart(struct target *target); + +static void riscv_sample_buf_maybe_add_timestamp(struct target *target, bool before) { RISCV_INFO(r); uint32_t now = timeval_ms() & 0xffffffff; @@ -212,7 +289,7 @@ void select_dmi_via_bscan(struct target *target) bscan_tunnel_nested_tap_select_dmi, TAP_IDLE); } -uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out) +int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ptr) { /* On BSCAN TAP: Select IR=USER4, issue tunneled IR scan via BSCAN TAP's DR */ uint8_t tunneled_ir_width[4] = {bscan_tunnel_ir_width}; @@ -293,18 +370,19 @@ uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out) uint32_t in = buf_get_u32(in_value, 1, 32); LOG_DEBUG("DTMCS: 0x%x -> 0x%x", out, in); - return in; + if (in_ptr) + *in_ptr = in; + return ERROR_OK; } -static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) +static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr) { struct scan_field field; uint8_t in_value[4]; uint8_t out_value[4] = { 0 }; if (bscan_tunnel_ir_width != 0) - return dtmcontrol_scan_via_bscan(target, out); - + return dtmcontrol_scan_via_bscan(target, out, in_ptr); buf_set_u32(out_value, 0, 32, out); @@ -320,43 +398,46 @@ static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) int retval = jtag_execute_queue(); if (retval != ERROR_OK) { - LOG_ERROR("failed jtag scan: %d", retval); + LOG_TARGET_ERROR(target, "dtmcontrol scan failed, error code = %d", retval); return retval; } uint32_t in = buf_get_u32(field.in_value, 0, 32); LOG_DEBUG("DTMCONTROL: 0x%x -> 0x%x", out, in); - return in; + if (in_ptr) + *in_ptr = in; + return ERROR_OK; } static struct target_type *get_target_type(struct target *target) { - riscv_info_t *info = (riscv_info_t *) target->arch_info; - - if (!info) { - LOG_ERROR("Target has not been initialized"); + if (!target->arch_info) { + LOG_TARGET_ERROR(target, "Target has not been initialized."); return NULL; } + RISCV_INFO(info); switch (info->dtm_version) { - case 0: + case DTM_DTMCS_VERSION_0_11: return &riscv011_target; - case 1: + case DTM_DTMCS_VERSION_1_0: return &riscv013_target; default: - LOG_ERROR("[%s] Unsupported DTM version: %d", - target_name(target), info->dtm_version); + /* TODO: once we have proper support for non-examined targets + * we should have an assert here */ + LOG_TARGET_ERROR(target, "Unsupported DTM version: %d", + info->dtm_version); return NULL; } } static int riscv_create_target(struct target *target, Jim_Interp *interp) { - LOG_DEBUG("riscv_create_target()"); - target->arch_info = calloc(1, sizeof(riscv_info_t)); + LOG_TARGET_DEBUG(target, "riscv_create_target()"); + target->arch_info = calloc(1, sizeof(struct riscv_info)); if (!target->arch_info) { - LOG_ERROR("Failed to allocate RISC-V target structure."); + LOG_TARGET_ERROR(target, "Failed to allocate RISC-V target structure."); return ERROR_FAIL; } riscv_info_init(target, target->arch_info); @@ -366,7 +447,7 @@ static int riscv_create_target(struct target *target, Jim_Interp *interp) static int riscv_init_target(struct command_context *cmd_ctx, struct target *target) { - LOG_DEBUG("riscv_init_target()"); + LOG_TARGET_DEBUG(target, "riscv_init_target()"); RISCV_INFO(info); info->cmd_ctx = cmd_ctx; @@ -381,10 +462,7 @@ static int riscv_init_target(struct command_context *cmd_ctx, assert(target->tap->ir_length >= 6); ir_user4_raw = 0x23 << (target->tap->ir_length - 6); } - ir_user4[0] = (uint8_t)ir_user4_raw; - ir_user4[1] = (uint8_t)(ir_user4_raw >>= 8); - ir_user4[2] = (uint8_t)(ir_user4_raw >>= 8); - ir_user4[3] = (uint8_t)(ir_user4_raw >>= 8); + h_u32_to_le(ir_user4, ir_user4_raw); select_user4.num_bits = target->tap->ir_length; bscan_tunneled_ir_width[0] = bscan_tunnel_ir_width; if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) @@ -414,25 +492,71 @@ static void riscv_free_registers(struct target *target) free(target->reg_cache->reg_list); } free(target->reg_cache); + target->reg_cache = NULL; + } +} + +static void free_reg_names(struct target *target); + +static void free_custom_register_names(struct target *target) +{ + RISCV_INFO(info); + + if (!info->custom_register_names.reg_names) + return; + + for (unsigned int i = 0; i < info->custom_register_names.num_entries; i++) + free(info->custom_register_names.reg_names[i]); + free(info->custom_register_names.reg_names); + info->custom_register_names.reg_names = NULL; +} + +static void free_wp_triggers_cache(struct target *target) +{ + RISCV_INFO(r); + + for (unsigned int i = 0; i < r->trigger_count; ++i) { + struct tdata1_cache *elem_1, *tmp_1; + list_for_each_entry_safe(elem_1, tmp_1, &r->wp_triggers_negative_cache[i], elem_tdata1) { + struct tdata2_cache *elem_2, *tmp_2; + list_for_each_entry_safe(elem_2, tmp_2, &elem_1->tdata2_cache_head, elem_tdata2) { + list_del(&elem_2->elem_tdata2); + free(elem_2); + } + list_del(&elem_1->elem_tdata1); + free(elem_1); + } } + free(r->wp_triggers_negative_cache); } static void riscv_deinit_target(struct target *target) { - LOG_DEBUG("riscv_deinit_target()"); + LOG_TARGET_DEBUG(target, "riscv_deinit_target()"); - riscv_info_t *info = target->arch_info; + struct riscv_info *info = target->arch_info; struct target_type *tt = get_target_type(target); + if (!tt) + LOG_TARGET_ERROR(target, "Could not identify target type."); if (riscv_flush_registers(target) != ERROR_OK) - LOG_ERROR("[%s] Failed to flush registers. Ignoring this error.", target_name(target)); + LOG_TARGET_ERROR(target, "Failed to flush registers. Ignoring this error."); - if (tt && info->version_specific) + if (tt && info && info->version_specific) tt->deinit_target(target); riscv_free_registers(target); + free_wp_triggers_cache(target); + + if (!info) + return; range_list_t *entry, *tmp; + list_for_each_entry_safe(entry, tmp, &info->hide_csr, list) { + free(entry->name); + free(entry); + } + list_for_each_entry_safe(entry, tmp, &info->expose_csr, list) { free(entry->name); free(entry); @@ -443,7 +567,7 @@ static void riscv_deinit_target(struct target *target) free(entry); } - free(info->reg_names); + free_reg_names(target); free(target->arch_info); target->arch_info = NULL; @@ -455,16 +579,121 @@ static void trigger_from_breakpoint(struct trigger *trigger, trigger->address = breakpoint->address; trigger->length = breakpoint->length; trigger->mask = ~0LL; - trigger->read = false; - trigger->write = false; - trigger->execute = true; + trigger->is_read = false; + trigger->is_write = false; + trigger->is_execute = true; /* unique_id is unique across both breakpoints and watchpoints. */ trigger->unique_id = breakpoint->unique_id; } -static int maybe_add_trigger_t1(struct target *target, - struct trigger *trigger, uint64_t tdata1) +static bool can_use_napot_match(struct trigger *trigger) +{ + riscv_reg_t addr = trigger->address; + riscv_reg_t size = trigger->length; + bool size_power_of_2 = (size & (size - 1)) == 0; + bool addr_aligned = (addr & (size - 1)) == 0; + return size > 1 && size_power_of_2 && addr_aligned; +} + +/* Find the next free trigger of the given type, without talking to the target. */ +static int find_next_free_trigger(struct target *target, int type, bool chained, + unsigned int *idx) +{ + assert(idx); + RISCV_INFO(r); + + unsigned int num_found = 0; + unsigned int num_required = chained ? 2 : 1; + + for (unsigned int i = *idx; i < r->trigger_count; i++) { + if (r->trigger_unique_id[i] == -1) { + if (r->trigger_tinfo[i] & (1 << type)) { + num_found++; + if (num_required == num_found) { + /* Found num_required consecutive free triggers - success, done. */ + *idx = i - (num_required - 1); + LOG_TARGET_DEBUG(target, + "%d trigger(s) of type %d found on index %u, " + "chained == %s", + num_required, type, *idx, + chained ? "true" : "false"); + return ERROR_OK; + } + /* Found a trigger but need more consecutive ones */ + continue; + } + } + /* Trigger already occupied or incompatible type. + * Reset the counter of found consecutive triggers */ + num_found = 0; + } + + return ERROR_FAIL; +} + +static int find_first_trigger_by_id(struct target *target, int unique_id) +{ + RISCV_INFO(r); + + for (unsigned int i = 0; i < r->trigger_count; i++) { + if (r->trigger_unique_id[i] == unique_id) + return i; + } + return -1; +} + +static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdata1, riscv_reg_t tdata2, + riscv_reg_t tdata1_ignore_mask) +{ + riscv_reg_t tdata1_rb, tdata2_rb; + // Select which trigger to use + if (riscv_set_register(target, GDB_REGNO_TSELECT, idx) != ERROR_OK) + return ERROR_FAIL; + + // Disable the trigger by writing 0 to it + if (riscv_set_register(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) + return ERROR_FAIL; + + // Set trigger data for tdata2 (and tdata3 if it was supported) + if (riscv_set_register(target, GDB_REGNO_TDATA2, tdata2) != ERROR_OK) + return ERROR_FAIL; + + // Set trigger data for tdata1 + if (riscv_set_register(target, GDB_REGNO_TDATA1, tdata1) != ERROR_OK) + return ERROR_FAIL; + + // Read back tdata1, tdata2, (tdata3), and check if the configuration is supported + if (riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK) + return ERROR_FAIL; + if (riscv_get_register(target, &tdata2_rb, GDB_REGNO_TDATA2) != ERROR_OK) + return ERROR_FAIL; + bool tdata1_config_denied = (tdata1 & ~tdata1_ignore_mask) != (tdata1_rb & ~tdata1_ignore_mask); + bool tdata2_config_denied = tdata2 != tdata2_rb; + if (tdata1_config_denied || tdata2_config_denied) { + LOG_TARGET_DEBUG(target, "Trigger %u doesn't support what we need.", idx); + + if (tdata1_config_denied) + LOG_TARGET_DEBUG(target, + "After writing 0x%" PRIx64 " to tdata1 it contains 0x%" PRIx64 "; tdata1_ignore_mask=0x%" PRIx64, + tdata1, tdata1_rb, tdata1_ignore_mask); + + if (tdata2_config_denied) + LOG_TARGET_DEBUG(target, + "wrote 0x%" PRIx64 " to tdata2 but read back 0x%" PRIx64, + tdata2, tdata2_rb); + if (riscv_set_register(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) + return ERROR_FAIL; + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + return ERROR_OK; +} + +static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger) { + int ret; + riscv_reg_t tdata1, tdata2; + RISCV_INFO(r); const uint32_t bpcontrol_x = 1<<0; @@ -477,203 +706,564 @@ static int maybe_add_trigger_t1(struct target *target, const uint32_t bpcontrol_bpmatch = 0xf << 7; const uint32_t bpcontrol_bpaction = 0xff << 11; + unsigned int idx = 0; + ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_LEGACY, false, &idx); + if (ret != ERROR_OK) + return ret; + + if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) + return ERROR_FAIL; if (tdata1 & (bpcontrol_r | bpcontrol_w | bpcontrol_x)) { /* Trigger is already in use, presumably by user code. */ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - tdata1 = set_field(tdata1, bpcontrol_r, trigger->read); - tdata1 = set_field(tdata1, bpcontrol_w, trigger->write); - tdata1 = set_field(tdata1, bpcontrol_x, trigger->execute); - tdata1 = set_field(tdata1, bpcontrol_u, - !!(r->misa & BIT('U' - 'A'))); - tdata1 = set_field(tdata1, bpcontrol_s, - !!(r->misa & BIT('S' - 'A'))); - tdata1 = set_field(tdata1, bpcontrol_h, - !!(r->misa & BIT('H' - 'A'))); - tdata1 |= bpcontrol_m; - tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); /* exact match */ + tdata1 = 0; + tdata1 = set_field(tdata1, bpcontrol_r, trigger->is_read); + tdata1 = set_field(tdata1, bpcontrol_w, trigger->is_write); + tdata1 = set_field(tdata1, bpcontrol_x, trigger->is_execute); + tdata1 = set_field(tdata1, bpcontrol_u, !!(r->misa & BIT('U' - 'A'))); + tdata1 = set_field(tdata1, bpcontrol_s, !!(r->misa & BIT('S' - 'A'))); + tdata1 = set_field(tdata1, bpcontrol_h, !!(r->misa & BIT('H' - 'A'))); + tdata1 = set_field(tdata1, bpcontrol_m, 1); tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); /* cause bp exception */ + tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); /* exact match */ + tdata2 = trigger->address; + ret = set_trigger(target, idx, tdata1, tdata2, 0); + if (ret != ERROR_OK) + return ret; + r->trigger_unique_id[idx] = trigger->unique_id; + return ERROR_OK; +} - riscv_set_register(target, GDB_REGNO_TDATA1, tdata1); +struct trigger_request_info { + riscv_reg_t tdata1; + riscv_reg_t tdata2; + riscv_reg_t tdata1_ignore_mask; +}; - riscv_reg_t tdata1_rb; - if (riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK) - return ERROR_FAIL; - LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); +static void log_trigger_request_info(struct trigger_request_info trig_info) +{ + LOG_DEBUG("tdata1=%" PRIx64 ", tdata2=%" PRIx64 ", tdata1_ignore_mask=%" PRIx64, + trig_info.tdata1, trig_info.tdata2, trig_info.tdata1_ignore_mask); +}; - if (tdata1 != tdata1_rb) { - LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%" - PRIx64 " to tdata1 it contains 0x%" PRIx64, - tdata1, tdata1_rb); - riscv_set_register(target, GDB_REGNO_TDATA1, 0); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; +static struct tdata1_cache *tdata1_cache_alloc(struct list_head *tdata1_cache_head, riscv_reg_t tdata1) +{ + struct tdata1_cache *elem = (struct tdata1_cache *)calloc(1, sizeof(struct tdata1_cache)); + elem->tdata1 = tdata1; + INIT_LIST_HEAD(&elem->tdata2_cache_head); + list_add_tail(&elem->elem_tdata1, tdata1_cache_head); + return elem; +} + +static void tdata2_cache_alloc(struct list_head *tdata2_cache_head, riscv_reg_t tdata2) +{ + struct tdata2_cache * const elem = calloc(1, sizeof(struct tdata2_cache)); + elem->tdata2 = tdata2; + list_add(&elem->elem_tdata2, tdata2_cache_head); +} + +struct tdata2_cache *tdata2_cache_search(struct list_head *tdata2_cache_head, riscv_reg_t find_tdata2) +{ + struct tdata2_cache *elem_2; + list_for_each_entry(elem_2, tdata2_cache_head, elem_tdata2) { + if (elem_2->tdata2 == find_tdata2) + return elem_2; } + return NULL; +} - riscv_set_register(target, GDB_REGNO_TDATA2, trigger->address); +struct tdata1_cache *tdata1_cache_search(struct list_head *tdata1_cache_head, riscv_reg_t find_tdata1) +{ + struct tdata1_cache *elem_1; + list_for_each_entry(elem_1, tdata1_cache_head, elem_tdata1) { + if (elem_1->tdata1 == find_tdata1) + return elem_1; + } + return NULL; +} - return ERROR_OK; +static void create_wp_trigger_cache(struct target *target) +{ + RISCV_INFO(r); + + r->wp_triggers_negative_cache = (struct list_head *)calloc(r->trigger_count, + sizeof(struct list_head)); + for (unsigned int i = 0; i < r->trigger_count; ++i) + INIT_LIST_HEAD(&r->wp_triggers_negative_cache[i]); } -static int maybe_add_trigger_t2(struct target *target, - struct trigger *trigger, uint64_t tdata1) +static void wp_triggers_cache_add(struct target *target, unsigned int idx, riscv_reg_t tdata1, + riscv_reg_t tdata2, int error_code) { RISCV_INFO(r); - /* tselect is already set */ - if (tdata1 & (CSR_MCONTROL_EXECUTE | CSR_MCONTROL_STORE | CSR_MCONTROL_LOAD)) { - /* Trigger is already in use, presumably by user code. */ - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + struct tdata1_cache *tdata1_cache = tdata1_cache_search(&r->wp_triggers_negative_cache[idx], tdata1); + if (!tdata1_cache) { + tdata1_cache = tdata1_cache_alloc(&r->wp_triggers_negative_cache[idx], tdata1); + } else { + struct tdata2_cache *tdata2_cache = tdata2_cache_search(&tdata1_cache->tdata2_cache_head, tdata2); + if (tdata2_cache) { + list_move(&tdata2_cache->elem_tdata2, &tdata1_cache->tdata2_cache_head); + return; + } } + tdata2_cache_alloc(&tdata1_cache->tdata2_cache_head, tdata2); +} - /* address/data match trigger */ - tdata1 |= CSR_MCONTROL_DMODE(riscv_xlen(target)); - tdata1 = set_field(tdata1, CSR_MCONTROL_ACTION, - CSR_MCONTROL_ACTION_DEBUG_MODE); - tdata1 = set_field(tdata1, CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_EQUAL); - tdata1 |= CSR_MCONTROL_M; - if (r->misa & (1 << ('S' - 'A'))) - tdata1 |= CSR_MCONTROL_S; - if (r->misa & (1 << ('U' - 'A'))) - tdata1 |= CSR_MCONTROL_U; - - if (trigger->execute) - tdata1 |= CSR_MCONTROL_EXECUTE; - if (trigger->read) - tdata1 |= CSR_MCONTROL_LOAD; - if (trigger->write) - tdata1 |= CSR_MCONTROL_STORE; - - riscv_set_register(target, GDB_REGNO_TDATA1, tdata1); - - uint64_t tdata1_rb; - int result = riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1); - if (result != ERROR_OK) - return result; - LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); +static bool wp_triggers_cache_search(struct target *target, unsigned int idx, + riscv_reg_t tdata1, riscv_reg_t tdata2) +{ + RISCV_INFO(r); + + struct tdata1_cache *tdata1_cache = tdata1_cache_search(&r->wp_triggers_negative_cache[idx], tdata1); + if (!tdata1_cache) + return false; + struct tdata2_cache *tdata2_cache = tdata2_cache_search(&tdata1_cache->tdata2_cache_head, tdata2); + if (!tdata2_cache) + return false; + assert(tdata1_cache->tdata1 == tdata1 && tdata2_cache->tdata2 == tdata2); + return true; +} - if (tdata1 != tdata1_rb) { - LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%" - PRIx64 " to tdata1 it contains 0x%" PRIx64, - tdata1, tdata1_rb); - riscv_set_register(target, GDB_REGNO_TDATA1, 0); +static int try_use_trigger_and_cache_result(struct target *target, unsigned int idx, riscv_reg_t tdata1, + riscv_reg_t tdata2, riscv_reg_t tdata1_ignore_mask) +{ + if (wp_triggers_cache_search(target, idx, tdata1, tdata2)) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - riscv_set_register(target, GDB_REGNO_TDATA2, trigger->address); + int ret = set_trigger(target, idx, tdata1, tdata2, tdata1_ignore_mask); - return ERROR_OK; + /* Add these values to the cache to remember that they are not supported. */ + if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + wp_triggers_cache_add(target, idx, tdata1, tdata2, ret); + return ret; } -static int maybe_add_trigger_t6(struct target *target, - struct trigger *trigger, uint64_t tdata1) +static int try_setup_single_match_trigger(struct target *target, + struct trigger *trigger, struct trigger_request_info trig_info) { + LOG_TARGET_DEBUG(target, "trying to set up a match trigger"); + log_trigger_request_info(trig_info); + + int trigger_type = + get_field(trig_info.tdata1, CSR_MCONTROL_TYPE(riscv_xlen(target))); + int ret = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; RISCV_INFO(r); - /* tselect is already set */ - if (tdata1 & (CSR_MCONTROL6_EXECUTE | CSR_MCONTROL6_STORE | CSR_MCONTROL6_LOAD)) { - /* Trigger is already in use, presumably by user code. */ - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + /* Find the first trigger, supporting required tdata1 value */ + for (unsigned int idx = 0; + find_next_free_trigger(target, trigger_type, false, &idx) == ERROR_OK; + ++idx) { + ret = try_use_trigger_and_cache_result(target, idx, trig_info.tdata1, trig_info.tdata2, + trig_info.tdata1_ignore_mask); + + if (ret == ERROR_OK) { + r->trigger_unique_id[idx] = trigger->unique_id; + return ERROR_OK; + } + if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + return ret; } + return ret; +} - /* address/data match trigger */ - tdata1 |= CSR_MCONTROL6_DMODE(riscv_xlen(target)); - tdata1 = set_field(tdata1, CSR_MCONTROL6_ACTION, - CSR_MCONTROL6_ACTION_DEBUG_MODE); - tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_EQUAL); - tdata1 |= CSR_MCONTROL6_M; - if (r->misa & (1 << ('H' - 'A'))) - tdata1 |= CSR_MCONTROL6_VS | CSR_MCONTROL6_VU; - if (r->misa & (1 << ('S' - 'A'))) - tdata1 |= CSR_MCONTROL6_S; - if (r->misa & (1 << ('U' - 'A'))) - tdata1 |= CSR_MCONTROL6_U; - - if (trigger->execute) - tdata1 |= CSR_MCONTROL6_EXECUTE; - if (trigger->read) - tdata1 |= CSR_MCONTROL6_LOAD; - if (trigger->write) - tdata1 |= CSR_MCONTROL6_STORE; - - riscv_set_register(target, GDB_REGNO_TDATA1, tdata1); - - uint64_t tdata1_rb; - int result = riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1); - if (result != ERROR_OK) - return result; - LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); +static int try_setup_chained_match_triggers(struct target *target, + struct trigger *trigger, struct trigger_request_info t1, + struct trigger_request_info t2) +{ + LOG_TARGET_DEBUG(target, "trying to set up a chain of match triggers"); + log_trigger_request_info(t1); + log_trigger_request_info(t2); + int trigger_type = + get_field(t1.tdata1, CSR_MCONTROL_TYPE(riscv_xlen(target))); + int ret = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + RISCV_INFO(r); - if (tdata1 != tdata1_rb) { - LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%" - PRIx64 " to tdata1 it contains 0x%" PRIx64, - tdata1, tdata1_rb); - riscv_set_register(target, GDB_REGNO_TDATA1, 0); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } + /* Find the first 2 consecutive triggers, supporting required tdata1 values */ + for (unsigned int idx = 0; + find_next_free_trigger(target, trigger_type, true, &idx) == ERROR_OK; + ++idx) { + ret = try_use_trigger_and_cache_result(target, idx, t1.tdata1, t1.tdata2, + t1.tdata1_ignore_mask); - riscv_set_register(target, GDB_REGNO_TDATA2, trigger->address); + if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + continue; + else if (ret != ERROR_OK) + return ret; - return ERROR_OK; + ret = try_use_trigger_and_cache_result(target, idx + 1, t2.tdata1, t2.tdata2, + t2.tdata1_ignore_mask); + + if (ret == ERROR_OK) { + r->trigger_unique_id[idx] = trigger->unique_id; + r->trigger_unique_id[idx + 1] = trigger->unique_id; + return ERROR_OK; + } + /* Undo the setting of the previous trigger */ + int ret_undo = set_trigger(target, idx, 0, 0, 0); + if (ret_undo != ERROR_OK) + return ret_undo; + + if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + return ret; + } + return ret; } -static int add_trigger(struct target *target, struct trigger *trigger) +struct match_triggers_tdata1_fields { + riscv_reg_t common; + struct { + /* Other values are available for this field, + * but currently only `any` is needed. + */ + riscv_reg_t any; + } size; + struct { + riscv_reg_t enable; + riscv_reg_t disable; + } chain; + struct { + riscv_reg_t napot; + riscv_reg_t lt; + riscv_reg_t ge; + riscv_reg_t eq; + } match; + riscv_reg_t tdata1_ignore_mask; +}; + +static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t2(struct target *target, + struct trigger *trigger) { RISCV_INFO(r); - if (riscv_enumerate_triggers(target) != ERROR_OK) - return ERROR_FAIL; + struct match_triggers_tdata1_fields result = { + .common = + field_value(CSR_MCONTROL_TYPE(riscv_xlen(target)), CSR_TDATA1_TYPE_MCONTROL) | + field_value(CSR_MCONTROL_DMODE(riscv_xlen(target)), 1) | + field_value(CSR_MCONTROL_ACTION, CSR_MCONTROL_ACTION_DEBUG_MODE) | + field_value(CSR_MCONTROL_M, 1) | + field_value(CSR_MCONTROL_S, !!(r->misa & BIT('S' - 'A'))) | + field_value(CSR_MCONTROL_U, !!(r->misa & BIT('U' - 'A'))) | + field_value(CSR_MCONTROL_EXECUTE, trigger->is_execute) | + field_value(CSR_MCONTROL_LOAD, trigger->is_read) | + field_value(CSR_MCONTROL_STORE, trigger->is_write), + .size = { + .any = + field_value(CSR_MCONTROL_SIZELO, CSR_MCONTROL_SIZELO_ANY & 3) | + field_value(CSR_MCONTROL_SIZEHI, (CSR_MCONTROL_SIZELO_ANY >> 2) & 3) + }, + .chain = { + .enable = field_value(CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_ENABLED), + .disable = field_value(CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_DISABLED) + }, + .match = { + .napot = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_NAPOT), + .lt = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_LT), + .ge = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_GE), + .eq = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_EQUAL) + }, + .tdata1_ignore_mask = CSR_MCONTROL_MASKMAX(riscv_xlen(target)) + }; + return result; +} - riscv_reg_t tselect; - if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) - return ERROR_FAIL; +static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t6(struct target *target, + struct trigger *trigger) +{ + bool misa_s = riscv_supports_extension(target, 'S'); + bool misa_u = riscv_supports_extension(target, 'U'); + bool misa_h = riscv_supports_extension(target, 'H'); + + struct match_triggers_tdata1_fields result = { + .common = + field_value(CSR_MCONTROL6_TYPE(riscv_xlen(target)), CSR_TDATA1_TYPE_MCONTROL6) | + field_value(CSR_MCONTROL6_DMODE(riscv_xlen(target)), 1) | + field_value(CSR_MCONTROL6_ACTION, CSR_MCONTROL_ACTION_DEBUG_MODE) | + field_value(CSR_MCONTROL6_M, 1) | + field_value(CSR_MCONTROL6_S, misa_s) | + field_value(CSR_MCONTROL6_U, misa_u) | + field_value(CSR_MCONTROL6_VS, misa_h && misa_s) | + field_value(CSR_MCONTROL6_VU, misa_h && misa_u) | + field_value(CSR_MCONTROL6_EXECUTE, trigger->is_execute) | + field_value(CSR_MCONTROL6_LOAD, trigger->is_read) | + field_value(CSR_MCONTROL6_STORE, trigger->is_write), + .size = { + .any = field_value(CSR_MCONTROL6_SIZE, CSR_MCONTROL6_SIZE_ANY) + }, + .chain = { + .enable = field_value(CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_ENABLED), + .disable = field_value(CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_DISABLED) + }, + .match = { + .napot = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_NAPOT), + .lt = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_LT), + .ge = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_GE), + .eq = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_EQUAL) + }, + .tdata1_ignore_mask = 0 + }; + return result; +} - unsigned int i; - for (i = 0; i < r->trigger_count; i++) { - if (r->trigger_unique_id[i] != -1) - continue; +static int maybe_add_trigger_t2_t6_for_wp(struct target *target, + struct trigger *trigger, struct match_triggers_tdata1_fields fields) +{ + RISCV_INFO(r); + int ret = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + if (trigger->length > 0) { + /* Setting a load/store trigger ("watchpoint") on a range of addresses */ + if (can_use_napot_match(trigger)) { + if (r->wp_allow_napot_trigger) { + LOG_TARGET_DEBUG(target, "trying to setup NAPOT match trigger"); + struct trigger_request_info napot = { + .tdata1 = fields.common | fields.size.any | + fields.chain.disable | fields.match.napot, + .tdata2 = trigger->address | ((trigger->length - 1) >> 1), + .tdata1_ignore_mask = fields.tdata1_ignore_mask + }; + ret = try_setup_single_match_trigger(target, trigger, napot); + if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + return ret; + } else { + LOG_TARGET_DEBUG(target, "NAPOT match triggers are disabled for watchpoints. " + "Use 'riscv set_enable_trigger_feature napot wp' to enable it."); + } + } - riscv_set_register(target, GDB_REGNO_TSELECT, i); + if (r->wp_allow_ge_lt_trigger) { + LOG_TARGET_DEBUG(target, "trying to setup GE+LT chained match trigger pair"); + struct trigger_request_info ge_1 = { + .tdata1 = fields.common | fields.size.any | fields.chain.enable | + fields.match.ge, + .tdata2 = trigger->address, + .tdata1_ignore_mask = fields.tdata1_ignore_mask + }; + struct trigger_request_info lt_2 = { + .tdata1 = fields.common | fields.size.any | fields.chain.disable | + fields.match.lt, + .tdata2 = trigger->address + trigger->length, + .tdata1_ignore_mask = fields.tdata1_ignore_mask + }; + ret = try_setup_chained_match_triggers(target, trigger, ge_1, lt_2); + if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + return ret; + + LOG_TARGET_DEBUG(target, "trying to setup LT+GE chained match trigger pair"); + struct trigger_request_info lt_1 = { + .tdata1 = fields.common | fields.size.any | fields.chain.enable | + fields.match.lt, + .tdata2 = trigger->address + trigger->length, + .tdata1_ignore_mask = fields.tdata1_ignore_mask + }; + struct trigger_request_info ge_2 = { + .tdata1 = fields.common | fields.size.any | fields.chain.disable | + fields.match.ge, + .tdata2 = trigger->address, + .tdata1_ignore_mask = fields.tdata1_ignore_mask + }; + ret = try_setup_chained_match_triggers(target, trigger, lt_1, ge_2); + if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + return ret; + } else { + LOG_TARGET_DEBUG(target, "LT+GE chained match triggers are disabled for watchpoints. " + "Use 'riscv set_enable_trigger_feature ge_lt wp' to enable it."); + } + } - uint64_t tdata1; - int result = riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1); - if (result != ERROR_OK) - return result; - int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target))); + if (r->wp_allow_equality_match_trigger) { + LOG_TARGET_DEBUG(target, "trying to setup equality match trigger"); + struct trigger_request_info eq = { + .tdata1 = fields.common | fields.size.any | fields.chain.disable | + fields.match.eq, + .tdata2 = trigger->address, + .tdata1_ignore_mask = fields.tdata1_ignore_mask + }; + ret = try_setup_single_match_trigger(target, trigger, eq); + if (ret != ERROR_OK) + return ret; + } else { + LOG_TARGET_DEBUG(target, "equality match triggers are disabled for watchpoints. " + "Use 'riscv set_enable_trigger_feature eq wp' to enable it."); + } + + if (ret == ERROR_OK && trigger->length > 1) { + LOG_TARGET_DEBUG(target, "Trigger will match accesses at address 0x%" TARGET_PRIxADDR + ", but may not match accesses at addresses in the inclusive range from 0x%" + TARGET_PRIxADDR " to 0x%" TARGET_PRIxADDR ".", trigger->address, + trigger->address + 1, trigger->address + trigger->length - 1); + RISCV_INFO(info); + if (!info->range_trigger_fallback_encountered) + /* This message is displayed only once per target to avoid + * overwhelming the user with such messages on resume. + */ + LOG_TARGET_WARNING(target, + "Could not set a trigger that will match a whole address range. " + "As a fallback, this trigger (and maybe others) will only match " + "against the first address of the range."); + info->range_trigger_fallback_encountered = true; + } - result = ERROR_OK; - switch (type) { - case 1: - result = maybe_add_trigger_t1(target, trigger, tdata1); - break; - case 2: - result = maybe_add_trigger_t2(target, trigger, tdata1); - break; - case 6: - result = maybe_add_trigger_t6(target, trigger, tdata1); - break; - default: - LOG_DEBUG("trigger %d has unknown type %d", i, type); - continue; - } + return ret; +} - if (result != ERROR_OK) - continue; +static int maybe_add_trigger_t2_t6_for_bp(struct target *target, + struct trigger *trigger, struct match_triggers_tdata1_fields fields) +{ + LOG_TARGET_DEBUG(target, "trying to setup equality match trigger"); + struct trigger_request_info eq = { + .tdata1 = fields.common | fields.size.any | fields.chain.disable | + fields.match.eq, + .tdata2 = trigger->address, + .tdata1_ignore_mask = fields.tdata1_ignore_mask + }; + + return try_setup_single_match_trigger(target, trigger, eq); +} - LOG_DEBUG("[%d] Using trigger %d (type %d) for bp %d", target->coreid, - i, type, trigger->unique_id); - r->trigger_unique_id[i] = trigger->unique_id; - break; +static int maybe_add_trigger_t2_t6(struct target *target, + struct trigger *trigger, struct match_triggers_tdata1_fields fields) +{ + if (trigger->is_execute) { + assert(!trigger->is_read && !trigger->is_write); + return maybe_add_trigger_t2_t6_for_bp(target, trigger, fields); } - riscv_set_register(target, GDB_REGNO_TSELECT, tselect); + assert(trigger->is_read || trigger->is_write); + return maybe_add_trigger_t2_t6_for_wp(target, trigger, fields); +} - if (i >= r->trigger_count) { - LOG_ERROR("Couldn't find an available hardware trigger."); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } +static int maybe_add_trigger_t3(struct target *target, bool vs, bool vu, + bool m, bool s, bool u, bool pending, unsigned int count, + int unique_id) +{ + int ret; + riscv_reg_t tdata1; + + RISCV_INFO(r); + + tdata1 = 0; + tdata1 = set_field(tdata1, CSR_ICOUNT_TYPE(riscv_xlen(target)), CSR_TDATA1_TYPE_ICOUNT); + tdata1 = set_field(tdata1, CSR_ICOUNT_DMODE(riscv_xlen(target)), 1); + tdata1 = set_field(tdata1, CSR_ICOUNT_ACTION, CSR_ICOUNT_ACTION_DEBUG_MODE); + tdata1 = set_field(tdata1, CSR_ICOUNT_VS, vs); + tdata1 = set_field(tdata1, CSR_ICOUNT_VU, vu); + tdata1 = set_field(tdata1, CSR_ICOUNT_PENDING, pending); + tdata1 = set_field(tdata1, CSR_ICOUNT_M, m); + tdata1 = set_field(tdata1, CSR_ICOUNT_S, s); + tdata1 = set_field(tdata1, CSR_ICOUNT_U, u); + tdata1 = set_field(tdata1, CSR_ICOUNT_COUNT, count); + + unsigned int idx = 0; + ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_ICOUNT, false, &idx); + if (ret != ERROR_OK) + return ret; + ret = set_trigger(target, idx, tdata1, 0, 0); + if (ret != ERROR_OK) + return ret; + r->trigger_unique_id[idx] = unique_id; + return ERROR_OK; +} + +static int maybe_add_trigger_t4(struct target *target, bool vs, bool vu, + bool nmi, bool m, bool s, bool u, riscv_reg_t interrupts, + int unique_id) +{ + int ret; + riscv_reg_t tdata1, tdata2; + + RISCV_INFO(r); + + tdata1 = 0; + tdata1 = set_field(tdata1, CSR_ITRIGGER_TYPE(riscv_xlen(target)), CSR_TDATA1_TYPE_ITRIGGER); + tdata1 = set_field(tdata1, CSR_ITRIGGER_DMODE(riscv_xlen(target)), 1); + tdata1 = set_field(tdata1, CSR_ITRIGGER_ACTION, CSR_ITRIGGER_ACTION_DEBUG_MODE); + tdata1 = set_field(tdata1, CSR_ITRIGGER_VS, vs); + tdata1 = set_field(tdata1, CSR_ITRIGGER_VU, vu); + tdata1 = set_field(tdata1, CSR_ITRIGGER_NMI, nmi); + tdata1 = set_field(tdata1, CSR_ITRIGGER_M, m); + tdata1 = set_field(tdata1, CSR_ITRIGGER_S, s); + tdata1 = set_field(tdata1, CSR_ITRIGGER_U, u); + + tdata2 = interrupts; + + unsigned int idx = 0; + ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_ITRIGGER, false, &idx); + if (ret != ERROR_OK) + return ret; + ret = set_trigger(target, idx, tdata1, tdata2, 0); + if (ret != ERROR_OK) + return ret; + r->trigger_unique_id[idx] = unique_id; + return ERROR_OK; +} + +static int maybe_add_trigger_t5(struct target *target, bool vs, bool vu, + bool m, bool s, bool u, riscv_reg_t exception_codes, + int unique_id) +{ + int ret; + riscv_reg_t tdata1, tdata2; + + RISCV_INFO(r); + + tdata1 = 0; + tdata1 = set_field(tdata1, CSR_ETRIGGER_TYPE(riscv_xlen(target)), CSR_TDATA1_TYPE_ETRIGGER); + tdata1 = set_field(tdata1, CSR_ETRIGGER_DMODE(riscv_xlen(target)), 1); + tdata1 = set_field(tdata1, CSR_ETRIGGER_ACTION, CSR_ETRIGGER_ACTION_DEBUG_MODE); + tdata1 = set_field(tdata1, CSR_ETRIGGER_VS, vs); + tdata1 = set_field(tdata1, CSR_ETRIGGER_VU, vu); + tdata1 = set_field(tdata1, CSR_ETRIGGER_M, m); + tdata1 = set_field(tdata1, CSR_ETRIGGER_S, s); + tdata1 = set_field(tdata1, CSR_ETRIGGER_U, u); + + tdata2 = exception_codes; + + unsigned int idx = 0; + ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_ETRIGGER, false, &idx); + if (ret != ERROR_OK) + return ret; + ret = set_trigger(target, idx, tdata1, tdata2, 0); + if (ret != ERROR_OK) + return ret; + r->trigger_unique_id[idx] = unique_id; + return ERROR_OK; +} + +static int add_trigger(struct target *target, struct trigger *trigger) +{ + int ret; + riscv_reg_t tselect; + + ret = riscv_enumerate_triggers(target); + if (ret != ERROR_OK) + return ret; + + ret = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT); + if (ret != ERROR_OK) + return ret; + + do { + ret = maybe_add_trigger_t1(target, trigger); + if (ret == ERROR_OK) + break; + ret = maybe_add_trigger_t2_t6(target, trigger, + fill_match_triggers_tdata1_fields_t2(target, trigger)); + if (ret == ERROR_OK) + break; + ret = maybe_add_trigger_t2_t6(target, trigger, + fill_match_triggers_tdata1_fields_t6(target, trigger)); + if (ret == ERROR_OK) + break; + } while (0); - return ERROR_OK; + if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK && + ret == ERROR_OK) + return ERROR_FAIL; + + return ret; } /** @@ -794,26 +1384,27 @@ int riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_ return ERROR_FAIL; } -int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) +static int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { LOG_TARGET_DEBUG(target, "@0x%" TARGET_PRIxADDR, breakpoint->address); assert(breakpoint); if (breakpoint->type == BKPT_SOFT) { /** @todo check RVC for size/alignment */ if (!(breakpoint->length == 4 || breakpoint->length == 2)) { - LOG_ERROR("Invalid breakpoint length %d", breakpoint->length); + LOG_TARGET_ERROR(target, "Invalid breakpoint length %d", breakpoint->length); return ERROR_FAIL; } if (0 != (breakpoint->address % 2)) { - LOG_ERROR("Invalid breakpoint alignment for address 0x%" TARGET_PRIxADDR, breakpoint->address); + LOG_TARGET_ERROR(target, "Invalid breakpoint alignment for address 0x%" TARGET_PRIxADDR, + breakpoint->address); return ERROR_FAIL; } /* Read the original instruction. */ if (riscv_read_by_any_size( target, breakpoint->address, breakpoint->length, breakpoint->orig_instr) != ERROR_OK) { - LOG_ERROR("Failed to read original instruction at 0x%" TARGET_PRIxADDR, + LOG_TARGET_ERROR(target, "Failed to read original instruction at 0x%" TARGET_PRIxADDR, breakpoint->address); return ERROR_FAIL; } @@ -822,7 +1413,7 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) buf_set_u32(buff, 0, breakpoint->length * CHAR_BIT, breakpoint->length == 4 ? ebreak() : ebreak_c()); /* Write the ebreak instruction. */ if (riscv_write_by_any_size(target, breakpoint->address, breakpoint->length, buff) != ERROR_OK) { - LOG_ERROR("Failed to write %d-byte breakpoint instruction at 0x%" + LOG_TARGET_ERROR(target, "Failed to write %d-byte breakpoint instruction at 0x%" TARGET_PRIxADDR, breakpoint->length, breakpoint->address); return ERROR_FAIL; } @@ -834,7 +1425,7 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) if (result != ERROR_OK) return result; } else { - LOG_INFO("OpenOCD only supports hardware and software breakpoints."); + LOG_TARGET_INFO(target, "OpenOCD only supports hardware and software breakpoints."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -842,46 +1433,48 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) return ERROR_OK; } -static int remove_trigger(struct target *target, struct trigger *trigger) +static int remove_trigger(struct target *target, int unique_id) { RISCV_INFO(r); if (riscv_enumerate_triggers(target) != ERROR_OK) return ERROR_FAIL; - unsigned int i; - for (i = 0; i < r->trigger_count; i++) { - if (r->trigger_unique_id[i] == trigger->unique_id) - break; - } - if (i >= r->trigger_count) { - LOG_ERROR("Couldn't find the hardware resources used by hardware " - "trigger."); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - LOG_DEBUG("[%d] Stop using resource %d for bp %d", target->coreid, i, - trigger->unique_id); - riscv_reg_t tselect; int result = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT); if (result != ERROR_OK) return result; - riscv_set_register(target, GDB_REGNO_TSELECT, i); - riscv_set_register(target, GDB_REGNO_TDATA1, 0); + + bool done = false; + for (unsigned int i = 0; i < r->trigger_count; i++) { + if (r->trigger_unique_id[i] == unique_id) { + riscv_set_register(target, GDB_REGNO_TSELECT, i); + riscv_set_register(target, GDB_REGNO_TDATA1, 0); + r->trigger_unique_id[i] = -1; + LOG_TARGET_DEBUG(target, "Stop using resource %d for bp %d", + i, unique_id); + done = true; + } + } + if (!done) { + LOG_TARGET_ERROR(target, + "Couldn't find the hardware resources used by hardware trigger."); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + riscv_set_register(target, GDB_REGNO_TSELECT, tselect); - r->trigger_unique_id[i] = -1; return ERROR_OK; } -int riscv_remove_breakpoint(struct target *target, +static int riscv_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (breakpoint->type == BKPT_SOFT) { /* Write the original instruction. */ if (riscv_write_by_any_size( target, breakpoint->address, breakpoint->length, breakpoint->orig_instr) != ERROR_OK) { - LOG_ERROR("Failed to restore instruction for %d-byte breakpoint at " + LOG_TARGET_ERROR(target, "Failed to restore instruction for %d-byte breakpoint at " "0x%" TARGET_PRIxADDR, breakpoint->length, breakpoint->address); return ERROR_FAIL; } @@ -889,12 +1482,12 @@ int riscv_remove_breakpoint(struct target *target, } else if (breakpoint->type == BKPT_HARD) { struct trigger trigger; trigger_from_breakpoint(&trigger, breakpoint); - int result = remove_trigger(target, &trigger); + int result = remove_trigger(target, trigger.unique_id); if (result != ERROR_OK) return result; } else { - LOG_INFO("OpenOCD only supports hardware and software breakpoints."); + LOG_TARGET_INFO(target, "OpenOCD only supports hardware and software breakpoints."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -910,15 +1503,20 @@ static void trigger_from_watchpoint(struct trigger *trigger, trigger->length = watchpoint->length; trigger->mask = watchpoint->mask; trigger->value = watchpoint->value; - trigger->read = (watchpoint->rw == WPT_READ || watchpoint->rw == WPT_ACCESS); - trigger->write = (watchpoint->rw == WPT_WRITE || watchpoint->rw == WPT_ACCESS); - trigger->execute = false; + trigger->is_read = (watchpoint->rw == WPT_READ || watchpoint->rw == WPT_ACCESS); + trigger->is_write = (watchpoint->rw == WPT_WRITE || watchpoint->rw == WPT_ACCESS); + trigger->is_execute = false; /* unique_id is unique across both breakpoints and watchpoints. */ trigger->unique_id = watchpoint->unique_id; } int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { + if (watchpoint->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) { + LOG_TARGET_ERROR(target, "Watchpoints on data values are not implemented"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + struct trigger trigger; trigger_from_watchpoint(&trigger, watchpoint); @@ -933,12 +1531,12 @@ int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint) int riscv_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { - LOG_DEBUG("[%d] @0x%" TARGET_PRIxADDR, target->coreid, watchpoint->address); + LOG_TARGET_DEBUG(target, "Removing watchpoint @0x%" TARGET_PRIxADDR, watchpoint->address); struct trigger trigger; trigger_from_watchpoint(&trigger, watchpoint); - int result = remove_trigger(target, &trigger); + int result = remove_trigger(target, trigger.unique_id); if (result != ERROR_OK) return result; watchpoint->is_set = false; @@ -974,17 +1572,26 @@ static int riscv_hit_trigger_hit_bit(struct target *target, uint32_t *unique_id) uint64_t hit_mask = 0; switch (type) { - case 1: + case CSR_TDATA1_TYPE_LEGACY: /* Doesn't support hit bit. */ break; - case 2: + case CSR_TDATA1_TYPE_MCONTROL: hit_mask = CSR_MCONTROL_HIT; break; - case 6: - hit_mask = CSR_MCONTROL6_HIT; + case CSR_TDATA1_TYPE_MCONTROL6: + hit_mask = CSR_MCONTROL6_HIT0 | CSR_MCONTROL6_HIT1; + break; + case CSR_TDATA1_TYPE_ICOUNT: + hit_mask = CSR_ICOUNT_HIT; + break; + case CSR_TDATA1_TYPE_ITRIGGER: + hit_mask = CSR_ITRIGGER_HIT(riscv_xlen(target)); + break; + case CSR_TDATA1_TYPE_ETRIGGER: + hit_mask = CSR_ETRIGGER_HIT(riscv_xlen(target)); break; default: - LOG_DEBUG("trigger %d has unknown type %d", i, type); + LOG_TARGET_DEBUG(target, "Trigger %d has unknown type %d", i, type); continue; } @@ -992,7 +1599,7 @@ static int riscv_hit_trigger_hit_bit(struct target *target, uint32_t *unique_id) * to be changed to ignore triggers that are not the last one in * the chain. */ if (tdata1 & hit_mask) { - LOG_DEBUG("Trigger %d (unique_id=%d) has hit bit set.", i, r->trigger_unique_id[i]); + LOG_TARGET_DEBUG(target, "Trigger %d (unique_id=%d) has hit bit set.", i, r->trigger_unique_id[i]); if (riscv_set_register(target, GDB_REGNO_TDATA1, tdata1 & ~hit_mask) != ERROR_OK) return ERROR_FAIL; @@ -1013,7 +1620,7 @@ static int riscv_hit_trigger_hit_bit(struct target *target, uint32_t *unique_id) * The GDB server uses this information to tell GDB what data address has * been hit, which enables GDB to print the hit variable along with its old * and new value. */ -int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) +static int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) { RISCV_INFO(r); @@ -1031,22 +1638,22 @@ int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoi riscv_reg_t dpc; riscv_get_register(target, &dpc, GDB_REGNO_DPC); const uint8_t length = 4; - LOG_DEBUG("dpc is 0x%" PRIx64, dpc); + LOG_TARGET_DEBUG(target, "dpc is 0x%" PRIx64, dpc); /* fetch the instruction at dpc */ uint8_t buffer[length]; if (target_read_buffer(target, dpc, length, buffer) != ERROR_OK) { - LOG_ERROR("Failed to read instruction at dpc 0x%" PRIx64, dpc); + LOG_TARGET_ERROR(target, "Failed to read instruction at dpc 0x%" PRIx64, dpc); return ERROR_FAIL; } uint32_t instruction = 0; for (int i = 0; i < length; i++) { - LOG_DEBUG("Next byte is %x", buffer[i]); + LOG_TARGET_DEBUG(target, "Next byte is %x", buffer[i]); instruction += (buffer[i] << 8 * i); } - LOG_DEBUG("Full instruction is %x", instruction); + LOG_TARGET_DEBUG(target, "Full instruction is %x", instruction); /* find out which memory address is accessed by the instruction at dpc */ /* opcode is first 7 bits of the instruction */ @@ -1060,19 +1667,19 @@ int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoi riscv_get_register(target, &mem_addr, rs1); if (opcode == MATCH_SB) { - LOG_DEBUG("%x is store instruction", instruction); + LOG_TARGET_DEBUG(target, "%x is store instruction", instruction); imm = ((instruction & 0xf80) >> 7) | ((instruction & 0xfe000000) >> 20); } else { - LOG_DEBUG("%x is load instruction", instruction); + LOG_TARGET_DEBUG(target, "%x is load instruction", instruction); imm = (instruction & 0xfff00000) >> 20; } /* sign extend 12-bit imm to 16-bits */ if (imm & (1 << 11)) imm |= 0xf000; mem_addr += imm; - LOG_DEBUG("memory address=0x%" PRIx64, mem_addr); + LOG_TARGET_DEBUG(target, "Memory address=0x%" PRIx64, mem_addr); } else { - LOG_DEBUG("%x is not a RV32I load or store", instruction); + LOG_TARGET_DEBUG(target, "%x is not a RV32I load or store", instruction); return ERROR_FAIL; } @@ -1081,7 +1688,7 @@ int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoi /*TODO support length/mask */ if (wp->address == mem_addr) { *hit_watchpoint = wp; - LOG_DEBUG("Hit address=%" TARGET_PRIxADDR, wp->address); + LOG_TARGET_DEBUG(target, "Hit address=%" TARGET_PRIxADDR, wp->address); return ERROR_OK; } wp = wp->next; @@ -1099,6 +1706,8 @@ static int oldriscv_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; return tt->step(target, current, address, handle_breakpoints); } @@ -1106,8 +1715,8 @@ static int old_or_new_riscv_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { RISCV_INFO(r); - LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); - if (!r->is_halted) + LOG_TARGET_DEBUG(target, "handle_breakpoints=%d", handle_breakpoints); + if (!r->get_hart_state) return oldriscv_step(target, current, address, handle_breakpoints); else return riscv_openocd_step(target, current, address, handle_breakpoints); @@ -1115,46 +1724,70 @@ static int old_or_new_riscv_step(struct target *target, int current, static int riscv_examine(struct target *target) { - LOG_DEBUG("[%s]", target_name(target)); + LOG_TARGET_DEBUG(target, "Starting examination"); if (target_was_examined(target)) { - LOG_DEBUG("Target was already examined."); + LOG_TARGET_DEBUG(target, "Target was already examined."); return ERROR_OK; } /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ RISCV_INFO(info); - uint32_t dtmcontrol = dtmcontrol_scan(target, 0); - LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol); + uint32_t dtmcontrol; + if (dtmcontrol_scan(target, 0, &dtmcontrol) != ERROR_OK || dtmcontrol == 0) { + LOG_TARGET_ERROR(target, "Could not read dtmcontrol. Check JTAG connectivity/board power."); + return ERROR_FAIL; + } + LOG_TARGET_DEBUG(target, "dtmcontrol=0x%x", dtmcontrol); info->dtm_version = get_field(dtmcontrol, DTMCONTROL_VERSION); - LOG_DEBUG(" version=0x%x", info->dtm_version); + LOG_TARGET_DEBUG(target, "version=0x%x", info->dtm_version); + int examine_status = ERROR_FAIL; struct target_type *tt = get_target_type(target); if (!tt) - return ERROR_FAIL; + goto examine_fail; - int result = tt->init_target(info->cmd_ctx, target); - if (result != ERROR_OK) - return result; + examine_status = tt->init_target(info->cmd_ctx, target); + if (examine_status != ERROR_OK) + goto examine_fail; + + examine_status = tt->examine(target); + if (examine_status != ERROR_OK) + goto examine_fail; + + return ERROR_OK; - return tt->examine(target); +examine_fail: + info->dtm_version = DTM_DTMCS_VERSION_UNKNOWN; + return examine_status; } static int oldriscv_poll(struct target *target) { struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; return tt->poll(target); } static int old_or_new_riscv_poll(struct target *target) { RISCV_INFO(r); - if (!r->is_halted) + if (!r->get_hart_state) return oldriscv_poll(target); else return riscv_openocd_poll(target); } +static struct reg *get_reg_cache_entry(struct target *target, + unsigned int number) +{ + assert(target->reg_cache); + assert(target->reg_cache->reg_list); + assert(number < target->reg_cache->num_regs); + return &target->reg_cache->reg_list[number]; +} + int riscv_flush_registers(struct target *target) { RISCV_INFO(r); @@ -1162,31 +1795,37 @@ int riscv_flush_registers(struct target *target) if (!target->reg_cache) return ERROR_OK; - LOG_DEBUG("[%s]", target_name(target)); + LOG_TARGET_DEBUG(target, "Flushing register cache"); - for (uint32_t number = 0; number < target->reg_cache->num_regs; number++) { - struct reg *reg = &target->reg_cache->reg_list[number]; + /* Writing non-GPR registers may require progbuf execution, and some GPRs + * may become dirty in the process (e.g. S0, S1). For that reason, flush + * registers in reverse order, so that GPRs are flushed last. + */ + for (unsigned int number = target->reg_cache->num_regs; number-- > 0; ) { + struct reg *reg = get_reg_cache_entry(target, number); if (reg->valid && reg->dirty) { - uint64_t value = buf_get_u64(reg->value, 0, reg->size); - LOG_DEBUG("[%s] %s is dirty; write back 0x%" PRIx64, - target_name(target), reg->name, value); - int result = r->set_register(target, number, value); - if (result != ERROR_OK) + riscv_reg_t value = buf_get_u64(reg->value, 0, reg->size); + + LOG_TARGET_DEBUG(target, "%s is dirty; write back 0x%" PRIx64, + reg->name, value); + if (r->set_register(target, number, value) != ERROR_OK) return ERROR_FAIL; reg->dirty = false; } } - + LOG_TARGET_DEBUG(target, "Flush of register cache completed"); return ERROR_OK; } -/* Convert: RISC-V hart's halt reason --> OpenOCD's generic debug reason */ -int set_debug_reason(struct target *target, enum riscv_halt_reason halt_reason) +/** + * Set OpenOCD's generic debug reason from the RISC-V halt reason. + */ +static int set_debug_reason(struct target *target, enum riscv_halt_reason halt_reason) { RISCV_INFO(r); r->trigger_hit = -1; switch (halt_reason) { - case RISCV_HALT_BREAKPOINT: + case RISCV_HALT_EBREAK: target->debug_reason = DBG_REASON_BREAKPOINT; break; case RISCV_HALT_TRIGGER: @@ -1212,25 +1851,21 @@ int set_debug_reason(struct target *target, enum riscv_halt_reason halt_reason) case RISCV_HALT_ERROR: return ERROR_FAIL; } - LOG_DEBUG("[%s] debug_reason=%d", target_name(target), target->debug_reason); + LOG_TARGET_DEBUG(target, "debug_reason=%d", target->debug_reason); return ERROR_OK; } -int halt_prep(struct target *target) +static int halt_prep(struct target *target) { RISCV_INFO(r); - LOG_DEBUG("[%s] prep hart, debug_reason=%d", target_name(target), - target->debug_reason); - if (riscv_is_halted(target)) { - LOG_DEBUG("[%s] Hart is already halted (debug_reason=%d).", - target_name(target), target->debug_reason); - if (target->debug_reason == DBG_REASON_NOTHALTED) { - enum riscv_halt_reason halt_reason = riscv_halt_reason(target); - if (set_debug_reason(target, halt_reason) != ERROR_OK) - return ERROR_FAIL; - } + LOG_TARGET_DEBUG(target, "prep hart, debug_reason=%d", target->debug_reason); + r->prepped = false; + if (target->state == TARGET_HALTED) { + LOG_TARGET_DEBUG(target, "Hart is already halted."); + } else if (target->state == TARGET_UNAVAILABLE) { + LOG_TARGET_DEBUG(target, "Hart is unavailable."); } else { if (r->halt_prep(target) != ERROR_OK) return ERROR_FAIL; @@ -1240,12 +1875,21 @@ int halt_prep(struct target *target) return ERROR_OK; } -int riscv_halt_go_all_harts(struct target *target) +static int riscv_halt_go_all_harts(struct target *target) { RISCV_INFO(r); - if (riscv_is_halted(target)) { - LOG_DEBUG("[%s] Hart is already halted.", target_name(target)); + enum riscv_hart_state state; + if (riscv_get_hart_state(target, &state) != ERROR_OK) + return ERROR_FAIL; + if (state == RISCV_STATE_HALTED) { + LOG_TARGET_DEBUG(target, "Hart is already halted."); + if (target->state != TARGET_HALTED) { + target->state = TARGET_HALTED; + enum riscv_halt_reason halt_reason = riscv_halt_reason(target); + if (set_debug_reason(target, halt_reason) != ERROR_OK) + return ERROR_FAIL; + } } else { if (r->halt_go(target) != ERROR_OK) return ERROR_FAIL; @@ -1256,17 +1900,18 @@ int riscv_halt_go_all_harts(struct target *target) return ERROR_OK; } -int halt_go(struct target *target) +static int halt_go(struct target *target) { - riscv_info_t *r = riscv_info(target); + RISCV_INFO(r); int result; - if (!r->is_halted) { + if (!r->get_hart_state) { struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; result = tt->halt(target); } else { result = riscv_halt_go_all_harts(target); } - target->state = TARGET_HALTED; if (target->debug_reason == DBG_REASON_NOTHALTED) target->debug_reason = DBG_REASON_DBGRQ; @@ -1282,8 +1927,10 @@ int riscv_halt(struct target *target) { RISCV_INFO(r); - if (!r->is_halted) { + if (!r->get_hart_state) { struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; return tt->halt(target); } @@ -1300,7 +1947,7 @@ int riscv_halt(struct target *target) foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; - riscv_info_t *i = riscv_info(t); + struct riscv_info *i = riscv_info(t); if (i->prepped) { if (halt_go(t) != ERROR_OK) result = ERROR_FAIL; @@ -1327,16 +1974,20 @@ int riscv_halt(struct target *target) static int riscv_assert_reset(struct target *target) { - LOG_DEBUG("[%d]", target->coreid); + LOG_TARGET_DEBUG(target, ""); struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; riscv_invalidate_register_cache(target); return tt->assert_reset(target); } static int riscv_deassert_reset(struct target *target) { - LOG_DEBUG("[%d]", target->coreid); + LOG_TARGET_DEBUG(target, ""); struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; return tt->deassert_reset(target); } @@ -1345,7 +1996,7 @@ static int disable_triggers(struct target *target, riscv_reg_t *state) { RISCV_INFO(r); - LOG_DEBUG("deal with triggers"); + LOG_TARGET_DEBUG(target, "Disabling triggers."); if (riscv_enumerate_triggers(target) != ERROR_OK) return ERROR_FAIL; @@ -1375,7 +2026,7 @@ static int disable_triggers(struct target *target, riscv_reg_t *state) struct watchpoint *watchpoint = target->watchpoints; int i = 0; while (watchpoint) { - LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->is_set); + LOG_TARGET_DEBUG(target, "Watchpoint %d: set=%d", i, watchpoint->is_set); state[i] = watchpoint->is_set; if (watchpoint->is_set) { if (riscv_remove_watchpoint(target, watchpoint) != ERROR_OK) @@ -1413,7 +2064,7 @@ static int enable_triggers(struct target *target, riscv_reg_t *state) struct watchpoint *watchpoint = target->watchpoints; int i = 0; while (watchpoint) { - LOG_DEBUG("watchpoint %d: cleared=%" PRId64, i, state[i]); + LOG_TARGET_DEBUG(target, "Watchpoint %d: cleared=%" PRId64, i, state[i]); if (state[i]) { if (riscv_add_watchpoint(target, watchpoint) != ERROR_OK) return ERROR_FAIL; @@ -1432,33 +2083,26 @@ static int enable_triggers(struct target *target, riscv_reg_t *state) static int resume_prep(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { + assert(target->state == TARGET_HALTED); RISCV_INFO(r); - LOG_TARGET_DEBUG(target, "target->state=%d", target->state); - - if (!current) - riscv_set_register(target, GDB_REGNO_PC, address); - - if (target->debug_reason == DBG_REASON_WATCHPOINT) { - /* To be able to run off a trigger, disable all the triggers, step, and - * then resume as usual. */ - riscv_reg_t trigger_state[RISCV_MAX_HWBPS] = {0}; - if (disable_triggers(target, trigger_state) != ERROR_OK) - return ERROR_FAIL; - - if (old_or_new_riscv_step(target, true, 0, false) != ERROR_OK) - return ERROR_FAIL; + if (!current && riscv_set_register(target, GDB_REGNO_PC, address) != ERROR_OK) + return ERROR_FAIL; - if (enable_triggers(target, trigger_state) != ERROR_OK) + if (handle_breakpoints) { + /* To be able to run off a trigger, we perform a step operation and then + * resume. If handle_breakpoints is true then step temporarily disables + * pending breakpoints so we can safely perform the step. */ + if (old_or_new_riscv_step(target, current, address, handle_breakpoints) != ERROR_OK) return ERROR_FAIL; } - if (r->is_halted) { + if (r->get_hart_state) { if (r->resume_prep(target) != ERROR_OK) return ERROR_FAIL; } - LOG_DEBUG("[%d] mark as prepped", target->coreid); + LOG_TARGET_DEBUG(target, "Mark as prepped."); r->prepped = true; return ERROR_OK; @@ -1471,10 +2115,13 @@ static int resume_prep(struct target *target, int current, static int resume_go(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { - riscv_info_t *r = riscv_info(target); + assert(target->state == TARGET_HALTED); + RISCV_INFO(r); int result; - if (!r->is_halted) { + if (!r->get_hart_state) { struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; result = tt->resume(target, current, address, handle_breakpoints, debug_execution); } else { @@ -1486,6 +2133,7 @@ static int resume_go(struct target *target, int current, static int resume_finish(struct target *target, int debug_execution) { + assert(target->state == TARGET_HALTED); register_cache_invalidate(target->reg_cache); target->state = debug_execution ? TARGET_DEBUG_RUNNING : TARGET_RUNNING; @@ -1498,7 +2146,7 @@ static int resume_finish(struct target *target, int debug_execution) * @par single_hart When true, only resume a single hart even if SMP is * configured. This is used to run algorithms on just one hart. */ -int riscv_resume( +static int riscv_resume( struct target *target, int current, target_addr_t address, @@ -1506,158 +2154,230 @@ int riscv_resume( int debug_execution, bool single_hart) { - LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); int result = ERROR_OK; + + struct list_head *targets; + + LIST_HEAD(single_target_list); + struct target_list single_target_entry = { + .lh = {NULL, NULL}, + .target = target + }; + if (target->smp && !single_hart) { - struct target_list *tlist; - foreach_smp_target_direction(resume_order == RO_NORMAL, - tlist, target->smp_targets) { - struct target *t = tlist->target; - if (resume_prep(t, current, address, handle_breakpoints, + targets = target->smp_targets; + } else { + /* Make a list that just contains a single target, so we can + * share code below. */ + list_add(&single_target_entry.lh, &single_target_list); + targets = &single_target_list; + } + + LOG_TARGET_DEBUG(target, "current=%s, address=0x%" + TARGET_PRIxADDR ", handle_breakpoints=%s, debug_exec=%s", + current ? "true" : "false", + address, + handle_breakpoints ? "true" : "false", + debug_execution ? "true" : "false"); + + struct target_list *tlist; + foreach_smp_target_direction(resume_order == RO_NORMAL, tlist, targets) { + struct target *t = tlist->target; + LOG_TARGET_DEBUG(t, "target->state=%s", target_state_name(t)); + if (t->state != TARGET_HALTED) + LOG_TARGET_DEBUG(t, "skipping this target: target not halted"); + else if (resume_prep(t, current, address, handle_breakpoints, + debug_execution) != ERROR_OK) + result = ERROR_FAIL; + } + + foreach_smp_target_direction(resume_order == RO_NORMAL, tlist, targets) { + struct target *t = tlist->target; + struct riscv_info *i = riscv_info(t); + if (i->prepped) { + if (resume_go(t, current, address, handle_breakpoints, debug_execution) != ERROR_OK) result = ERROR_FAIL; } + } - foreach_smp_target_direction(resume_order == RO_NORMAL, - tlist, target->smp_targets) { - struct target *t = tlist->target; - riscv_info_t *i = riscv_info(t); - if (i->prepped) { - if (resume_go(t, current, address, handle_breakpoints, - debug_execution) != ERROR_OK) - result = ERROR_FAIL; - } - } - - foreach_smp_target_direction(resume_order == RO_NORMAL, - tlist, target->smp_targets) { - struct target *t = tlist->target; + foreach_smp_target_direction(resume_order == RO_NORMAL, tlist, targets) { + struct target *t = tlist->target; + if (t->state == TARGET_HALTED) { if (resume_finish(t, debug_execution) != ERROR_OK) result = ERROR_FAIL; } - - } else { - if (resume_prep(target, current, address, handle_breakpoints, - debug_execution) != ERROR_OK) - result = ERROR_FAIL; - if (resume_go(target, current, address, handle_breakpoints, - debug_execution) != ERROR_OK) - result = ERROR_FAIL; - if (resume_finish(target, debug_execution) != ERROR_OK) - return ERROR_FAIL; } return result; } -static int riscv_target_resume(struct target *target, int current, target_addr_t address, - int handle_breakpoints, int debug_execution) +static int riscv_target_resume(struct target *target, int current, + target_addr_t address, int handle_breakpoints, int debug_execution) { + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "Not halted."); + return ERROR_TARGET_NOT_HALTED; + } return riscv_resume(target, current, address, handle_breakpoints, debug_execution, false); } +static int riscv_effective_privilege_mode(struct target *target, int *v_mode, int *effective_mode) +{ + riscv_reg_t priv; + if (riscv_get_register(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read priv register."); + return ERROR_FAIL; + } + *v_mode = get_field(priv, VIRT_PRIV_V); + + riscv_reg_t mstatus; + if (riscv_get_register(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read mstatus register."); + return ERROR_FAIL; + } + + if (get_field(mstatus, MSTATUS_MPRV)) + *effective_mode = get_field(mstatus, MSTATUS_MPP); + else + *effective_mode = get_field(priv, VIRT_PRIV_PRV); + + LOG_TARGET_DEBUG(target, "Effective mode=%d; v=%d", *effective_mode, *v_mode); + + return ERROR_OK; +} + static int riscv_mmu(struct target *target, int *enabled) { - if (!riscv_enable_virt2phys) { - *enabled = 0; + *enabled = 0; + + if (!riscv_enable_virt2phys) return ERROR_OK; - } /* Don't use MMU in explicit or effective M (machine) mode */ riscv_reg_t priv; if (riscv_get_register(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) { - LOG_ERROR("Failed to read priv register."); + LOG_TARGET_ERROR(target, "Failed to read priv register."); return ERROR_FAIL; } - riscv_reg_t mstatus; - if (riscv_get_register(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) { - LOG_ERROR("Failed to read mstatus register."); + int effective_mode; + int v_mode; + if (riscv_effective_privilege_mode(target, &v_mode, &effective_mode) != ERROR_OK) return ERROR_FAIL; + + unsigned int xlen = riscv_xlen(target); + + if (v_mode) { + /* vsatp and hgatp registers are considered active for the + * purposes of the address-translation algorithm unless the + * effective privilege mode is U and hstatus.HU=0. */ + if (effective_mode == PRV_U) { + riscv_reg_t hstatus; + if (riscv_get_register(target, &hstatus, GDB_REGNO_HSTATUS) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read hstatus register."); + return ERROR_FAIL; + } + + if (get_field(hstatus, HSTATUS_HU) == 0) + /* In hypervisor mode regular satp translation + * doesn't happen. */ + return ERROR_OK; + + } + + riscv_reg_t vsatp; + if (riscv_get_register(target, &vsatp, GDB_REGNO_VSATP) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read vsatp register; priv=0x%" PRIx64, + priv); + return ERROR_FAIL; + } + /* vsatp is identical to satp, so we can use the satp macros. */ + if (RISCV_SATP_MODE(xlen) != SATP_MODE_OFF) { + LOG_TARGET_DEBUG(target, "VS-stage translation is enabled."); + *enabled = 1; + return ERROR_OK; + } + + riscv_reg_t hgatp; + if (riscv_get_register(target, &hgatp, GDB_REGNO_HGATP) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read hgatp register; priv=0x%" PRIx64, + priv); + return ERROR_FAIL; + } + if (RISCV_HGATP_MODE(xlen) != HGATP_MODE_OFF) { + LOG_TARGET_DEBUG(target, "G-stage address translation is enabled."); + *enabled = 1; + } else { + LOG_TARGET_DEBUG(target, "No V-mode address translation enabled."); + } + + return ERROR_OK; } - if ((get_field(mstatus, MSTATUS_MPRV) ? get_field(mstatus, MSTATUS_MPP) : priv) == PRV_M) { - LOG_DEBUG("SATP/MMU ignored in Machine mode (mstatus=0x%" PRIx64 ").", mstatus); - *enabled = 0; + /* Don't use MMU in explicit or effective M (machine) mode */ + if (effective_mode == PRV_M) { + LOG_TARGET_DEBUG(target, "SATP/MMU ignored in Machine mode."); return ERROR_OK; } riscv_reg_t satp; if (riscv_get_register(target, &satp, GDB_REGNO_SATP) != ERROR_OK) { - LOG_DEBUG("Couldn't read SATP."); + LOG_TARGET_DEBUG(target, "Couldn't read SATP."); /* If we can't read SATP, then there must not be an MMU. */ - *enabled = 0; return ERROR_OK; } - if (get_field(satp, RISCV_SATP_MODE(riscv_xlen(target))) == SATP_MODE_OFF) { - LOG_DEBUG("MMU is disabled."); - *enabled = 0; + if (get_field(satp, RISCV_SATP_MODE(xlen)) == SATP_MODE_OFF) { + LOG_TARGET_DEBUG(target, "MMU is disabled."); } else { - LOG_DEBUG("MMU is enabled."); + LOG_TARGET_DEBUG(target, "MMU is enabled."); *enabled = 1; } return ERROR_OK; } +/* Translate address from virtual to physical, using info and ppn. + * If extra_info is non-NULL, then translate page table accesses for the primary + * translation using extra_info and extra_ppn. */ static int riscv_address_translate(struct target *target, + const virt2phys_info_t *info, target_addr_t ppn, + const virt2phys_info_t *extra_info, target_addr_t extra_ppn, target_addr_t virtual, target_addr_t *physical) { RISCV_INFO(r); - riscv_reg_t satp_value; - int mode; - uint64_t ppn_value; - target_addr_t table_address; - const virt2phys_info_t *info; - uint64_t pte = 0; - int i; + unsigned int xlen = riscv_xlen(target); - int result = riscv_get_register(target, &satp_value, GDB_REGNO_SATP); - if (result != ERROR_OK) - return result; - - unsigned xlen = riscv_xlen(target); - mode = get_field(satp_value, RISCV_SATP_MODE(xlen)); - switch (mode) { - case SATP_MODE_SV32: - info = &sv32; - break; - case SATP_MODE_SV39: - info = &sv39; - break; - case SATP_MODE_SV48: - info = &sv48; - break; - case SATP_MODE_OFF: - LOG_ERROR("No translation or protection." \ - " (satp: 0x%" PRIx64 ")", satp_value); - return ERROR_FAIL; - default: - LOG_ERROR("The translation mode is not supported." \ - " (satp: 0x%" PRIx64 ")", satp_value); - return ERROR_FAIL; - } - LOG_DEBUG("virtual=0x%" TARGET_PRIxADDR "; mode=%s", virtual, info->name); + LOG_TARGET_DEBUG(target, "mode=%s; ppn=0x%" TARGET_PRIxADDR "; virtual=0x%" TARGET_PRIxADDR, + info->name, ppn, virtual); /* verify bits xlen-1:va_bits-1 are all equal */ + assert(xlen >= info->va_bits); target_addr_t mask = ((target_addr_t)1 << (xlen - (info->va_bits - 1))) - 1; target_addr_t masked_msbs = (virtual >> (info->va_bits - 1)) & mask; if (masked_msbs != 0 && masked_msbs != mask) { - LOG_ERROR("Virtual address 0x%" TARGET_PRIxADDR " is not sign-extended " + LOG_TARGET_ERROR(target, "Virtual address 0x%" TARGET_PRIxADDR " is not sign-extended " "for %s mode.", virtual, info->name); return ERROR_FAIL; } - ppn_value = get_field(satp_value, RISCV_SATP_PPN(xlen)); - table_address = ppn_value << RISCV_PGSHIFT; - i = info->level - 1; + uint64_t pte = 0; + target_addr_t table_address = ppn << RISCV_PGSHIFT; + int i = info->level - 1; while (i >= 0) { uint64_t vpn = virtual >> info->vpn_shift[i]; vpn &= info->vpn_mask[i]; - target_addr_t pte_address = table_address + - (vpn << info->pte_shift); + target_addr_t pte_address = table_address + (vpn << info->pte_shift); + + if (extra_info) { + /* Perform extra stage translation. */ + if (riscv_address_translate(target, extra_info, extra_ppn, + NULL, 0, pte_address, &pte_address) != ERROR_OK) + return ERROR_FAIL; + } + uint8_t buffer[8]; assert(info->pte_shift <= 3); int retval = r->read_memory(target, pte_address, @@ -1670,24 +2390,27 @@ static int riscv_address_translate(struct target *target, else pte = buf_get_u64(buffer, 0, 64); - LOG_DEBUG("i=%d; PTE @0x%" TARGET_PRIxADDR " = 0x%" PRIx64, i, + LOG_TARGET_DEBUG(target, "i=%d; PTE @0x%" TARGET_PRIxADDR " = 0x%" PRIx64, i, pte_address, pte); - if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) + if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) { + LOG_TARGET_ERROR(target, "invalid PTE @0x%" TARGET_PRIxADDR ": 0x%" PRIx64 + "; mode=%s; i=%d", pte_address, pte, info->name, i); return ERROR_FAIL; + } - if ((pte & PTE_R) || (pte & PTE_X)) /* Found leaf PTE. */ + if ((pte & PTE_R) || (pte & PTE_W) || (pte & PTE_X)) /* Found leaf PTE. */ break; i--; if (i < 0) break; - ppn_value = pte >> PTE_PPN_SHIFT; - table_address = ppn_value << RISCV_PGSHIFT; + ppn = pte >> PTE_PPN_SHIFT; + table_address = ppn << RISCV_PGSHIFT; } if (i < 0) { - LOG_ERROR("Couldn't find the PTE."); + LOG_TARGET_ERROR(target, "Couldn't find the PTE."); return ERROR_FAIL; } @@ -1695,15 +2418,125 @@ static int riscv_address_translate(struct target *target, *physical = virtual & (((target_addr_t)1 << info->va_bits) - 1); while (i < info->level) { - ppn_value = pte >> info->pte_ppn_shift[i]; - ppn_value &= info->pte_ppn_mask[i]; + ppn = pte >> info->pte_ppn_shift[i]; + ppn &= info->pte_ppn_mask[i]; *physical &= ~(((target_addr_t)info->pa_ppn_mask[i]) << info->pa_ppn_shift[i]); - *physical |= (ppn_value << info->pa_ppn_shift[i]); + *physical |= (ppn << info->pa_ppn_shift[i]); i++; } - LOG_DEBUG("0x%" TARGET_PRIxADDR " -> 0x%" TARGET_PRIxADDR, virtual, - *physical); + LOG_TARGET_DEBUG(target, "mode=%s; 0x%" TARGET_PRIxADDR " -> 0x%" TARGET_PRIxADDR, + info->name, virtual, *physical); + return ERROR_OK; +} + +/* Virtual to physical translation for hypervisor mode. */ +static int riscv_virt2phys_v(struct target *target, target_addr_t virtual, target_addr_t *physical) +{ + riscv_reg_t vsatp; + if (riscv_get_register(target, &vsatp, GDB_REGNO_VSATP) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read vsatp register."); + return ERROR_FAIL; + } + /* vsatp is identical to satp, so we can use the satp macros. */ + unsigned int xlen = riscv_xlen(target); + int vsatp_mode = get_field(vsatp, RISCV_SATP_MODE(xlen)); + LOG_TARGET_DEBUG(target, "VS-stage translation mode: %d", vsatp_mode); + riscv_reg_t hgatp; + if (riscv_get_register(target, &hgatp, GDB_REGNO_HGATP) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read hgatp register."); + return ERROR_FAIL; + } + int hgatp_mode = get_field(hgatp, RISCV_HGATP_MODE(xlen)); + LOG_TARGET_DEBUG(target, "G-stage translation mode: %d", hgatp_mode); + + const virt2phys_info_t *vsatp_info; + /* VS-stage address translation. */ + switch (vsatp_mode) { + case SATP_MODE_SV32: + vsatp_info = &sv32; + break; + case SATP_MODE_SV39: + vsatp_info = &sv39; + break; + case SATP_MODE_SV48: + vsatp_info = &sv48; + break; + case SATP_MODE_SV57: + vsatp_info = &sv57; + break; + case SATP_MODE_OFF: + vsatp_info = NULL; + LOG_TARGET_DEBUG(target, "vsatp mode is %d. No VS-stage translation. (vsatp: 0x%" PRIx64 ")", + vsatp_mode, vsatp); + break; + default: + LOG_TARGET_ERROR(target, + "vsatp mode %d is not supported. (vsatp: 0x%" PRIx64 ")", + vsatp_mode, vsatp); + return ERROR_FAIL; + } + + const virt2phys_info_t *hgatp_info; + /* G-stage address translation. */ + switch (hgatp_mode) { + case HGATP_MODE_SV32X4: + hgatp_info = &sv32x4; + break; + case HGATP_MODE_SV39X4: + hgatp_info = &sv39x4; + break; + case HGATP_MODE_SV48X4: + hgatp_info = &sv48x4; + break; + case HGATP_MODE_SV57X4: + hgatp_info = &sv57x4; + break; + case HGATP_MODE_OFF: + hgatp_info = NULL; + LOG_TARGET_DEBUG(target, "hgatp mode is %d. No G-stage translation. (hgatp: 0x%" PRIx64 ")", + hgatp_mode, hgatp); + break; + default: + LOG_TARGET_ERROR(target, + "hgatp mode %d is not supported. (hgatp: 0x%" PRIx64 ")", + hgatp_mode, hgatp); + return ERROR_FAIL; + } + + /* For any virtual memory access, the original virtual address is + * converted in the first stage by VS-level address translation, + * as controlled by the vsatp register, into a guest physical + * address. */ + target_addr_t guest_physical; + if (vsatp_info) { + /* When V=1, memory accesses that would normally bypass + * address translation are subject to G- stage address + * translation alone. This includes memory accesses made + * in support of VS-stage address translation, such as + * reads and writes of VS-level page tables. */ + + if (riscv_address_translate(target, + vsatp_info, get_field(vsatp, RISCV_SATP_PPN(xlen)), + hgatp_info, get_field(hgatp, RISCV_SATP_PPN(xlen)), + virtual, &guest_physical) != ERROR_OK) + return ERROR_FAIL; + } else { + guest_physical = virtual; + } + + /* The guest physical address is then converted in the second + * stage by guest physical address translation, as controlled by + * the hgatp register, into a supervisor physical address. */ + if (hgatp_info) { + if (riscv_address_translate(target, + hgatp_info, get_field(hgatp, RISCV_HGATP_PPN(xlen)), + NULL, 0, + guest_physical, physical) != ERROR_OK) + return ERROR_FAIL; + } else { + *physical = guest_physical; + } return ERROR_OK; } @@ -1711,15 +2544,59 @@ static int riscv_address_translate(struct target *target, static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical) { int enabled; - if (riscv_mmu(target, &enabled) == ERROR_OK) { - if (!enabled) - return ERROR_FAIL; + if (riscv_mmu(target, &enabled) != ERROR_OK) + return ERROR_FAIL; + if (!enabled) { + *physical = virtual; + LOG_TARGET_DEBUG(target, "MMU is disabled. 0x%" TARGET_PRIxADDR " -> 0x%" TARGET_PRIxADDR, virtual, *physical); + return ERROR_OK; + } - if (riscv_address_translate(target, virtual, physical) == ERROR_OK) - return ERROR_OK; + riscv_reg_t priv; + if (riscv_get_register(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read priv register."); + return ERROR_FAIL; } - return ERROR_FAIL; + if (priv & VIRT_PRIV_V) + return riscv_virt2phys_v(target, virtual, physical); + + riscv_reg_t satp_value; + if (riscv_get_register(target, &satp_value, GDB_REGNO_SATP) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read SATP register."); + return ERROR_FAIL; + } + + unsigned int xlen = riscv_xlen(target); + int satp_mode = get_field(satp_value, RISCV_SATP_MODE(xlen)); + const virt2phys_info_t *satp_info; + switch (satp_mode) { + case SATP_MODE_SV32: + satp_info = &sv32; + break; + case SATP_MODE_SV39: + satp_info = &sv39; + break; + case SATP_MODE_SV48: + satp_info = &sv48; + break; + case SATP_MODE_SV57: + satp_info = &sv57; + break; + case SATP_MODE_OFF: + LOG_TARGET_ERROR(target, "No translation or protection." + " (satp: 0x%" PRIx64 ")", satp_value); + return ERROR_FAIL; + default: + LOG_TARGET_ERROR(target, "The translation mode is not supported." + " (satp: 0x%" PRIx64 ")", satp_value); + return ERROR_FAIL; + } + + return riscv_address_translate(target, + satp_info, get_field(satp_value, RISCV_SATP_PPN(xlen)), + NULL, 0, + virtual, physical); } static int riscv_read_phys_memory(struct target *target, target_addr_t phys_address, @@ -1733,22 +2610,27 @@ static int riscv_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { if (count == 0) { - LOG_WARNING("0-length read from 0x%" TARGET_PRIxADDR, address); + LOG_TARGET_WARNING(target, "0-length read from 0x%" TARGET_PRIxADDR, address); return ERROR_OK; } target_addr_t physical_addr; - if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK) - address = physical_addr; + int result = target->type->virt2phys(target, address, &physical_addr); + if (result != ERROR_OK) { + LOG_TARGET_ERROR(target, "Address translation failed."); + return result; + } RISCV_INFO(r); - return r->read_memory(target, address, size, count, buffer, size); + return r->read_memory(target, physical_addr, size, count, buffer, size); } static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; return tt->write_memory(target, phys_address, size, count, buffer); } @@ -1756,19 +2638,24 @@ static int riscv_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { if (count == 0) { - LOG_WARNING("0-length write to 0x%" TARGET_PRIxADDR, address); + LOG_TARGET_WARNING(target, "0-length write to 0x%" TARGET_PRIxADDR, address); return ERROR_OK; } target_addr_t physical_addr; - if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK) - address = physical_addr; + int result = target->type->virt2phys(target, address, &physical_addr); + if (result != ERROR_OK) { + LOG_TARGET_ERROR(target, "Address translation failed."); + return result; + } struct target_type *tt = get_target_type(target); - return tt->write_memory(target, address, size, count, buffer); + if (!tt) + return ERROR_FAIL; + return tt->write_memory(target, physical_addr, size, count, buffer); } -const char *riscv_get_gdb_arch(struct target *target) +static const char *riscv_get_gdb_arch(const struct target *target) { switch (riscv_xlen(target)) { case 32: @@ -1776,18 +2663,18 @@ const char *riscv_get_gdb_arch(struct target *target) case 64: return "riscv:rv64"; } - LOG_ERROR("Unsupported xlen: %d", riscv_xlen(target)); + LOG_TARGET_ERROR(target, "Unsupported xlen: %d", riscv_xlen(target)); return NULL; } static int riscv_get_gdb_reg_list_internal(struct target *target, struct reg **reg_list[], int *reg_list_size, - enum target_register_class reg_class, bool read) + enum target_register_class reg_class, bool is_read) { - LOG_TARGET_DEBUG(target, "reg_class=%d, read=%d", reg_class, read); + LOG_TARGET_DEBUG(target, "reg_class=%d, read=%d", reg_class, is_read); if (!target->reg_cache) { - LOG_ERROR("Target not initialized. Return ERROR_FAIL."); + LOG_TARGET_ERROR(target, "Target not initialized. Return ERROR_FAIL."); return ERROR_FAIL; } @@ -1799,7 +2686,7 @@ static int riscv_get_gdb_reg_list_internal(struct target *target, *reg_list_size = target->reg_cache->num_regs; break; default: - LOG_ERROR("Unsupported reg_class: %d", reg_class); + LOG_TARGET_ERROR(target, "Unsupported reg_class: %d", reg_class); return ERROR_FAIL; } @@ -1811,7 +2698,7 @@ static int riscv_get_gdb_reg_list_internal(struct target *target, assert(!target->reg_cache->reg_list[i].valid || target->reg_cache->reg_list[i].size > 0); (*reg_list)[i] = &target->reg_cache->reg_list[i]; - if (read && + if (is_read && target->reg_cache->reg_list[i].exist && !target->reg_cache->reg_list[i].valid) { if (target->reg_cache->reg_list[i].type->get( @@ -1841,7 +2728,17 @@ static int riscv_get_gdb_reg_list(struct target *target, static int riscv_arch_state(struct target *target) { + assert(target->state == TARGET_HALTED); + const bool semihosting_active = target->semihosting && + target->semihosting->is_active; + LOG_USER("%s halted due to %s.%s", + target_name(target), + debug_reason_name(target), + semihosting_active ? " Semihosting is active." : ""); struct target_type *tt = get_target_type(target); + if (!tt) + return ERROR_FAIL; + assert(tt->arch_state); return tt->arch_state(target); } @@ -1849,20 +2746,23 @@ static int riscv_arch_state(struct target *target) static int riscv_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, - target_addr_t exit_point, int timeout_ms, void *arch_info) + target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { RISCV_INFO(info); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted (run target algo)"); return ERROR_TARGET_NOT_HALTED; } - + + /* Write memory parameters to the target memory */ for (int i = 0; i < num_mem_params; i++) { - if (mem_params[i].direction != PARAM_IN) { + if (mem_params[i].direction == PARAM_OUT || + mem_params[i].direction == PARAM_IN_OUT) { int retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); - if (retval != ERROR_OK){ - LOG_ERROR("Couldn't write input mem param into the memory."); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "Couldn't write input mem param into the memory, addr=0x%" TARGET_PRIxADDR + " size=0x%" PRIx32, mem_params[i].address, mem_params[i].size); return retval; } } @@ -1874,25 +2774,25 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, if (!reg_pc || reg_pc->type->get(reg_pc) != ERROR_OK) return ERROR_FAIL; uint64_t saved_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size); - LOG_DEBUG("saved_pc=0x%" PRIx64, saved_pc); + LOG_TARGET_DEBUG(target, "saved_pc=0x%" PRIx64, saved_pc); uint64_t saved_regs[32]; for (int i = 0; i < num_reg_params; i++) { - LOG_DEBUG("save %s", reg_params[i].reg_name); + LOG_TARGET_DEBUG(target, "save %s", reg_params[i].reg_name); struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, false); if (!r) { - LOG_ERROR("Couldn't find register named '%s'", reg_params[i].reg_name); + LOG_TARGET_ERROR(target, "Couldn't find register named '%s'", reg_params[i].reg_name); return ERROR_FAIL; } if (r->size != reg_params[i].size) { - LOG_ERROR("Register %s is %d bits instead of %d bits.", + LOG_TARGET_ERROR(target, "Register %s is %d bits instead of %d bits.", reg_params[i].reg_name, r->size, reg_params[i].size); return ERROR_FAIL; } if (r->number > GDB_REGNO_XPR31) { - LOG_ERROR("Only GPRs can be use as argument registers."); + LOG_TARGET_ERROR(target, "Only GPRs can be use as argument registers."); return ERROR_FAIL; } @@ -1913,16 +2813,16 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, return ERROR_FAIL; /* Run algorithm */ - LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point); + LOG_TARGET_DEBUG(target, "Resume at 0x%" TARGET_PRIxADDR, entry_point); if (riscv_resume(target, 0, entry_point, 0, 1, true) != ERROR_OK) return ERROR_FAIL; int64_t start = timeval_ms(); while (target->state != TARGET_HALTED) { - LOG_DEBUG("poll()"); + LOG_TARGET_DEBUG(target, "poll()"); int64_t now = timeval_ms(); if (now - start > timeout_ms) { - LOG_ERROR("Algorithm timed out after %" PRId64 " ms.", now - start); + LOG_TARGET_ERROR(target, "Algorithm timed out after %" PRId64 " ms.", now - start); riscv_halt(target); old_or_new_riscv_poll(target); enum gdb_regno regnums[] = { @@ -1942,7 +2842,8 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, riscv_reg_t reg_value; if (riscv_get_register(target, ®_value, regno) != ERROR_OK) break; - LOG_ERROR("%s = 0x%" PRIx64, gdb_regno_name(regno), reg_value); + + LOG_TARGET_ERROR(target, "%s = 0x%" PRIx64, gdb_regno_name(target, regno), reg_value); } return ERROR_TARGET_TIMEOUT; } @@ -1960,7 +2861,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, return ERROR_FAIL; uint64_t final_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size); if (exit_point && final_pc != exit_point) { - LOG_ERROR("PC ended up at 0x%" PRIx64 " instead of 0x%" + LOG_TARGET_ERROR(target, "PC ended up at 0x%" PRIx64 " instead of 0x%" TARGET_PRIxADDR, final_pc, exit_point); return ERROR_FAIL; } @@ -1980,26 +2881,41 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, reg_params[i].direction == PARAM_IN_OUT) { struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, false); if (r->type->get(r) != ERROR_OK) { - LOG_ERROR("get(%s) failed", r->name); + LOG_TARGET_ERROR(target, "get(%s) failed", r->name); return ERROR_FAIL; } buf_cpy(r->value, reg_params[i].value, reg_params[i].size); } - LOG_DEBUG("restore %s", reg_params[i].reg_name); + LOG_TARGET_DEBUG(target, "restore %s", reg_params[i].reg_name); struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, false); buf_set_u64(buf, 0, info->xlen, saved_regs[r->number]); if (r->type->set(r, buf) != ERROR_OK) { - LOG_ERROR("set(%s) failed", r->name); + LOG_TARGET_ERROR(target, "set(%s) failed", r->name); return ERROR_FAIL; } } for (int i = 0; i < num_mem_params; i++) { - if (mem_params[i].direction != PARAM_OUT) { + if (mem_params[i].direction != PARAM_OUT) { + int retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, + mem_params[i].value); + if (retval != ERROR_OK){ + LOG_ERROR("Couldn't read output mem param from the memory."); + return retval; + } + } + } + + /* Read memory parameters from the target memory */ + for (int i = 0; i < num_mem_params; i++) { + if (mem_params[i].direction == PARAM_IN || + mem_params[i].direction == PARAM_IN_OUT) { int retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); - if (retval != ERROR_OK){ - LOG_ERROR("Couldn't read output mem param from the memory."); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "Couldn't read output mem param from the memory, " + "addr=0x%" TARGET_PRIxADDR " size=0x%" PRIx32, + mem_params[i].address, mem_params[i].size); return retval; } } @@ -2016,7 +2932,7 @@ static int riscv_checksum_memory(struct target *target, struct reg_param reg_params[2]; int retval; - LOG_DEBUG("address=0x%" TARGET_PRIxADDR "; count=0x%" PRIx32, address, count); + LOG_TARGET_DEBUG(target, "address=0x%" TARGET_PRIxADDR "; count=0x%" PRIx32, address, count); static const uint8_t riscv32_crc_code[] = { #include "../../../contrib/loaders/checksum/riscv32_crc.inc" @@ -2060,7 +2976,7 @@ static int riscv_checksum_memory(struct target *target, retval = target_write_buffer(target, crc_algorithm->address, crc_code_size, crc_code); if (retval != ERROR_OK) { - LOG_ERROR("Failed to write code to " TARGET_ADDR_FMT ": %d", + LOG_TARGET_ERROR(target, "Failed to write code to " TARGET_ADDR_FMT ": %d", crc_algorithm->address, retval); target_free_working_area(target, crc_algorithm); return retval; @@ -2072,7 +2988,7 @@ static int riscv_checksum_memory(struct target *target, buf_set_u64(reg_params[1].value, 0, xlen, count); /* 20 second timeout/megabyte */ - int timeout = 20000 * (1 + (count / (1024 * 1024))); + unsigned int timeout = 20000 * (1 + (count / (1024 * 1024))); retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, @@ -2082,65 +2998,164 @@ static int riscv_checksum_memory(struct target *target, if (retval == ERROR_OK) *checksum = buf_get_u32(reg_params[0].value, 0, 32); else - LOG_ERROR("error executing RISC-V CRC algorithm"); + LOG_TARGET_ERROR(target, "Error executing RISC-V CRC algorithm."); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); target_free_working_area(target, crc_algorithm); - LOG_DEBUG("checksum=0x%" PRIx32 ", result=%d", *checksum, retval); + LOG_TARGET_DEBUG(target, "checksum=0x%" PRIx32 ", result=%d", *checksum, retval); return retval; } /*** OpenOCD Helper Functions ***/ -enum riscv_poll_hart { - RPH_NO_CHANGE, - RPH_DISCOVERED_HALTED, - RPH_DISCOVERED_RUNNING, - RPH_ERROR +enum riscv_next_action { + RPH_NONE, + RPH_RESUME, + RPH_REMAIN_HALTED }; -static enum riscv_poll_hart riscv_poll_hart(struct target *target, int hartid) +static int riscv_poll_hart(struct target *target, enum riscv_next_action *next_action) { RISCV_INFO(r); LOG_TARGET_DEBUG(target, "polling, target->state=%d", target->state); + *next_action = RPH_NONE; + + enum riscv_hart_state previous_riscv_state = 0; + enum target_state previous_target_state = target->state; + switch (target->state) { + case TARGET_UNKNOWN: + /* Special case, handled further down. */ + previous_riscv_state = RISCV_STATE_UNAVAILABLE; /* Need to assign something. */ + break; + case TARGET_RUNNING: + previous_riscv_state = RISCV_STATE_RUNNING; + break; + case TARGET_HALTED: + previous_riscv_state = RISCV_STATE_HALTED; + break; + case TARGET_RESET: + previous_riscv_state = RISCV_STATE_HALTED; + break; + case TARGET_DEBUG_RUNNING: + previous_riscv_state = RISCV_STATE_RUNNING; + break; + case TARGET_UNAVAILABLE: + previous_riscv_state = RISCV_STATE_UNAVAILABLE; + break; + } + /* If OpenOCD thinks we're running but this hart is halted then it's time * to raise an event. */ - bool halted = riscv_is_halted(target); + enum riscv_hart_state state; + if (riscv_get_hart_state(target, &state) != ERROR_OK) + return ERROR_FAIL; + + if (state == RISCV_STATE_NON_EXISTENT) { + LOG_TARGET_ERROR(target, "Hart is non-existent!"); + return ERROR_FAIL; + } - if (halted && timeval_ms() - r->last_activity > 100) { + if (state == RISCV_STATE_HALTED && timeval_ms() - r->last_activity > 100) { /* If we've been idle for a while, flush the register cache. Just in case * OpenOCD is going to be disconnected without shutting down cleanly. */ if (riscv_flush_registers(target) != ERROR_OK) return ERROR_FAIL; } - if (target->state != TARGET_HALTED && halted) { - LOG_DEBUG(" triggered a halt"); - r->on_halt(target); - return RPH_DISCOVERED_HALTED; - } else if (target->state != TARGET_RUNNING && target->state != TARGET_DEBUG_RUNNING && !halted) { - LOG_DEBUG(" triggered running"); - target->state = TARGET_RUNNING; - target->debug_reason = DBG_REASON_NOTHALTED; - return RPH_DISCOVERED_RUNNING; + if (target->state == TARGET_UNKNOWN || state != previous_riscv_state) { + switch (state) { + case RISCV_STATE_HALTED: + if (previous_riscv_state == RISCV_STATE_UNAVAILABLE) + LOG_TARGET_INFO(target, "became available (halted)"); + + LOG_TARGET_DEBUG(target, " triggered a halt; previous_target_state=%d", + previous_target_state); + target->state = TARGET_HALTED; + enum riscv_halt_reason halt_reason = riscv_halt_reason(target); + if (set_debug_reason(target, halt_reason) != ERROR_OK) + return ERROR_FAIL; + + if (halt_reason == RISCV_HALT_EBREAK) { + int retval; + /* Detect if this EBREAK is a semihosting request. If so, handle it. */ + switch (riscv_semihosting(target, &retval)) { + case SEMIHOSTING_NONE: + break; + case SEMIHOSTING_WAITING: + /* This hart should remain halted. */ + *next_action = RPH_REMAIN_HALTED; + break; + case SEMIHOSTING_HANDLED: + /* This hart should be resumed, along with any other + * harts that halted due to haltgroups. */ + *next_action = RPH_RESUME; + return ERROR_OK; + case SEMIHOSTING_ERROR: + return retval; + } + } + + if (r->handle_became_halted && + r->handle_became_halted(target, previous_riscv_state) != ERROR_OK) + return ERROR_FAIL; + + /* We shouldn't do the callbacks yet. What if + * there are multiple harts that halted at the + * same time? We need to set debug reason on each + * of them before calling a callback, which is + * going to figure out the "current thread". */ + + r->halted_needs_event_callback = true; + if (previous_target_state == TARGET_DEBUG_RUNNING) + r->halted_callback_event = TARGET_EVENT_DEBUG_HALTED; + else + r->halted_callback_event = TARGET_EVENT_HALTED; + break; + + case RISCV_STATE_RUNNING: + if (previous_riscv_state == RISCV_STATE_UNAVAILABLE) + LOG_TARGET_INFO(target, "became available (running)"); + + LOG_TARGET_DEBUG(target, " triggered running"); + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + if (r->handle_became_running && + r->handle_became_running(target, previous_riscv_state) != ERROR_OK) + return ERROR_FAIL; + break; + + case RISCV_STATE_UNAVAILABLE: + LOG_TARGET_DEBUG(target, " became unavailable"); + LOG_TARGET_INFO(target, "became unavailable."); + target->state = TARGET_UNAVAILABLE; + if (r->handle_became_unavailable && + r->handle_became_unavailable(target, previous_riscv_state) != ERROR_OK) + return ERROR_FAIL; + break; + + case RISCV_STATE_NON_EXISTENT: + LOG_TARGET_ERROR(target, "Hart is non-existent!"); + target->state = TARGET_UNAVAILABLE; + break; + } } - return RPH_NO_CHANGE; + return ERROR_OK; } -int sample_memory(struct target *target) +static int sample_memory(struct target *target) { RISCV_INFO(r); if (!r->sample_buf.buf || !r->sample_config.enabled) return ERROR_OK; - LOG_DEBUG("buf used/size: %d/%d", r->sample_buf.used, r->sample_buf.size); + LOG_TARGET_DEBUG(target, "buf used/size: %d/%d", r->sample_buf.used, r->sample_buf.size); uint64_t start = timeval_ms(); riscv_sample_buf_maybe_add_timestamp(target, true); @@ -2174,7 +3189,7 @@ int sample_memory(struct target *target) exit: riscv_sample_buf_maybe_add_timestamp(target, false); if (result != ERROR_OK) { - LOG_INFO("Turning off memory sampling because it failed."); + LOG_TARGET_INFO(target, "Turning off memory sampling because it failed."); r->sample_config.enabled = false; } return result; @@ -2183,121 +3198,111 @@ int sample_memory(struct target *target) /*** OpenOCD Interface ***/ int riscv_openocd_poll(struct target *target) { - LOG_DEBUG("polling all harts"); - enum target_state old_state = target->state; + LOG_TARGET_DEBUG(target, "Polling all harts."); - if (target->smp) { - unsigned should_remain_halted = 0; - unsigned should_resume = 0; - struct target_list *list; - foreach_smp_target(list, target->smp_targets) { - struct target *t = list->target; - if (!target_was_examined(t)) - continue; - enum riscv_poll_hart out = riscv_poll_hart(t, t->coreid); - switch (out) { - case RPH_NO_CHANGE: - break; - case RPH_DISCOVERED_RUNNING: - t->state = TARGET_RUNNING; - t->debug_reason = DBG_REASON_NOTHALTED; - break; - case RPH_DISCOVERED_HALTED: - t->state = TARGET_HALTED; - enum riscv_halt_reason halt_reason = - riscv_halt_reason(t); - if (set_debug_reason(t, halt_reason) != ERROR_OK) - return ERROR_FAIL; + struct list_head *targets; - if (halt_reason == RISCV_HALT_BREAKPOINT) { - int retval; - switch (riscv_semihosting(t, &retval)) { - case SEMI_NONE: - case SEMI_WAITING: - /* This hart should remain halted. */ - should_remain_halted++; - break; - case SEMI_HANDLED: - /* This hart should be resumed, along with any other - * harts that halted due to haltgroups. */ - should_resume++; - break; - case SEMI_ERROR: - return retval; - } - } else if (halt_reason != RISCV_HALT_GROUP) { - should_remain_halted++; - } - break; + LIST_HEAD(single_target_list); + struct target_list single_target_entry = { + .lh = {NULL, NULL}, + .target = target + }; - case RPH_ERROR: - return ERROR_FAIL; - } - } + if (target->smp) { + targets = target->smp_targets; + } else { + /* Make a list that just contains a single target, so we can + * share code below. */ + list_add(&single_target_entry.lh, &single_target_list); + targets = &single_target_list; + } + + unsigned int should_remain_halted = 0; + unsigned int should_resume = 0; + unsigned int halted = 0; + unsigned int running = 0; + struct target_list *entry; + foreach_smp_target(entry, targets) { + struct target *t = entry->target; + struct riscv_info *info = riscv_info(t); + + /* Clear here just in case there were errors and we never got to + * check this flag further down. */ + info->halted_needs_event_callback = false; + + if (!target_was_examined(t)) + continue; - LOG_DEBUG("should_remain_halted=%d, should_resume=%d", - should_remain_halted, should_resume); - if (should_remain_halted && should_resume) { - LOG_WARNING("%d harts should remain halted, and %d should resume.", - should_remain_halted, should_resume); - } - if (should_remain_halted) { - LOG_DEBUG("halt all"); - riscv_halt(target); - } else if (should_resume) { - LOG_DEBUG("resume all"); - riscv_resume(target, true, 0, 0, 0, false); - } + enum riscv_next_action next_action; + if (riscv_poll_hart(t, &next_action) != ERROR_OK) + return ERROR_FAIL; - /* Sample memory if any target is running. */ - foreach_smp_target(list, target->smp_targets) { - struct target *t = list->target; - if (t->state == TARGET_RUNNING) { - sample_memory(target); + switch (next_action) { + case RPH_NONE: + if (t->state == TARGET_HALTED) + halted++; + if (t->state == TARGET_RUNNING || + t->state == TARGET_DEBUG_RUNNING) + running++; + break; + case RPH_REMAIN_HALTED: + should_remain_halted++; + break; + case RPH_RESUME: + should_resume++; break; - } } + } - return ERROR_OK; - + LOG_TARGET_DEBUG(target, "should_remain_halted=%d, should_resume=%d", + should_remain_halted, should_resume); + if (should_remain_halted && should_resume) { + LOG_TARGET_WARNING(target, "%d harts should remain halted, and %d should resume.", + should_remain_halted, should_resume); + } + if (should_remain_halted) { + LOG_TARGET_DEBUG(target, "halt all; should_remain_halted=%d", + should_remain_halted); + riscv_halt(target); + } else if (should_resume) { + LOG_TARGET_DEBUG(target, "resume all"); + riscv_resume(target, true, 0, 0, 0, false); + } else if (halted && running) { + LOG_TARGET_DEBUG(target, "halt all; halted=%d", + halted); + riscv_halt(target); } else { - enum riscv_poll_hart out = riscv_poll_hart(target, target->coreid); - if (out == RPH_NO_CHANGE || out == RPH_DISCOVERED_RUNNING) { - if (target->state == TARGET_RUNNING) - sample_memory(target); - return ERROR_OK; - } else if (out == RPH_ERROR) { - return ERROR_FAIL; + /* For targets that were discovered to be halted, call the + * appropriate callback. */ + foreach_smp_target(entry, targets) + { + struct target *t = entry->target; + struct riscv_info *info = riscv_info(t); + if (info->halted_needs_event_callback) { + target_call_event_callbacks(t, info->halted_callback_event); + info->halted_needs_event_callback = false; + } } + } - LOG_TARGET_DEBUG(target, "hart halted"); - - target->state = TARGET_HALTED; - enum riscv_halt_reason halt_reason = riscv_halt_reason(target); - if (set_debug_reason(target, halt_reason) != ERROR_OK) + /* Call tick() for every hart. What happens in tick() is opaque to this + * layer. The reason it's outside the previous loop is that at this point + * the state of every hart has settled, so any side effects happening in + * tick() won't affect the delicate poll() code. */ + foreach_smp_target(entry, targets) { + struct target *t = entry->target; + struct riscv_info *info = riscv_info(t); + if (info->tick && info->tick(t) != ERROR_OK) return ERROR_FAIL; - target->state = TARGET_HALTED; } - if (target->debug_reason == DBG_REASON_BREAKPOINT) { - int retval; - switch (riscv_semihosting(target, &retval)) { - case SEMI_NONE: - case SEMI_WAITING: - target_call_event_callbacks(target, TARGET_EVENT_HALTED); - break; - case SEMI_HANDLED: - if (riscv_resume(target, true, 0, 0, 0, false) != ERROR_OK) - return ERROR_FAIL; - break; - case SEMI_ERROR: - return retval; + /* Sample memory if any target is running. */ + foreach_smp_target(entry, targets) { + struct target *t = entry->target; + if (t->state == TARGET_RUNNING) { + sample_memory(target); + break; } - } else { - if (old_state == TARGET_DEBUG_RUNNING) - target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); - else - target_call_event_callbacks(target, TARGET_EVENT_HALTED); } return ERROR_OK; @@ -2339,14 +3344,14 @@ int riscv_openocd_step(struct target *target, int current, if (riscv_interrupts_disable(target, irq_disabled_mask, ¤t_mstatus) != ERROR_OK) { success = false; - LOG_ERROR("unable to disable interrupts"); + LOG_TARGET_ERROR(target, "Unable to disable interrupts."); goto _exit; } } if (riscv_step_rtos_hart(target) != ERROR_OK) { success = false; - LOG_ERROR("unable to step rtos hart"); + LOG_TARGET_ERROR(target, "Unable to step rtos hart."); } register_cache_invalidate(target->reg_cache); @@ -2354,18 +3359,18 @@ int riscv_openocd_step(struct target *target, int current, if (info->isrmask_mode == RISCV_ISRMASK_STEPONLY) if (riscv_interrupts_restore(target, current_mstatus) != ERROR_OK) { success = false; - LOG_ERROR("unable to restore interrupts"); + LOG_TARGET_ERROR(target, "Unable to restore interrupts."); } _exit: if (enable_triggers(target, trigger_state) != ERROR_OK) { success = false; - LOG_ERROR("unable to enable triggers"); + LOG_TARGET_ERROR(target, "Unable to enable triggers."); } if (breakpoint && (riscv_add_breakpoint(target, breakpoint) != ERROR_OK)) { success = false; - LOG_TARGET_ERROR(target, "unable to restore the disabled breakpoint"); + LOG_TARGET_ERROR(target, "Unable to restore the disabled breakpoint."); } if (success) { @@ -2382,7 +3387,7 @@ int riscv_openocd_step(struct target *target, int current, COMMAND_HANDLER(riscv_set_command_timeout_sec) { if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); + LOG_ERROR("Command takes exactly 1 parameter."); return ERROR_COMMAND_SYNTAX_ERROR; } int timeout = atoi(CMD_ARGV[0]); @@ -2399,7 +3404,7 @@ COMMAND_HANDLER(riscv_set_command_timeout_sec) COMMAND_HANDLER(riscv_set_reset_timeout_sec) { if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); + LOG_ERROR("Command takes exactly 1 parameter."); return ERROR_COMMAND_SYNTAX_ERROR; } int timeout = atoi(CMD_ARGV[0]); @@ -2412,37 +3417,6 @@ COMMAND_HANDLER(riscv_set_reset_timeout_sec) return ERROR_OK; } -COMMAND_HANDLER(riscv_set_prefer_sba) -{ - struct target *target = get_current_target(CMD_CTX); - RISCV_INFO(r); - bool prefer_sba; - LOG_WARNING("`riscv set_prefer_sba` is deprecated. Please use `riscv set_mem_access` instead."); - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); - return ERROR_COMMAND_SYNTAX_ERROR; - } - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], prefer_sba); - if (prefer_sba) { - /* Use system bus with highest priority */ - r->mem_access_methods[0] = RISCV_MEM_ACCESS_SYSBUS; - r->mem_access_methods[1] = RISCV_MEM_ACCESS_PROGBUF; - r->mem_access_methods[2] = RISCV_MEM_ACCESS_ABSTRACT; - } else { - /* Use progbuf with highest priority */ - r->mem_access_methods[0] = RISCV_MEM_ACCESS_PROGBUF; - r->mem_access_methods[1] = RISCV_MEM_ACCESS_SYSBUS; - r->mem_access_methods[2] = RISCV_MEM_ACCESS_ABSTRACT; - } - - /* Reset warning flags */ - r->mem_access_progbuf_warn = true; - r->mem_access_sysbus_warn = true; - r->mem_access_abstract_warn = true; - - return ERROR_OK; -} - COMMAND_HANDLER(riscv_set_mem_access) { struct target *target = get_current_target(CMD_CTX); @@ -2505,7 +3479,7 @@ COMMAND_HANDLER(riscv_set_enable_virtual) return ERROR_OK; } -int parse_ranges(struct list_head *ranges, const char *tcl_arg, const char *reg_type, unsigned int max_val) +static int parse_ranges(struct list_head *ranges, const char *tcl_arg, const char *reg_type, unsigned int max_val) { char *args = strdup(tcl_arg); if (!args) @@ -2633,7 +3607,7 @@ int parse_ranges(struct list_head *ranges, const char *tcl_arg, const char *reg_ COMMAND_HANDLER(riscv_set_expose_csrs) { if (CMD_ARGC == 0) { - LOG_ERROR("Command expects parameters"); + LOG_ERROR("Command expects parameters."); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -2653,7 +3627,7 @@ COMMAND_HANDLER(riscv_set_expose_csrs) COMMAND_HANDLER(riscv_set_expose_custom) { if (CMD_ARGC == 0) { - LOG_ERROR("Command expects parameters"); + LOG_ERROR("Command expects parameters."); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -2670,6 +3644,26 @@ COMMAND_HANDLER(riscv_set_expose_custom) return ret; } +COMMAND_HANDLER(riscv_hide_csrs) +{ + if (CMD_ARGC == 0) { + LOG_ERROR("Command expects parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(info); + int ret = ERROR_OK; + + for (unsigned int i = 0; i < CMD_ARGC; i++) { + ret = parse_ranges(&info->hide_csr, CMD_ARGV[i], "csr", 0xfff); + if (ret != ERROR_OK) + break; + } + + return ret; +} + COMMAND_HANDLER(riscv_authdata_read) { unsigned int index = 0; @@ -2678,7 +3672,7 @@ COMMAND_HANDLER(riscv_authdata_read) } else if (CMD_ARGC == 1) { COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], index); } else { - LOG_ERROR("Command takes at most one parameter"); + LOG_ERROR("Command takes at most one parameter."); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -2690,7 +3684,7 @@ COMMAND_HANDLER(riscv_authdata_read) RISCV_INFO(r); if (!r) { - LOG_ERROR("riscv_info is NULL!"); + LOG_TARGET_ERROR(target, "riscv_info is NULL!"); return ERROR_FAIL; } @@ -2701,7 +3695,7 @@ COMMAND_HANDLER(riscv_authdata_read) command_print_sameline(CMD, "0x%08" PRIx32, value); return ERROR_OK; } else { - LOG_ERROR("authdata_read is not implemented for this target."); + LOG_TARGET_ERROR(target, "authdata_read is not implemented for this target."); return ERROR_FAIL; } } @@ -2711,126 +3705,159 @@ COMMAND_HANDLER(riscv_authdata_write) uint32_t value; unsigned int index = 0; - if (CMD_ARGC == 0) { - /* nop */ - } else if (CMD_ARGC == 1) { + if (CMD_ARGC == 0 || CMD_ARGC > 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (CMD_ARGC == 1) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], value); - } else if (CMD_ARGC == 2) { + } else { COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], index); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); - } else { - LOG_ERROR("Command takes at most 2 arguments"); - return ERROR_COMMAND_SYNTAX_ERROR; } struct target *target = get_current_target(CMD_CTX); RISCV_INFO(r); - if (r->authdata_write) { - return r->authdata_write(target, value, index); - } else { - LOG_ERROR("authdata_write is not implemented for this target."); + if (!r->authdata_write) { + LOG_TARGET_ERROR(target, "authdata_write is not implemented for this target."); return ERROR_FAIL; } + + return r->authdata_write(target, value, index); } -COMMAND_HANDLER(riscv_dmi_read) +static uint32_t riscv_get_dmi_address(const struct target *target, uint32_t dm_address) { - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes 1 parameter"); - return ERROR_COMMAND_SYNTAX_ERROR; - } + assert(target); + RISCV_INFO(r); + if (!r || !r->get_dmi_address) + return dm_address; + return r->get_dmi_address(target, dm_address); +} - struct target *target = get_current_target(CMD_CTX); +static int riscv_dmi_read(struct target *target, uint32_t *value, uint32_t address) +{ if (!target) { LOG_ERROR("target is NULL!"); return ERROR_FAIL; } - RISCV_INFO(r); if (!r) { - LOG_ERROR("riscv_info is NULL!"); + LOG_TARGET_ERROR(target, "riscv_info is NULL!"); return ERROR_FAIL; } - - if (r->dmi_read) { - uint32_t address, value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); - if (r->dmi_read(target, &value, address) != ERROR_OK) - return ERROR_FAIL; - command_print(CMD, "0x%" PRIx32, value); - return ERROR_OK; - } else { - LOG_ERROR("dmi_read is not implemented for this target."); + if (!r->dmi_read) { + LOG_TARGET_ERROR(target, "dmi_read is not implemented."); return ERROR_FAIL; } + return r->dmi_read(target, value, address); } +static int riscv_dmi_write(struct target *target, uint32_t dmi_address, uint32_t value) +{ + if (!target) { + LOG_ERROR("target is NULL!"); + return ERROR_FAIL; + } + RISCV_INFO(r); + if (!r) { + LOG_TARGET_ERROR(target, "riscv_info is NULL!"); + return ERROR_FAIL; + } + if (!r->dmi_write) { + LOG_TARGET_ERROR(target, "dmi_write is not implemented."); + return ERROR_FAIL; + } + const int result = r->dmi_write(target, dmi_address, value); + /* Invalidate our cached progbuf copy: + * - if the user tinkered directly with a progbuf register + * - if debug module was reset, in which case progbuf registers + * may not retain their value. + * FIXME: If there are multiple DMs on a single TAP, it is possible to + * clobber progbuf or reset the DM of another target. + */ + const bool progbuf_touched = + (dmi_address >= riscv_get_dmi_address(target, DM_PROGBUF0) && + dmi_address <= riscv_get_dmi_address(target, DM_PROGBUF15)); + const bool dm_deactivated = + (dmi_address == riscv_get_dmi_address(target, DM_DMCONTROL) && + (value & DM_DMCONTROL_DMACTIVE) == 0); + if (progbuf_touched || dm_deactivated) { + if (r->invalidate_cached_progbuf) { + /* Here the return value of invalidate_cached_progbuf() + * is ignored. It is okay to do so for now, since the + * only case an error is returned is a failure to + * assign a DM to the target, which would have already + * caused an error during dmi_write(). + * FIXME: invalidate_cached_progbuf() should be void. + */ + r->invalidate_cached_progbuf(target); + } else { + LOG_TARGET_DEBUG(target, + "invalidate_cached_progbuf() is not implemented."); + } + } + return result; +} -COMMAND_HANDLER(riscv_dmi_write) +COMMAND_HANDLER(handle_riscv_dmi_read) { - if (CMD_ARGC != 2) { - LOG_ERROR("Command takes exactly 2 arguments"); + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - } - struct target *target = get_current_target(CMD_CTX); - RISCV_INFO(r); + uint32_t dmi_address; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], dmi_address); - uint32_t address, value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + struct target * const target = get_current_target(CMD_CTX); + uint32_t value; + const int result = riscv_dmi_read(target, &value, dmi_address); + if (result == ERROR_OK) + command_print(CMD, "0x%" PRIx32, value); + return result; +} - if (r->dmi_write) { - /* Perform the DMI write */ - int retval = r->dmi_write(target, address, value); - - /* Invalidate our cached progbuf copy: - - if the user tinkered directly with a progbuf register - - if debug module was reset, in which case progbuf registers - may not retain their value. - */ - bool progbufTouched = (address >= DM_PROGBUF0 && address <= DM_PROGBUF15); - bool dmDeactivated = (address == DM_DMCONTROL && (value & DM_DMCONTROL_DMACTIVE) == 0); - if (progbufTouched || dmDeactivated) { - if (r->invalidate_cached_debug_buffer) - r->invalidate_cached_debug_buffer(target); - } +COMMAND_HANDLER(handle_riscv_dmi_write) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; - return retval; - } + uint32_t dmi_address, value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], dmi_address); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); - LOG_ERROR("dmi_write is not implemented for this target."); - return ERROR_FAIL; + struct target * const target = get_current_target(CMD_CTX); + return riscv_dmi_write(target, dmi_address, value); } -COMMAND_HANDLER(riscv_test_sba_config_reg) +COMMAND_HANDLER(handle_riscv_dm_read) { - if (CMD_ARGC != 4) { - LOG_ERROR("Command takes exactly 4 arguments"); + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - } - struct target *target = get_current_target(CMD_CTX); - RISCV_INFO(r); + uint32_t dm_address; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], dm_address); + + struct target * const target = get_current_target(CMD_CTX); + uint32_t value; + const int result = riscv_dmi_read(target, &value, + riscv_get_dmi_address(target, dm_address)); + if (result == ERROR_OK) + command_print(CMD, "0x%" PRIx32, value); + return result; +} - target_addr_t legal_address; - uint32_t num_words; - target_addr_t illegal_address; - bool run_sbbusyerror_test; +COMMAND_HANDLER(handle_riscv_dm_write) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[0], legal_address); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], num_words); - COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[2], illegal_address); - COMMAND_PARSE_ON_OFF(CMD_ARGV[3], run_sbbusyerror_test); + uint32_t dm_address, value; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], dm_address); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); - if (r->test_sba_config_reg) { - return r->test_sba_config_reg(target, legal_address, num_words, - illegal_address, run_sbbusyerror_test); - } else { - LOG_ERROR("test_sba_config_reg is not implemented for this target."); - return ERROR_FAIL; - } + struct target * const target = get_current_target(CMD_CTX); + return riscv_dmi_write(target, riscv_get_dmi_address(target, dm_address), + value); } COMMAND_HANDLER(riscv_reset_delays) @@ -2935,69 +3962,301 @@ COMMAND_HANDLER(riscv_set_bscan_tunnel_ir) return ERROR_OK; } +COMMAND_HANDLER(riscv_set_maskisr) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(info); + + static const struct jim_nvp nvp_maskisr_modes[] = { + { .name = "off", .value = RISCV_ISRMASK_OFF }, + { .name = "steponly", .value = RISCV_ISRMASK_STEPONLY }, + { .name = NULL, .value = -1 }, + }; + const struct jim_nvp *n; + + if (CMD_ARGC > 0) { + n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); + if (!n->name) + return ERROR_COMMAND_SYNTAX_ERROR; + info->isrmask_mode = n->value; + } else { + n = jim_nvp_value2name_simple(nvp_maskisr_modes, info->isrmask_mode); + command_print(CMD, "riscv interrupt mask %s", n->name); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(riscv_set_enable_virt2phys) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_enable_virt2phys); + return ERROR_OK; +} + +COMMAND_HANDLER(riscv_set_ebreakm) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (CMD_ARGC == 0) { + command_print(CMD, "riscv_ebreakm enabled: %s", r->riscv_ebreakm ? "on" : "off"); + return ERROR_OK; + } else if (CMD_ARGC == 1) { + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->riscv_ebreakm); + return ERROR_OK; + } + + LOG_ERROR("Command takes 0 or 1 parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; +} + +COMMAND_HANDLER(riscv_set_ebreaks) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (CMD_ARGC == 0) { + command_print(CMD, "riscv_ebreaks enabled: %s", r->riscv_ebreaks ? "on" : "off"); + return ERROR_OK; + } else if (CMD_ARGC == 1) { + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->riscv_ebreaks); + return ERROR_OK; + } + + LOG_ERROR("Command takes 0 or 1 parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; +} -COMMAND_HANDLER(riscv_set_maskisr) +COMMAND_HANDLER(riscv_set_ebreaku) { struct target *target = get_current_target(CMD_CTX); - RISCV_INFO(info); - - static const struct jim_nvp nvp_maskisr_modes[] = { - { .name = "off", .value = RISCV_ISRMASK_OFF }, - { .name = "steponly", .value = RISCV_ISRMASK_STEPONLY }, - { .name = NULL, .value = -1 }, - }; - const struct jim_nvp *n; + RISCV_INFO(r); - if (CMD_ARGC > 0) { - n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); - if (!n->name) - return ERROR_COMMAND_SYNTAX_ERROR; - info->isrmask_mode = n->value; - } else { - n = jim_nvp_value2name_simple(nvp_maskisr_modes, info->isrmask_mode); - command_print(CMD, "riscv interrupt mask %s", n->name); + if (CMD_ARGC == 0) { + command_print(CMD, "riscv_ebreaku enabled: %s", r->riscv_ebreaku ? "on" : "off"); + return ERROR_OK; + } else if (CMD_ARGC == 1) { + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->riscv_ebreaku); + return ERROR_OK; } - return ERROR_OK; + LOG_ERROR("Command takes 0 or 1 parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; } -COMMAND_HANDLER(riscv_set_enable_virt2phys) +COMMAND_HELPER(riscv_clear_trigger, int trigger_id, const char *name) { + struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); + LOG_ERROR("clear command takes no extra arguments."); return ERROR_COMMAND_SYNTAX_ERROR; } - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_enable_virt2phys); - return ERROR_OK; + if (find_first_trigger_by_id(target, trigger_id) < 0) { + LOG_TARGET_ERROR(target, "No %s is set. Nothing to clear.", name); + return ERROR_FAIL; + } + return remove_trigger(target, trigger_id); } -COMMAND_HANDLER(riscv_set_ebreakm) +COMMAND_HANDLER(riscv_itrigger) { - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); + if (CMD_ARGC < 1) { + LOG_ERROR("Command takes at least 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + const int ITRIGGER_UNIQUE_ID = -CSR_TDATA1_TYPE_ITRIGGER; + + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + + if (!strcmp(CMD_ARGV[0], "set")) { + if (find_first_trigger_by_id(target, ITRIGGER_UNIQUE_ID) >= 0) { + LOG_TARGET_ERROR(target, "An itrigger is already set, and OpenOCD " + "doesn't support setting more than one at a time."); + return ERROR_FAIL; + } + bool vs = false; + bool vu = false; + bool nmi = false; + bool m = false; + bool s = false; + bool u = false; + riscv_reg_t interrupts = 0; + + for (unsigned int i = 1; i < CMD_ARGC; i++) { + if (!strcmp(CMD_ARGV[i], "vs")) + vs = true; + else if (!strcmp(CMD_ARGV[i], "vu")) + vu = true; + else if (!strcmp(CMD_ARGV[i], "nmi")) + nmi = true; + else if (!strcmp(CMD_ARGV[i], "m")) + m = true; + else if (!strcmp(CMD_ARGV[i], "s")) + s = true; + else if (!strcmp(CMD_ARGV[i], "u")) + u = true; + else + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[i], interrupts); + } + if (!nmi && interrupts == 0) { + LOG_ERROR("Doesn't make sense to set itrigger with " + "mie_bits=0 and without nmi."); + return ERROR_FAIL; + } else if (!vs && !vu && !m && !s && !u) { + LOG_ERROR("Doesn't make sense to set itrigger without at " + "least one of vs, vu, m, s, or u."); + return ERROR_FAIL; + } + int result = maybe_add_trigger_t4(target, vs, vu, nmi, m, s, u, interrupts, ITRIGGER_UNIQUE_ID); + if (result != ERROR_OK) + LOG_TARGET_ERROR(target, "Failed to set requested itrigger."); + return result; + + } else if (!strcmp(CMD_ARGV[0], "clear")) { + return riscv_clear_trigger(CMD, ITRIGGER_UNIQUE_ID, "itrigger"); + + } else { + LOG_ERROR("First argument must be either 'set' or 'clear'."); return ERROR_COMMAND_SYNTAX_ERROR; } - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreakm); return ERROR_OK; } -COMMAND_HANDLER(riscv_set_ebreaks) +COMMAND_HANDLER(riscv_icount) { - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); + if (CMD_ARGC < 1) { + LOG_ERROR("Command takes at least 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + const int ICOUNT_UNIQUE_ID = -CSR_TDATA1_TYPE_ICOUNT; + + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + + if (!strcmp(CMD_ARGV[0], "set")) { + if (find_first_trigger_by_id(target, ICOUNT_UNIQUE_ID) >= 0) { + LOG_TARGET_ERROR(target, "An icount trigger is already set, and OpenOCD " + "doesn't support setting more than one at a time."); + return ERROR_FAIL; + } + bool vs = false; + bool vu = false; + bool m = false; + bool s = false; + bool u = false; + bool pending = false; + unsigned int count = 0; + + for (unsigned int i = 1; i < CMD_ARGC; i++) { + if (!strcmp(CMD_ARGV[i], "vs")) + vs = true; + else if (!strcmp(CMD_ARGV[i], "vu")) + vu = true; + else if (!strcmp(CMD_ARGV[i], "pending")) + pending = true; + else if (!strcmp(CMD_ARGV[i], "m")) + m = true; + else if (!strcmp(CMD_ARGV[i], "s")) + s = true; + else if (!strcmp(CMD_ARGV[i], "u")) + u = true; + else + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[i], count); + } + if (count == 0) { + LOG_ERROR("Doesn't make sense to set icount trigger with " + "count=0."); + return ERROR_FAIL; + } else if (!vs && !vu && !m && !s && !u) { + LOG_ERROR("Doesn't make sense to set itrigger without at " + "least one of vs, vu, m, s, or u."); + return ERROR_FAIL; + } + int result = maybe_add_trigger_t3(target, vs, vu, m, s, u, pending, count, ICOUNT_UNIQUE_ID); + if (result != ERROR_OK) + LOG_TARGET_ERROR(target, "Failed to set requested icount trigger."); + return result; + + } else if (!strcmp(CMD_ARGV[0], "clear")) { + return riscv_clear_trigger(CMD, ICOUNT_UNIQUE_ID, "icount trigger"); + + } else { + LOG_ERROR("First argument must be either 'set' or 'clear'."); return ERROR_COMMAND_SYNTAX_ERROR; } - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaks); return ERROR_OK; } -COMMAND_HANDLER(riscv_set_ebreaku) +COMMAND_HANDLER(riscv_etrigger) { - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); + if (CMD_ARGC < 1) { + LOG_ERROR("Command takes at least 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + const int ETRIGGER_UNIQUE_ID = -CSR_TDATA1_TYPE_ETRIGGER; + + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + + if (!strcmp(CMD_ARGV[0], "set")) { + if (find_first_trigger_by_id(target, ETRIGGER_UNIQUE_ID) >= 0) { + LOG_TARGET_ERROR(target, "An etrigger is already set, and OpenOCD " + "doesn't support setting more than one at a time."); + return ERROR_FAIL; + } + bool vs = false; + bool vu = false; + bool m = false; + bool s = false; + bool u = false; + riscv_reg_t exception_codes = 0; + + for (unsigned int i = 1; i < CMD_ARGC; i++) { + if (!strcmp(CMD_ARGV[i], "vs")) + vs = true; + else if (!strcmp(CMD_ARGV[i], "vu")) + vu = true; + else if (!strcmp(CMD_ARGV[i], "m")) + m = true; + else if (!strcmp(CMD_ARGV[i], "s")) + s = true; + else if (!strcmp(CMD_ARGV[i], "u")) + u = true; + else + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[i], exception_codes); + } + if (exception_codes == 0) { + LOG_ERROR("Doesn't make sense to set etrigger with " + "exception_codes=0."); + return ERROR_FAIL; + } else if (!vs && !vu && !m && !s && !u) { + LOG_ERROR("Doesn't make sense to set etrigger without at " + "least one of vs, vu, m, s, or u."); + return ERROR_FAIL; + } + int result = maybe_add_trigger_t5(target, vs, vu, m, s, u, exception_codes, ETRIGGER_UNIQUE_ID); + if (result != ERROR_OK) + LOG_TARGET_ERROR(target, "Failed to set requested etrigger."); + return result; + + } else if (!strcmp(CMD_ARGV[0], "clear")) { + return riscv_clear_trigger(CMD, ETRIGGER_UNIQUE_ID, "etrigger"); + + } else { + LOG_ERROR("First argument must be either 'set' or 'clear'."); return ERROR_COMMAND_SYNTAX_ERROR; } - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaku); return ERROR_OK; } @@ -3047,7 +4306,7 @@ COMMAND_HANDLER(handle_memory_sample_command) if (CMD_ARGC == 0) { command_print(CMD, "Memory sample configuration for %s:", target_name(target)); - for (unsigned i = 0; i < ARRAY_SIZE(r->sample_config.bucket); i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(r->sample_config.bucket); i++) { if (r->sample_config.bucket[i].enabled) { command_print(CMD, "bucket %d; address=0x%" TARGET_PRIxADDR "; size=%d", i, r->sample_config.bucket[i].address, @@ -3067,7 +4326,7 @@ COMMAND_HANDLER(handle_memory_sample_command) uint32_t bucket; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], bucket); if (bucket > ARRAY_SIZE(r->sample_config.bucket)) { - LOG_ERROR("Max bucket number is %d.", (unsigned) ARRAY_SIZE(r->sample_config.bucket)); + LOG_TARGET_ERROR(target, "Max bucket number is %zd.", ARRAY_SIZE(r->sample_config.bucket)); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -3080,7 +4339,7 @@ COMMAND_HANDLER(handle_memory_sample_command) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], r->sample_config.bucket[bucket].size_bytes); if (r->sample_config.bucket[bucket].size_bytes != 4 && r->sample_config.bucket[bucket].size_bytes != 8) { - LOG_ERROR("Only 4-byte and 8-byte sizes are supported."); + LOG_TARGET_ERROR(target, "Only 4-byte and 8-byte sizes are supported."); return ERROR_COMMAND_ARGUMENT_INVALID; } } else { @@ -3127,14 +4386,14 @@ COMMAND_HANDLER(handle_dump_sample_buf_command) unsigned char *encoded = base64_encode(r->sample_buf.buf, r->sample_buf.used, NULL); if (!encoded) { - LOG_ERROR("Failed base64 encode!"); + LOG_TARGET_ERROR(target, "Failed base64 encode!"); result = ERROR_FAIL; goto error; } command_print(CMD, "%s", encoded); free(encoded); } else { - unsigned i = 0; + unsigned int i = 0; while (i < r->sample_buf.used) { uint8_t command = r->sample_buf.buf[i++]; if (command == RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE) { @@ -3157,13 +4416,13 @@ COMMAND_HANDLER(handle_dump_sample_buf_command) i += 8; command_print(CMD, "0x%016" PRIx64, value); } else { - LOG_ERROR("Found invalid size in bucket %d: %d", command, + LOG_TARGET_ERROR(target, "Found invalid size in bucket %d: %d", command, r->sample_config.bucket[command].size_bytes); result = ERROR_FAIL; goto error; } } else { - LOG_ERROR("Found invalid command byte in sample buf: 0x%2x at offset 0x%x", + LOG_TARGET_ERROR(target, "Found invalid command byte in sample buf: 0x%2x at offset 0x%x", command, i - 1); result = ERROR_FAIL; goto error; @@ -3177,15 +4436,25 @@ COMMAND_HANDLER(handle_dump_sample_buf_command) return result; } -COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key, - unsigned value) +static COMMAND_HELPER(riscv_print_info_line_if_available, const char *section, + const char *key, unsigned int value, bool is_available) { char full_key[80]; snprintf(full_key, sizeof(full_key), "%s.%s", section, key); - command_print(CMD, "%-21s %3d", full_key, value); + if (is_available) + command_print(CMD, "%-21s %3d", full_key, value); + else + command_print(CMD, "%-21s unavailable", full_key); return 0; } +COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key, + unsigned int value) +{ + return CALL_COMMAND_HANDLER(riscv_print_info_line_if_available, section, + key, value, /*is_available*/ true); +} + COMMAND_HANDLER(handle_info) { struct target *target = get_current_target(CMD_CTX); @@ -3194,16 +4463,113 @@ COMMAND_HANDLER(handle_info) /* This output format can be fed directly into TCL's "array set". */ riscv_print_info_line(CMD, "hart", "xlen", riscv_xlen(target)); - riscv_enumerate_triggers(target); - riscv_print_info_line(CMD, "hart", "trigger_count", - r->trigger_count); + const bool trigger_count_available = + riscv_enumerate_triggers(target) == ERROR_OK; + riscv_print_info_line_if_available(CMD, "hart", "trigger_count", + r->trigger_count, trigger_count_available); if (r->print_info) return CALL_COMMAND_HANDLER(r->print_info, target); return 0; } +COMMAND_HANDLER(riscv_exec_progbuf) +{ + if (CMD_ARGC < 1 || CMD_ARGC > 16) { + LOG_ERROR("Command 'exec_progbuf' takes 1 to 16 arguments."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + + RISCV_INFO(r); + if (r->dtm_version != DTM_DTMCS_VERSION_1_0) { + LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer is " + "only supported on v0.13 or v1.0 targets."); + return ERROR_FAIL; + } + + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "exec_progbuf: Can't execute " + "program buffer, target not halted."); + return ERROR_FAIL; + } + + if (riscv_progbuf_size(target) == 0) { + LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer not implemented " + "in the target."); + return ERROR_FAIL; + } + + struct riscv_program prog; + riscv_program_init(&prog, target); + + for (unsigned int i = 0; i < CMD_ARGC; i++) { + riscv_insn_t instr; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i], instr); + if (riscv_program_insert(&prog, instr) != ERROR_OK) + return ERROR_FAIL; + } + + if (riscv_flush_registers(target) != ERROR_OK) + return ERROR_FAIL; + int error = riscv_program_exec(&prog, target); + riscv_invalidate_register_cache(target); + + if (error != ERROR_OK) { + LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer execution failed."); + return ERROR_FAIL; + } + + LOG_TARGET_DEBUG(target, "exec_progbuf: Program buffer execution successful."); + + return ERROR_OK; +} + +COMMAND_HANDLER(riscv_set_enable_trigger_feature) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (CMD_ARGC == 2) { + bool enable_for_wp = true; + + if (!strcmp(CMD_ARGV[1], "wp")) + enable_for_wp = true; + else if (!strcmp(CMD_ARGV[1], "none")) + enable_for_wp = false; + else + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!strcmp(CMD_ARGV[0], "all")) { + r->wp_allow_equality_match_trigger = enable_for_wp; + r->wp_allow_napot_trigger = enable_for_wp; + r->wp_allow_ge_lt_trigger = enable_for_wp; + } else if (!strcmp(CMD_ARGV[0], "eq")) { + r->wp_allow_equality_match_trigger = enable_for_wp; + } else if (!strcmp(CMD_ARGV[0], "napot")) { + r->wp_allow_napot_trigger = enable_for_wp; + } else if (!strcmp(CMD_ARGV[0], "ge_lt")) { + r->wp_allow_ge_lt_trigger = enable_for_wp; + } else { + return ERROR_COMMAND_SYNTAX_ERROR; + } + } else if (CMD_ARGC != 0) { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + command_print(CMD, "Triggers feature configuration:\n" + "Equality match trigger: for wp (%s)\n" + "NAPOT trigger: for wp (%s)\n" + "ge-lt chained triggers: for wp (%s)", + r->wp_allow_equality_match_trigger ? "enabled" : "disabled", + r->wp_allow_napot_trigger ? "enabled" : "disabled", + r->wp_allow_ge_lt_trigger ? "enabled" : "disabled"); + + return ERROR_OK; +} + static const struct command_registration riscv_exec_command_handlers[] = { { .name = "dump_sample_buf", @@ -3247,14 +4613,6 @@ static const struct command_registration riscv_exec_command_handlers[] = { .usage = "[sec]", .help = "Set the wall-clock timeout (in seconds) after reset is deasserted" }, - { - .name = "set_prefer_sba", - .handler = riscv_set_prefer_sba, - .mode = COMMAND_ANY, - .usage = "on|off", - .help = "When on, prefer to use System Bus Access to access memory. " - "When off (default), prefer to use the Program Buffer to access memory." - }, { .name = "set_mem_access", .handler = riscv_set_mem_access, @@ -3290,6 +4648,16 @@ static const struct command_registration riscv_exec_command_handlers[] = { "expose. custom0 is accessed as abstract register number 0xc000, " "etc. This must be executed before `init`." }, + { + .name = "hide_csrs", + .handler = riscv_hide_csrs, + .mode = COMMAND_CONFIG, + .usage = "{n0|n-m0}[,n1|n-m1]......", + .help = "Configure a list of inclusive ranges for CSRs to hide from gdb. " + "Hidden registers are still available, but are not listed in " + "gdb target description and `reg` command output. " + "This must be executed before `init`." + }, { .name = "authdata_read", .handler = riscv_authdata_read, @@ -3308,30 +4676,34 @@ static const struct command_registration riscv_exec_command_handlers[] = { }, { .name = "dmi_read", - .handler = riscv_dmi_read, + .handler = handle_riscv_dmi_read, .mode = COMMAND_ANY, .usage = "address", - .help = "Perform a 32-bit DMI read at address, returning the value." + .help = "Read and return 32-bit value from the given address on the " + "RISC-V DMI bus." }, { .name = "dmi_write", - .handler = riscv_dmi_write, + .handler = handle_riscv_dmi_write, .mode = COMMAND_ANY, .usage = "address value", - .help = "Perform a 32-bit DMI write of value at address." + .help = "Write a 32-bit value to the given address on the RISC-V DMI bus." + }, + { + .name = "dm_read", + .handler = handle_riscv_dm_read, + .mode = COMMAND_ANY, + .usage = "reg_address", + .help = "Read and return 32-bit value from a debug module's register " + "at reg_address." }, { - .name = "test_sba_config_reg", - .handler = riscv_test_sba_config_reg, + .name = "dm_write", + .handler = handle_riscv_dm_write, .mode = COMMAND_ANY, - .usage = "legal_address num_words " - "illegal_address run_sbbusyerror_test[on/off]", - .help = "Perform a series of tests on the SBCS register. " - "Inputs are a legal, 128-byte aligned address and a number of words to " - "read/write starting at that address (i.e., address range [legal address, " - "legal_address+word_size*num_words) must be legally readable/writable), " - "an illegal, 128-byte aligned address for error flag/handling cases, " - "and whether sbbusyerror test should be run." + .usage = "reg_address value", + .help = "Write a 32-bit value to the debug module's register at " + "reg_address." }, { .name = "reset_delays", @@ -3398,7 +4770,7 @@ static const struct command_registration riscv_exec_command_handlers[] = { .name = "set_ebreakm", .handler = riscv_set_ebreakm, .mode = COMMAND_ANY, - .usage = "on|off", + .usage = "[on|off]", .help = "Control dcsr.ebreakm. When off, M-mode ebreak instructions " "don't trap to OpenOCD. Defaults to on." }, @@ -3406,7 +4778,7 @@ static const struct command_registration riscv_exec_command_handlers[] = { .name = "set_ebreaks", .handler = riscv_set_ebreaks, .mode = COMMAND_ANY, - .usage = "on|off", + .usage = "[on|off]", .help = "Control dcsr.ebreaks. When off, S-mode ebreak instructions " "don't trap to OpenOCD. Defaults to on." }, @@ -3414,10 +4786,46 @@ static const struct command_registration riscv_exec_command_handlers[] = { .name = "set_ebreaku", .handler = riscv_set_ebreaku, .mode = COMMAND_ANY, - .usage = "on|off", + .usage = "[on|off]", .help = "Control dcsr.ebreaku. When off, U-mode ebreak instructions " "don't trap to OpenOCD. Defaults to on." }, + { + .name = "etrigger", + .handler = riscv_etrigger, + .mode = COMMAND_EXEC, + .usage = "set [vs] [vu] [m] [s] [u] <exception_codes>|clear", + .help = "Set or clear a single exception trigger." + }, + { + .name = "icount", + .handler = riscv_icount, + .mode = COMMAND_EXEC, + .usage = "set [vs] [vu] [m] [s] [u] [pending] <count>|clear", + .help = "Set or clear a single instruction count trigger." + }, + { + .name = "itrigger", + .handler = riscv_itrigger, + .mode = COMMAND_EXEC, + .usage = "set [vs] [vu] [nmi] [m] [s] [u] <mie_bits>|clear", + .help = "Set or clear a single interrupt trigger." + }, + { + .name = "exec_progbuf", + .handler = riscv_exec_progbuf, + .mode = COMMAND_EXEC, + .usage = "instr1 [instr2 [... instr16]]", + .help = "Execute a sequence of 32-bit instructions using the program buffer. " + "The final ebreak instruction is added automatically, if needed." + }, + { + .name = "set_enable_trigger_feature", + .handler = riscv_set_enable_trigger_feature, + .mode = COMMAND_ANY, + .usage = "[('eq'|'napot'|'ge_lt'|'all') ('wp'|'none')]", + .help = "Control whether OpenOCD is allowed to use certain RISC-V trigger features for watchpoints." + }, COMMAND_REGISTRATION_DONE }; @@ -3434,9 +4842,8 @@ static const struct command_registration riscv_exec_command_handlers[] = { * protocol, then a command like `riscv semihosting enable` will make * sense, but for now all semihosting commands are prefixed with `arm`. */ -extern const struct command_registration semihosting_common_handlers[]; -const struct command_registration riscv_command_handlers[] = { +static const struct command_registration riscv_command_handlers[] = { { .name = "riscv", .mode = COMMAND_ANY, @@ -3451,10 +4858,13 @@ const struct command_registration riscv_command_handlers[] = { .usage = "", .chain = semihosting_common_handlers }, + { + .chain = smp_command_handlers + }, COMMAND_REGISTRATION_DONE }; -static unsigned riscv_xlen_nonconst(struct target *target) +static unsigned int riscv_xlen_nonconst(struct target *target) { return riscv_xlen(target); } @@ -3518,10 +4928,14 @@ struct target_type riscv_target = { /*** RISC-V Interface ***/ -void riscv_info_init(struct target *target, riscv_info_t *r) +/* Initializes the shared RISC-V structure. */ +static void riscv_info_init(struct target *target, struct riscv_info *r) { memset(r, 0, sizeof(*r)); - r->dtm_version = 1; + + r->common_magic = RISCV_COMMON_MAGIC; + + r->dtm_version = DTM_DTMCS_VERSION_UNKNOWN; r->version_specific = NULL; memset(r->trigger_unique_id, 0xff, sizeof(r->trigger_unique_id)); @@ -3540,19 +4954,29 @@ void riscv_info_init(struct target *target, riscv_info_t *r) INIT_LIST_HEAD(&r->expose_csr); INIT_LIST_HEAD(&r->expose_custom); + INIT_LIST_HEAD(&r->hide_csr); + + r->vsew64_supported = YNM_MAYBE; + + r->riscv_ebreakm = true; + r->riscv_ebreaks = true; + r->riscv_ebreaku = true; + + r->wp_allow_equality_match_trigger = true; + r->wp_allow_ge_lt_trigger = true; + r->wp_allow_napot_trigger = true; } static int riscv_resume_go_all_harts(struct target *target) { RISCV_INFO(r); - LOG_TARGET_DEBUG(target, "resuming hart, state=%d", target->state); - if (riscv_is_halted(target)) { + LOG_TARGET_DEBUG(target, "Resuming hart, state=%d.", target->state); + if (target->state == TARGET_HALTED) { if (r->resume_go(target) != ERROR_OK) return ERROR_FAIL; } else { - LOG_DEBUG("[%s] hart requested resume, but was already resumed", - target_name(target)); + LOG_TARGET_DEBUG(target, "Hart requested resume, but was already resumed."); } riscv_invalidate_register_cache(target); @@ -3561,11 +4985,11 @@ static int riscv_resume_go_all_harts(struct target *target) int riscv_interrupts_disable(struct target *target, uint64_t irq_mask, uint64_t *old_mstatus) { - LOG_DEBUG("Disabling Interrupts"); + LOG_TARGET_DEBUG(target, "Disabling interrupts."); struct reg *reg_mstatus = register_get_by_name(target->reg_cache, "mstatus", true); if (!reg_mstatus) { - LOG_ERROR("Couldn't find mstatus!"); + LOG_TARGET_ERROR(target, "Couldn't find mstatus!"); return ERROR_FAIL; } @@ -3591,11 +5015,11 @@ int riscv_interrupts_disable(struct target *target, uint64_t irq_mask, uint64_t int riscv_interrupts_restore(struct target *target, uint64_t old_mstatus) { - LOG_DEBUG("Restore Interrupts"); + LOG_TARGET_DEBUG(target, "Restoring interrupts."); struct reg *reg_mstatus = register_get_by_name(target->reg_cache, "mstatus", true); if (!reg_mstatus) { - LOG_ERROR("Couldn't find mstatus!"); + LOG_TARGET_ERROR(target, "Couldn't find mstatus!"); return ERROR_FAIL; } @@ -3605,21 +5029,20 @@ int riscv_interrupts_restore(struct target *target, uint64_t old_mstatus) return reg_mstatus->type->set(reg_mstatus, mstatus_bytes); } -int riscv_step_rtos_hart(struct target *target) +static int riscv_step_rtos_hart(struct target *target) { RISCV_INFO(r); - LOG_DEBUG("[%s] stepping", target_name(target)); + LOG_TARGET_DEBUG(target, "Stepping."); - if (!riscv_is_halted(target)) { - LOG_ERROR("Hart isn't halted before single step!"); + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "Hart isn't halted before single step!"); return ERROR_FAIL; } r->on_step(target); if (r->step_current_hart(target) != ERROR_OK) return ERROR_FAIL; - r->on_halt(target); - if (!riscv_is_halted(target)) { - LOG_ERROR("Hart was not halted after single step!"); + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "Hart was not halted after single step!"); return ERROR_FAIL; } return ERROR_OK; @@ -3644,32 +5067,18 @@ unsigned riscv_xlen(const struct target *target) return r->xlen; } -void riscv_invalidate_register_cache(struct target *target) +static void riscv_invalidate_register_cache(struct target *target) { /* Do not invalidate the register cache if it is not yet set up * (e.g. when the target failed to get examined). */ if (!target->reg_cache) return; - LOG_DEBUG("[%d]", target->coreid); + LOG_TARGET_DEBUG(target, "Invalidating register cache."); register_cache_invalidate(target->reg_cache); - for (size_t i = 0; i < target->reg_cache->num_regs; ++i) { - struct reg *reg = &target->reg_cache->reg_list[i]; - reg->valid = false; - } } -unsigned int riscv_count_harts(struct target *target) -{ - if (!target) - return 1; - RISCV_INFO(r); - if (!r || !r->hart_count) - return 1; - return r->hart_count(target); -} - /** * If write is true: * return true iff we are guaranteed that the register will contain exactly @@ -3678,8 +5087,11 @@ unsigned int riscv_count_harts(struct target *target) * return true iff we are guaranteed that the register will read the same * value in the future as the value we just read. */ -static bool gdb_regno_cacheable(enum gdb_regno regno, bool write) +static bool gdb_regno_cacheable(enum gdb_regno regno, bool is_write) { + if (regno == GDB_REGNO_ZERO) + return !is_write; + /* GPRs, FPRs, vector registers are just normal data stores. */ if (regno <= GDB_REGNO_XPR31 || (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) || @@ -3690,8 +5102,6 @@ static bool gdb_regno_cacheable(enum gdb_regno regno, bool write) * CSRs. */ switch (regno) { case GDB_REGNO_DPC: - return true; - case GDB_REGNO_VSTART: case GDB_REGNO_VXSAT: case GDB_REGNO_VXRM: @@ -3709,107 +5119,195 @@ static bool gdb_regno_cacheable(enum gdb_regno regno, bool write) * WARL registers might not contain the value we just wrote, but * these ones won't spontaneously change their value either. * */ - return !write; + return !is_write; case GDB_REGNO_TSELECT: /* I think this should be above, but then it doesn't work. */ case GDB_REGNO_TDATA1: /* Changes value when tselect is changed. */ - case GDB_REGNO_TDATA2: /* Changse value when tselect is changed. */ + case GDB_REGNO_TDATA2: /* Changes value when tselect is changed. */ default: return false; } } /** - * This function is called when the debug user wants to change the value of a - * register. The new value may be cached, and may not be written until the hart - * is resumed. */ -int riscv_set_register(struct target *target, enum gdb_regno regid, riscv_reg_t value) + * This function is used internally by functions that change register values. + * If `write_through` is true, it is ensured that the value of the target's + * register is set to be equal to the `value` argument. The cached value is + * updated if the register is cacheable. + */ +static int riscv_set_or_write_register(struct target *target, + enum gdb_regno regid, riscv_reg_t value, bool write_through) { RISCV_INFO(r); - LOG_DEBUG("[%s] %s <- %" PRIx64, target_name(target), gdb_regno_name(regid), value); assert(r->set_register); keep_alive(); - /* TODO: Hack to deal with gdb that thinks these registers still exist. */ - if (regid > GDB_REGNO_XPR15 && regid <= GDB_REGNO_XPR31 && value == 0 && - riscv_supports_extension(target, 'E')) - return ERROR_OK; + if (regid == GDB_REGNO_PC) { + return riscv_set_or_write_register(target, GDB_REGNO_DPC, value, write_through); + } else if (regid == GDB_REGNO_PRIV) { + riscv_reg_t dcsr; - struct reg *reg = &target->reg_cache->reg_list[regid]; - buf_set_u64(reg->value, 0, reg->size, value); + if (riscv_get_register(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) + return ERROR_FAIL; + dcsr = set_field(dcsr, CSR_DCSR_PRV, get_field(value, VIRT_PRIV_PRV)); + dcsr = set_field(dcsr, CSR_DCSR_V, get_field(value, VIRT_PRIV_V)); + return riscv_set_or_write_register(target, GDB_REGNO_DCSR, dcsr, write_through); + } - if (gdb_regno_cacheable(regid, true)) { - reg->valid = true; - reg->dirty = true; - } else { + if (!target->reg_cache) { + assert(!target_was_examined(target)); + LOG_TARGET_DEBUG(target, + "No cache, writing to target: %s <- 0x%" PRIx64, + gdb_regno_name(target, regid), value); + return r->set_register(target, regid, value); + } + + struct reg *reg = get_reg_cache_entry(target, regid); + + if (!reg->exist) { + LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name); + return ERROR_FAIL; + } + + if (target->state != TARGET_HALTED) { + LOG_TARGET_DEBUG(target, + "Target not halted, writing to target: %s <- 0x%" PRIx64, + reg->name, value); + return r->set_register(target, regid, value); + } + + const bool need_to_write = !reg->valid || reg->dirty || + value != buf_get_u64(reg->value, 0, reg->size); + const bool cacheable = gdb_regno_cacheable(regid, need_to_write); + + if (!cacheable || (write_through && need_to_write)) { + LOG_TARGET_DEBUG(target, + "Writing to target: %s <- 0x%" PRIx64 " (cacheable=%s, valid=%s, dirty=%s)", + reg->name, value, cacheable ? "true" : "false", + reg->valid ? "true" : "false", + reg->dirty ? "true" : "false"); if (r->set_register(target, regid, value) != ERROR_OK) return ERROR_FAIL; + + reg->dirty = false; + } else { + reg->dirty = need_to_write; } - LOG_DEBUG("[%s] wrote 0x%" PRIx64 " to %s valid=%d", - target_name(target), value, reg->name, reg->valid); + buf_set_u64(reg->value, 0, reg->size, value); + reg->valid = cacheable; + + LOG_TARGET_DEBUG(target, + "Wrote 0x%" PRIx64 " to %s (cacheable=%s, valid=%s, dirty=%s)", + value, reg->name, cacheable ? "true" : "false", + reg->valid ? "true" : "false", + reg->dirty ? "true" : "false"); return ERROR_OK; } +/** + * This function is used to change the value of a register. The new value may + * be cached, and may not be written until the hart is resumed. + */ +int riscv_set_register(struct target *target, enum gdb_regno regid, + riscv_reg_t value) +{ + return riscv_set_or_write_register(target, regid, value, + /* write_through */ false); +} + +/** + * This function is used to change the value of a register. The new value may + * be cached, but it will be written to hart immediately. + */ +int riscv_write_register(struct target *target, enum gdb_regno regid, + riscv_reg_t value) +{ + return riscv_set_or_write_register(target, regid, value, + /* write_through */ true); +} + +/** + * This function is used to get the value of a register. If possible, the value + * in cache will be updated. + */ int riscv_get_register(struct target *target, riscv_reg_t *value, enum gdb_regno regid) { RISCV_INFO(r); + assert(r->get_register); keep_alive(); - struct reg *reg = &target->reg_cache->reg_list[regid]; + if (regid == GDB_REGNO_PC) + return riscv_get_register(target, value, GDB_REGNO_DPC); + + if (!target->reg_cache) { + assert(!target_was_examined(target)); + LOG_TARGET_DEBUG(target, "No cache, reading %s from target", + gdb_regno_name(target, regid)); + return r->get_register(target, value, regid); + } + + struct reg *reg = get_reg_cache_entry(target, regid); if (!reg->exist) { - LOG_DEBUG("[%s] %s does not exist.", - target_name(target), gdb_regno_name(regid)); + LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name); return ERROR_FAIL; } - if (reg && reg->valid) { + if (reg->valid) { *value = buf_get_u64(reg->value, 0, reg->size); - LOG_DEBUG("[%s] %s: %" PRIx64 " (cached)", target_name(target), - gdb_regno_name(regid), *value); - return ERROR_OK; - } - - /* TODO: Hack to deal with gdb that thinks these registers still exist. */ - if (regid > GDB_REGNO_XPR15 && regid <= GDB_REGNO_XPR31 && - riscv_supports_extension(target, 'E')) { - *value = 0; + LOG_TARGET_DEBUG(target, "Read %s: 0x%" PRIx64 " (cached)", reg->name, + *value); return ERROR_OK; } - int result = r->get_register(target, value, regid); + LOG_TARGET_DEBUG(target, "Reading %s from target", reg->name); + if (r->get_register(target, value, regid) != ERROR_OK) + return ERROR_FAIL; - if (result == ERROR_OK) { - /* Update the cache in case we're called from - * riscv_save_register(). */ - buf_set_u64(reg->value, 0, reg->size, *value); - reg->valid = gdb_regno_cacheable(regid, false); - } + buf_set_u64(reg->value, 0, reg->size, *value); + reg->valid = gdb_regno_cacheable(regid, /* is write? */ false); + reg->dirty = false; - LOG_DEBUG("[%s] %s: %" PRIx64, target_name(target), - gdb_regno_name(regid), *value); - return result; + LOG_TARGET_DEBUG(target, "Read %s: 0x%" PRIx64, reg->name, *value); + return ERROR_OK; } +/** + * This function is used to save the value of a register in cache. The register + * is marked as dirty, and writeback is delayed for as long as possible. + */ int riscv_save_register(struct target *target, enum gdb_regno regid) { + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "Can't save register %s on a hart that is not halted.", + gdb_regno_name(target, regid)); + return ERROR_FAIL; + } + assert(gdb_regno_cacheable(regid, /* is write? */ false) && + "Only cacheable registers can be saved."); + RISCV_INFO(r); riscv_reg_t value; if (!target->reg_cache) { assert(!target_was_examined(target)); + /* To create register cache it is needed to examine the target first, + * therefore during examine, any changed register needs to be saved + * and restored manually. + */ return ERROR_OK; } - struct reg *reg = &target->reg_cache->reg_list[regid]; - LOG_DEBUG("[%s] save %s", target_name(target), reg->name); + struct reg *reg = get_reg_cache_entry(target, regid); + + LOG_TARGET_DEBUG(target, "Saving %s", reg->name); if (riscv_get_register(target, &value, regid) != ERROR_OK) return ERROR_FAIL; - if (!reg->valid) - return ERROR_FAIL; + assert(reg->valid && + "The register is cacheable, so the cache entry must be valid now."); /* Mark the register dirty. We assume that this function is called * because the caller is about to mess with the underlying value of the * register. */ @@ -3820,70 +5318,142 @@ int riscv_save_register(struct target *target, enum gdb_regno regid) return ERROR_OK; } -bool riscv_is_halted(struct target *target) +int riscv_get_hart_state(struct target *target, enum riscv_hart_state *state) { RISCV_INFO(r); - assert(r->is_halted); - return r->is_halted(target); + assert(r->get_hart_state); + return r->get_hart_state(target, state); } -enum riscv_halt_reason riscv_halt_reason(struct target *target) +static enum riscv_halt_reason riscv_halt_reason(struct target *target) { RISCV_INFO(r); if (target->state != TARGET_HALTED) { - LOG_ERROR("Hart is not halted!"); + LOG_TARGET_ERROR(target, "Hart is not halted!"); return RISCV_HALT_UNKNOWN; } return r->halt_reason(target); } -size_t riscv_debug_buffer_size(struct target *target) +size_t riscv_progbuf_size(struct target *target) { RISCV_INFO(r); - return r->debug_buffer_size; + return r->progbuf_size; } -int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn) +int riscv_write_progbuf(struct target *target, int index, riscv_insn_t insn) { RISCV_INFO(r); - r->write_debug_buffer(target, index, insn); + r->write_progbuf(target, index, insn); return ERROR_OK; } -riscv_insn_t riscv_read_debug_buffer(struct target *target, int index) +riscv_insn_t riscv_read_progbuf(struct target *target, int index) { RISCV_INFO(r); - return r->read_debug_buffer(target, index); + return r->read_progbuf(target, index); } -int riscv_execute_debug_buffer(struct target *target) +int riscv_execute_progbuf(struct target *target, uint32_t *cmderr) { RISCV_INFO(r); - return r->execute_debug_buffer(target); + return r->execute_progbuf(target, cmderr); } -void riscv_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d) +void riscv_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d) { RISCV_INFO(r); - r->fill_dmi_write_u64(target, buf, a, d); + r->fill_dm_write(target, buf, a, d); } -void riscv_fill_dmi_read_u64(struct target *target, char *buf, int a) +void riscv_fill_dm_read(struct target *target, char *buf, uint64_t a) { RISCV_INFO(r); - r->fill_dmi_read_u64(target, buf, a); + r->fill_dm_read(target, buf, a); } -void riscv_fill_dmi_nop_u64(struct target *target, char *buf) +void riscv_fill_dm_nop(struct target *target, char *buf) { RISCV_INFO(r); - r->fill_dmi_nop_u64(target, buf); + r->fill_dm_nop(target, buf); } -int riscv_dmi_write_u64_bits(struct target *target) +int riscv_get_dmi_scan_length(struct target *target) { RISCV_INFO(r); - return r->dmi_write_u64_bits(target); + return r->get_dmi_scan_length(target); +} + +static int check_if_trigger_exists(struct target *target, unsigned int index) +{ + /* If we can't write tselect, then this hart does not support triggers. */ + if (riscv_set_register(target, GDB_REGNO_TSELECT, index) != ERROR_OK) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + riscv_reg_t tselect_rb; + if (riscv_get_register(target, &tselect_rb, GDB_REGNO_TSELECT) != ERROR_OK) + return ERROR_FAIL; + /* Mask off the top bit, which is used as tdrmode in legacy RISC-V Debug Spec + * (old revisions of v0.11 spec). */ + tselect_rb &= ~(1ULL << (riscv_xlen(target) - 1)); + if (tselect_rb != index) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + return ERROR_OK; +} + +/** + * This function reads `tinfo` or `tdata1`, when reading `tinfo` fails, + * to determine trigger types supported by a trigger. + * It is assumed that the trigger is already selected via writing `tselect`. + */ +static int get_trigger_types(struct target *target, unsigned int *trigger_tinfo, + riscv_reg_t tdata1) +{ + assert(trigger_tinfo); + riscv_reg_t tinfo; + if (riscv_get_register(target, &tinfo, GDB_REGNO_TINFO) == ERROR_OK) { + /* tinfo.INFO == 1: trigger doesn’t exist + * tinfo == 0 or tinfo.INFO != 1 and tinfo LSB is set: invalid tinfo */ + if (tinfo == 0 || tinfo & 0x1) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + *trigger_tinfo = tinfo; + return ERROR_OK; + } + const unsigned int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target))); + if (type == 0) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + *trigger_tinfo = 1 << type; + return ERROR_OK; +} + +static int disable_trigger_if_dmode(struct target *target, riscv_reg_t tdata1) +{ + bool dmode_is_set = false; + switch (get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target)))) { + case CSR_TDATA1_TYPE_LEGACY: + /* On these older cores we don't support software using + * triggers. */ + dmode_is_set = true; + break; + case CSR_TDATA1_TYPE_MCONTROL: + dmode_is_set = tdata1 & CSR_MCONTROL_DMODE(riscv_xlen(target)); + break; + case CSR_TDATA1_TYPE_MCONTROL6: + dmode_is_set = tdata1 & CSR_MCONTROL6_DMODE(riscv_xlen(target)); + break; + case CSR_TDATA1_TYPE_ICOUNT: + dmode_is_set = tdata1 & CSR_ICOUNT_DMODE(riscv_xlen(target)); + break; + case CSR_TDATA1_TYPE_ITRIGGER: + dmode_is_set = tdata1 & CSR_ITRIGGER_DMODE(riscv_xlen(target)); + break; + case CSR_TDATA1_TYPE_ETRIGGER: + dmode_is_set = tdata1 & CSR_ETRIGGER_DMODE(riscv_xlen(target)); + break; + } + if (!dmode_is_set) + /* Nothing to do */ + return ERROR_OK; + return riscv_set_register(target, GDB_REGNO_TDATA1, 0); } /** @@ -3892,7 +5462,7 @@ int riscv_dmi_write_u64_bits(struct target *target) * something. * Disable any hardware triggers that have dmode set. We can't have set them * ourselves. Maybe they're left over from some killed debug session. - * */ + */ int riscv_enumerate_triggers(struct target *target) { RISCV_INFO(r); @@ -3900,264 +5470,254 @@ int riscv_enumerate_triggers(struct target *target) if (r->triggers_enumerated) return ERROR_OK; - r->triggers_enumerated = true; /* At the very least we tried. */ + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "Unable to enumerate triggers: target not halted."); + return ERROR_FAIL; + } - riscv_reg_t tselect; - int result = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT); + riscv_reg_t orig_tselect; + int result = riscv_get_register(target, &orig_tselect, GDB_REGNO_TSELECT); /* If tselect is not readable, the trigger module is likely not - * implemented. There are no triggers to enumerate then and no error - * should be thrown. */ + * implemented. */ if (result != ERROR_OK) { - LOG_DEBUG("[%s] Cannot access tselect register. " - "Assuming that triggers are not implemented.", target_name(target)); + LOG_TARGET_INFO(target, "Cannot access tselect register. " + "Assuming that triggers are not implemented."); + r->triggers_enumerated = true; r->trigger_count = 0; return ERROR_OK; } - for (unsigned int t = 0; t < RISCV_MAX_TRIGGERS; ++t) { - r->trigger_count = t; - - /* If we can't write tselect, then this hart does not support triggers. */ - if (riscv_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK) - break; - uint64_t tselect_rb; - result = riscv_get_register(target, &tselect_rb, GDB_REGNO_TSELECT); - if (result != ERROR_OK) - return result; - /* Mask off the top bit, which is used as tdrmode in old - * implementations. */ - tselect_rb &= ~(1ULL << (riscv_xlen(target) - 1)); - if (tselect_rb != t) + unsigned int t = 0; + for (; t < ARRAY_SIZE(r->trigger_tinfo); ++t) { + result = check_if_trigger_exists(target, t); + if (result == ERROR_FAIL) + return ERROR_FAIL; + if (result == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) break; - uint64_t tdata1; - result = riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1); - if (result != ERROR_OK) - return result; - int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target))); - if (type == 0) + riscv_reg_t tdata1; + if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) + return ERROR_FAIL; + + result = get_trigger_types(target, &r->trigger_tinfo[t], tdata1); + if (result == ERROR_FAIL) + return ERROR_FAIL; + if (result == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) break; - switch (type) { - case 1: - /* On these older cores we don't support software using - * triggers. */ - riscv_set_register(target, GDB_REGNO_TDATA1, 0); - break; - case 2: - if (tdata1 & CSR_MCONTROL_DMODE(riscv_xlen(target))) - riscv_set_register(target, GDB_REGNO_TDATA1, 0); - break; - case 6: - if (tdata1 & CSR_MCONTROL6_DMODE(riscv_xlen(target))) - riscv_set_register(target, GDB_REGNO_TDATA1, 0); - break; - } - } - riscv_set_register(target, GDB_REGNO_TSELECT, tselect); + LOG_TARGET_DEBUG(target, "Trigger %u: supported types (mask) = 0x%08x", + t, r->trigger_tinfo[t]); + + if (disable_trigger_if_dmode(target, tdata1) != ERROR_OK) + return ERROR_FAIL; + } - LOG_INFO("[%s] Found %d triggers", target_name(target), r->trigger_count); + if (riscv_set_register(target, GDB_REGNO_TSELECT, orig_tselect) != ERROR_OK) + return ERROR_FAIL; + r->triggers_enumerated = true; + r->trigger_count = t; + LOG_TARGET_INFO(target, "Found %d triggers", r->trigger_count); + create_wp_trigger_cache(target); return ERROR_OK; } -const char *gdb_regno_name(enum gdb_regno regno) +static char *init_reg_name(const char *name) { - static char buf[32]; + const int size_buf = strlen(name) + 1; - switch (regno) { - case GDB_REGNO_ZERO: - return "zero"; - case GDB_REGNO_RA: - return "ra"; - case GDB_REGNO_SP: - return "sp"; - case GDB_REGNO_GP: - return "gp"; - case GDB_REGNO_TP: - return "tp"; - case GDB_REGNO_T0: - return "t0"; - case GDB_REGNO_T1: - return "t1"; - case GDB_REGNO_T2: - return "t2"; - case GDB_REGNO_S0: - return "s0"; - case GDB_REGNO_S1: - return "s1"; - case GDB_REGNO_A0: - return "a0"; - case GDB_REGNO_A1: - return "a1"; - case GDB_REGNO_A2: - return "a2"; - case GDB_REGNO_A3: - return "a3"; - case GDB_REGNO_A4: - return "a4"; - case GDB_REGNO_A5: - return "a5"; - case GDB_REGNO_A6: - return "a6"; - case GDB_REGNO_A7: - return "a7"; - case GDB_REGNO_S2: - return "s2"; - case GDB_REGNO_S3: - return "s3"; - case GDB_REGNO_S4: - return "s4"; - case GDB_REGNO_S5: - return "s5"; - case GDB_REGNO_S6: - return "s6"; - case GDB_REGNO_S7: - return "s7"; - case GDB_REGNO_S8: - return "s8"; - case GDB_REGNO_S9: - return "s9"; - case GDB_REGNO_S10: - return "s10"; - case GDB_REGNO_S11: - return "s11"; - case GDB_REGNO_T3: - return "t3"; - case GDB_REGNO_T4: - return "t4"; - case GDB_REGNO_T5: - return "t5"; - case GDB_REGNO_T6: - return "t6"; - case GDB_REGNO_PC: - return "pc"; - case GDB_REGNO_FPR0: - return "fpr0"; - case GDB_REGNO_FPR31: - return "fpr31"; - case GDB_REGNO_CSR0: - return "csr0"; - case GDB_REGNO_TSELECT: - return "tselect"; - case GDB_REGNO_TDATA1: - return "tdata1"; - case GDB_REGNO_TDATA2: - return "tdata2"; - case GDB_REGNO_MISA: - return "misa"; - case GDB_REGNO_DPC: - return "dpc"; - case GDB_REGNO_DCSR: - return "dcsr"; - case GDB_REGNO_DSCRATCH0: - return "dscratch0"; - case GDB_REGNO_MSTATUS: - return "mstatus"; - case GDB_REGNO_MEPC: - return "mepc"; - case GDB_REGNO_MCAUSE: - return "mcause"; - case GDB_REGNO_PRIV: - return "priv"; - case GDB_REGNO_SATP: - return "satp"; - case GDB_REGNO_VTYPE: - return "vtype"; - case GDB_REGNO_VL: - return "vl"; - case GDB_REGNO_V0: - return "v0"; - case GDB_REGNO_V1: - return "v1"; - case GDB_REGNO_V2: - return "v2"; - case GDB_REGNO_V3: - return "v3"; - case GDB_REGNO_V4: - return "v4"; - case GDB_REGNO_V5: - return "v5"; - case GDB_REGNO_V6: - return "v6"; - case GDB_REGNO_V7: - return "v7"; - case GDB_REGNO_V8: - return "v8"; - case GDB_REGNO_V9: - return "v9"; - case GDB_REGNO_V10: - return "v10"; - case GDB_REGNO_V11: - return "v11"; - case GDB_REGNO_V12: - return "v12"; - case GDB_REGNO_V13: - return "v13"; - case GDB_REGNO_V14: - return "v14"; - case GDB_REGNO_V15: - return "v15"; - case GDB_REGNO_V16: - return "v16"; - case GDB_REGNO_V17: - return "v17"; - case GDB_REGNO_V18: - return "v18"; - case GDB_REGNO_V19: - return "v19"; - case GDB_REGNO_V20: - return "v20"; - case GDB_REGNO_V21: - return "v21"; - case GDB_REGNO_V22: - return "v22"; - case GDB_REGNO_V23: - return "v23"; - case GDB_REGNO_V24: - return "v24"; - case GDB_REGNO_V25: - return "v25"; - case GDB_REGNO_V26: - return "v26"; - case GDB_REGNO_V27: - return "v27"; - case GDB_REGNO_V28: - return "v28"; - case GDB_REGNO_V29: - return "v29"; - case GDB_REGNO_V30: - return "v30"; - case GDB_REGNO_V31: - return "v31"; - default: - if (regno <= GDB_REGNO_XPR31) - sprintf(buf, "x%d", regno - GDB_REGNO_ZERO); - else if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) - sprintf(buf, "csr%d", regno - GDB_REGNO_CSR0); - else if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) - sprintf(buf, "f%d", regno - GDB_REGNO_FPR0); - else - sprintf(buf, "gdb_regno_%d", regno); - return buf; + char * const buf = calloc(size_buf, sizeof(char)); + if (!buf) { + LOG_ERROR("Failed to allocate memory for a register name."); + return NULL; + } + strcpy(buf, name); + return buf; +} + +static char *init_reg_name_with_prefix(const char *name_prefix, + unsigned int num) +{ + const int size_buf = snprintf(NULL, 0, "%s%d", name_prefix, num) + 1; + + char * const buf = calloc(size_buf, sizeof(char)); + if (!buf) { + LOG_ERROR("Failed to allocate memory for a register name."); + return NULL; + } + int result = snprintf(buf, size_buf, "%s%d", name_prefix, num); + assert(result > 0 && result <= (size_buf - 1)); + return buf; +} + +static const char * const default_reg_names[GDB_REGNO_COUNT] = { + [GDB_REGNO_ZERO] = "zero", + [GDB_REGNO_RA] = "ra", + [GDB_REGNO_SP] = "sp", + [GDB_REGNO_GP] = "gp", + [GDB_REGNO_TP] = "tp", + [GDB_REGNO_T0] = "t0", + [GDB_REGNO_T1] = "t1", + [GDB_REGNO_T2] = "t2", + [GDB_REGNO_FP] = "fp", + [GDB_REGNO_S1] = "s1", + [GDB_REGNO_A0] = "a0", + [GDB_REGNO_A1] = "a1", + [GDB_REGNO_A2] = "a2", + [GDB_REGNO_A3] = "a3", + [GDB_REGNO_A4] = "a4", + [GDB_REGNO_A5] = "a5", + [GDB_REGNO_A6] = "a6", + [GDB_REGNO_A7] = "a7", + [GDB_REGNO_S2] = "s2", + [GDB_REGNO_S3] = "s3", + [GDB_REGNO_S4] = "s4", + [GDB_REGNO_S5] = "s5", + [GDB_REGNO_S6] = "s6", + [GDB_REGNO_S7] = "s7", + [GDB_REGNO_S8] = "s8", + [GDB_REGNO_S9] = "s9", + [GDB_REGNO_S10] = "s10", + [GDB_REGNO_S11] = "s11", + [GDB_REGNO_T3] = "t3", + [GDB_REGNO_T4] = "t4", + [GDB_REGNO_T5] = "t5", + [GDB_REGNO_T6] = "t6", + [GDB_REGNO_PC] = "pc", + [GDB_REGNO_CSR0] = "csr0", + [GDB_REGNO_PRIV] = "priv", + [GDB_REGNO_FT0] = "ft0", + [GDB_REGNO_FT1] = "ft1", + [GDB_REGNO_FT2] = "ft2", + [GDB_REGNO_FT3] = "ft3", + [GDB_REGNO_FT4] = "ft4", + [GDB_REGNO_FT5] = "ft5", + [GDB_REGNO_FT6] = "ft6", + [GDB_REGNO_FT7] = "ft7", + [GDB_REGNO_FS0] = "fs0", + [GDB_REGNO_FS1] = "fs1", + [GDB_REGNO_FA0] = "fa0", + [GDB_REGNO_FA1] = "fa1", + [GDB_REGNO_FA2] = "fa2", + [GDB_REGNO_FA3] = "fa3", + [GDB_REGNO_FA4] = "fa4", + [GDB_REGNO_FA5] = "fa5", + [GDB_REGNO_FA6] = "fa6", + [GDB_REGNO_FA7] = "fa7", + [GDB_REGNO_FS2] = "fs2", + [GDB_REGNO_FS3] = "fs3", + [GDB_REGNO_FS4] = "fs4", + [GDB_REGNO_FS5] = "fs5", + [GDB_REGNO_FS6] = "fs6", + [GDB_REGNO_FS7] = "fs7", + [GDB_REGNO_FS8] = "fs8", + [GDB_REGNO_FS9] = "fs9", + [GDB_REGNO_FS10] = "fs10", + [GDB_REGNO_FS11] = "fs11", + [GDB_REGNO_FT8] = "ft8", + [GDB_REGNO_FT9] = "ft9", + [GDB_REGNO_FT10] = "ft10", + [GDB_REGNO_FT11] = "ft11", + + #define DECLARE_CSR(csr_name, number)[(number) + GDB_REGNO_CSR0] = #csr_name, + #include "encoding.h" + #undef DECLARE_CSR +}; + +static void free_reg_names(struct target *target) +{ + RISCV_INFO(info); + + if (!info->reg_names) + return; + + for (unsigned int i = 0; i < GDB_REGNO_COUNT; ++i) + free(info->reg_names[i]); + free(info->reg_names); + info->reg_names = NULL; + + free_custom_register_names(target); +} + +static void init_custom_csr_names(struct target *target) +{ + RISCV_INFO(info); + range_list_t *entry; + + list_for_each_entry(entry, &info->expose_csr, list) { + if (!entry->name) + continue; + assert(entry->low == entry->high); + const unsigned int regno = entry->low + GDB_REGNO_CSR0; + assert(regno <= GDB_REGNO_CSR4095); + if (info->reg_names[regno]) + return; + info->reg_names[regno] = init_reg_name(entry->name); + } +} + +const char *gdb_regno_name(struct target *target, enum gdb_regno regno) +{ + RISCV_INFO(info); + + if (regno >= GDB_REGNO_COUNT) { + assert(info->custom_register_names.reg_names); + assert(regno - GDB_REGNO_COUNT <= info->custom_register_names.num_entries); + return info->custom_register_names.reg_names[regno - GDB_REGNO_COUNT]; + } + + if (!info->reg_names) + info->reg_names = calloc(GDB_REGNO_COUNT, sizeof(char *)); + + if (info->reg_names[regno]) + return info->reg_names[regno]; + if (default_reg_names[regno]) + return default_reg_names[regno]; + if (regno <= GDB_REGNO_XPR31) { + info->reg_names[regno] = init_reg_name_with_prefix("x", regno - GDB_REGNO_ZERO); + return info->reg_names[regno]; + } + if (regno <= GDB_REGNO_V31 && regno >= GDB_REGNO_V0) { + info->reg_names[regno] = init_reg_name_with_prefix("v", regno - GDB_REGNO_V0); + return info->reg_names[regno]; } + if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) { + init_custom_csr_names(target); + info->reg_names[regno] = init_reg_name_with_prefix("csr", regno - GDB_REGNO_CSR0); + return info->reg_names[regno]; + } + assert(!"Encountered uninitialized entry in reg_names table"); + + return NULL; } +/** + * This function is the handler of user's request to read a register. + */ static int register_get(struct reg *reg) { - riscv_reg_info_t *reg_info = reg->arch_info; - struct target *target = reg_info->target; + struct target *target = ((riscv_reg_info_t *)reg->arch_info)->target; RISCV_INFO(r); + /* TODO: Hack to deal with gdb that thinks these registers still exist. */ + if (reg->number > GDB_REGNO_XPR15 && reg->number <= GDB_REGNO_XPR31 && + riscv_supports_extension(target, 'E')) { + buf_set_u64(reg->value, 0, reg->size, 0); + return ERROR_OK; + } + if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) { if (!r->get_register_buf) { - LOG_ERROR("Reading register %s not supported on this RISC-V target.", - gdb_regno_name(reg->number)); + LOG_TARGET_ERROR(target, + "Reading register %s not supported on this target.", + reg->name); return ERROR_FAIL; } if (r->get_register_buf(target, reg->value, reg->number) != ERROR_OK) return ERROR_FAIL; + + reg->valid = gdb_regno_cacheable(reg->number, /* is write? */ false); } else { uint64_t value; int result = riscv_get_register(target, &value, reg->number); @@ -4165,33 +5725,32 @@ static int register_get(struct reg *reg) return result; buf_set_u64(reg->value, 0, reg->size, value); } - reg->valid = gdb_regno_cacheable(reg->number, false); char *str = buf_to_hex_str(reg->value, reg->size); - LOG_DEBUG("[%s] read 0x%s from %s (valid=%d)", target_name(target), - str, reg->name, reg->valid); + LOG_TARGET_DEBUG(target, "Read 0x%s from %s (valid=%d).", str, reg->name, + reg->valid); free(str); return ERROR_OK; } +/** + * This function is the handler of user's request to write a register. + */ static int register_set(struct reg *reg, uint8_t *buf) { - riscv_reg_info_t *reg_info = reg->arch_info; - struct target *target = reg_info->target; + struct target *target = ((riscv_reg_info_t *)reg->arch_info)->target; RISCV_INFO(r); char *str = buf_to_hex_str(buf, reg->size); - LOG_DEBUG("[%s] write 0x%s to %s (valid=%d)", target_name(target), - str, reg->name, reg->valid); + LOG_TARGET_DEBUG(target, "Write 0x%s to %s (valid=%d).", str, reg->name, + reg->valid); free(str); - /* Exit early for writing x0, which on the hardware would be ignored, and we - * don't want to update our cache. */ - if (reg->number == GDB_REGNO_ZERO) + /* TODO: Hack to deal with gdb that thinks these registers still exist. */ + if (reg->number > GDB_REGNO_XPR15 && reg->number <= GDB_REGNO_XPR31 && + riscv_supports_extension(target, 'E') && + buf_get_u64(buf, 0, reg->size) == 0) return ERROR_OK; - memcpy(reg->value, buf, DIV_ROUND_UP(reg->size, 8)); - reg->valid = gdb_regno_cacheable(reg->number, true); - if (reg->number == GDB_REGNO_TDATA1 || reg->number == GDB_REGNO_TDATA2) { r->manual_hwbp_set = true; @@ -4205,15 +5764,19 @@ static int register_set(struct reg *reg, uint8_t *buf) if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) { if (!r->set_register_buf) { - LOG_ERROR("Writing register %s not supported on this RISC-V target.", - gdb_regno_name(reg->number)); + LOG_TARGET_ERROR(target, + "Writing register %s not supported on this target.", + reg->name); return ERROR_FAIL; } - if (r->set_register_buf(target, reg->number, reg->value) != ERROR_OK) + if (r->set_register_buf(target, reg->number, buf) != ERROR_OK) return ERROR_FAIL; + + memcpy(reg->value, buf, DIV_ROUND_UP(reg->size, 8)); + reg->valid = gdb_regno_cacheable(reg->number, /* is write? */ true); } else { - uint64_t value = buf_get_u64(buf, 0, reg->size); + const riscv_reg_t value = buf_get_u64(buf, 0, reg->size); if (riscv_set_register(target, reg->number, value) != ERROR_OK) return ERROR_FAIL; } @@ -4226,14 +5789,54 @@ static struct reg_arch_type riscv_reg_arch_type = { .set = register_set }; -struct csr_info { - unsigned number; - const char *name; -}; +static int init_custom_register_names(struct list_head *expose_custom, + struct reg_name_table *custom_register_names) +{ + unsigned int custom_regs_num = 0; + if (!list_empty(expose_custom)) { + range_list_t *entry; + list_for_each_entry(entry, expose_custom, list) + custom_regs_num += entry->high - entry->low + 1; + } + + if (!custom_regs_num) + return ERROR_OK; + + custom_register_names->reg_names = calloc(custom_regs_num, sizeof(char *)); + if (!custom_register_names->reg_names) { + LOG_ERROR("Failed to allocate memory for custom_register_names->reg_names"); + return ERROR_FAIL; + } + custom_register_names->num_entries = custom_regs_num; + char **reg_names = custom_register_names->reg_names; + range_list_t *range; + unsigned int next_custom_reg_index = 0; + list_for_each_entry(range, expose_custom, list) { + for (unsigned int custom_number = range->low; custom_number <= range->high; ++custom_number) { + if (range->name) + reg_names[next_custom_reg_index] = init_reg_name(range->name); + else + reg_names[next_custom_reg_index] = + init_reg_name_with_prefix("custom", custom_number); + + if (!reg_names[next_custom_reg_index]) + return ERROR_FAIL; + ++next_custom_reg_index; + } + } + return ERROR_OK; +} -static int cmp_csr_info(const void *p1, const void *p2) +static bool is_known_standard_csr(unsigned int csr_num) { - return (int) (((struct csr_info *)p1)->number) - (int) (((struct csr_info *)p2)->number); + static const bool is_csr_in_buf[GDB_REGNO_CSR4095 - GDB_REGNO_CSR0 + 1] = { + #define DECLARE_CSR(csr_name, number)[number] = true, + #include "encoding.h" + #undef DECLARE_CSR + }; + assert(csr_num < ARRAY_SIZE(is_csr_in_buf)); + + return is_csr_in_buf[csr_num]; } int riscv_init_registers(struct target *target) @@ -4243,32 +5846,27 @@ int riscv_init_registers(struct target *target) riscv_free_registers(target); target->reg_cache = calloc(1, sizeof(*target->reg_cache)); - if (!target->reg_cache) + if (!target->reg_cache) { + LOG_TARGET_ERROR(target, "Failed to allocate memory for target->reg_cache"); return ERROR_FAIL; + } target->reg_cache->name = "RISC-V Registers"; - target->reg_cache->num_regs = GDB_REGNO_COUNT; - if (!list_empty(&info->expose_custom)) { - range_list_t *entry; - list_for_each_entry(entry, &info->expose_custom, list) - target->reg_cache->num_regs += entry->high - entry->low + 1; + if (init_custom_register_names(&info->expose_custom, &info->custom_register_names) != ERROR_OK) { + LOG_TARGET_ERROR(target, "init_custom_register_names failed"); + return ERROR_FAIL; } - LOG_DEBUG("[%s] create register cache for %d registers", - target_name(target), target->reg_cache->num_regs); + target->reg_cache->num_regs = GDB_REGNO_COUNT + info->custom_register_names.num_entries; + LOG_TARGET_DEBUG(target, "create register cache for %d registers", + target->reg_cache->num_regs); target->reg_cache->reg_list = calloc(target->reg_cache->num_regs, sizeof(struct reg)); - if (!target->reg_cache->reg_list) - return ERROR_FAIL; - - const unsigned int max_reg_name_len = 12; - free(info->reg_names); - info->reg_names = - calloc(target->reg_cache->num_regs, max_reg_name_len); - if (!info->reg_names) + if (!target->reg_cache->reg_list) { + LOG_TARGET_ERROR(target, "Failed to allocate memory for target->reg_cache->reg_list"); return ERROR_FAIL; - char *reg_name = info->reg_names; + } static struct reg_feature feature_cpu = { .name = "org.gnu.gdb.riscv.cpu" @@ -4400,152 +5998,45 @@ int riscv_init_registers(struct target *target) info->type_vector.type_class = REG_TYPE_CLASS_UNION; info->type_vector.reg_type_union = &info->vector_union; - struct csr_info csr_info[] = { -#define DECLARE_CSR(name, number) { number, #name }, -#include "encoding.h" -#undef DECLARE_CSR - }; - /* encoding.h does not contain the registers in sorted order. */ - qsort(csr_info, ARRAY_SIZE(csr_info), sizeof(*csr_info), cmp_csr_info); - unsigned csr_info_index = 0; - - int custom_within_range = 0; - riscv_reg_info_t *shared_reg_info = calloc(1, sizeof(riscv_reg_info_t)); if (!shared_reg_info) return ERROR_FAIL; shared_reg_info->target = target; + int custom_within_range = 0; + /* When gdb requests register N, gdb_get_register_packet() assumes that this * is register at index N in reg_list. So if there are certain registers * that don't exist, we need to leave holes in the list (or renumber, but * it would be nice not to have yet another set of numbers to translate * between). */ - for (uint32_t number = 0; number < target->reg_cache->num_regs; number++) { - struct reg *r = &target->reg_cache->reg_list[number]; + for (uint32_t reg_num = 0; reg_num < target->reg_cache->num_regs; reg_num++) { + struct reg *r = &target->reg_cache->reg_list[reg_num]; r->dirty = false; r->valid = false; r->exist = true; r->type = &riscv_reg_arch_type; r->arch_info = shared_reg_info; - r->number = number; + r->number = reg_num; r->size = riscv_xlen(target); /* r->size is set in riscv_invalidate_register_cache, maybe because the * target is in theory allowed to change XLEN on us. But I expect a lot * of other things to break in that case as well. */ - if (number <= GDB_REGNO_XPR31) { - r->exist = number <= GDB_REGNO_XPR15 || + r->name = gdb_regno_name(target, reg_num); + if (reg_num <= GDB_REGNO_XPR31) { + r->exist = reg_num <= GDB_REGNO_XPR15 || !riscv_supports_extension(target, 'E'); /* TODO: For now we fake that all GPRs exist because otherwise gdb * doesn't work. */ r->exist = true; r->caller_save = true; - switch (number) { - case GDB_REGNO_ZERO: - r->name = "zero"; - break; - case GDB_REGNO_RA: - r->name = "ra"; - break; - case GDB_REGNO_SP: - r->name = "sp"; - break; - case GDB_REGNO_GP: - r->name = "gp"; - break; - case GDB_REGNO_TP: - r->name = "tp"; - break; - case GDB_REGNO_T0: - r->name = "t0"; - break; - case GDB_REGNO_T1: - r->name = "t1"; - break; - case GDB_REGNO_T2: - r->name = "t2"; - break; - case GDB_REGNO_FP: - r->name = "fp"; - break; - case GDB_REGNO_S1: - r->name = "s1"; - break; - case GDB_REGNO_A0: - r->name = "a0"; - break; - case GDB_REGNO_A1: - r->name = "a1"; - break; - case GDB_REGNO_A2: - r->name = "a2"; - break; - case GDB_REGNO_A3: - r->name = "a3"; - break; - case GDB_REGNO_A4: - r->name = "a4"; - break; - case GDB_REGNO_A5: - r->name = "a5"; - break; - case GDB_REGNO_A6: - r->name = "a6"; - break; - case GDB_REGNO_A7: - r->name = "a7"; - break; - case GDB_REGNO_S2: - r->name = "s2"; - break; - case GDB_REGNO_S3: - r->name = "s3"; - break; - case GDB_REGNO_S4: - r->name = "s4"; - break; - case GDB_REGNO_S5: - r->name = "s5"; - break; - case GDB_REGNO_S6: - r->name = "s6"; - break; - case GDB_REGNO_S7: - r->name = "s7"; - break; - case GDB_REGNO_S8: - r->name = "s8"; - break; - case GDB_REGNO_S9: - r->name = "s9"; - break; - case GDB_REGNO_S10: - r->name = "s10"; - break; - case GDB_REGNO_S11: - r->name = "s11"; - break; - case GDB_REGNO_T3: - r->name = "t3"; - break; - case GDB_REGNO_T4: - r->name = "t4"; - break; - case GDB_REGNO_T5: - r->name = "t5"; - break; - case GDB_REGNO_T6: - r->name = "t6"; - break; - } r->group = "general"; r->feature = &feature_cpu; - } else if (number == GDB_REGNO_PC) { + } else if (reg_num == GDB_REGNO_PC) { r->caller_save = true; - sprintf(reg_name, "pc"); r->group = "general"; r->feature = &feature_cpu; - } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + } else if (reg_num >= GDB_REGNO_FPR0 && reg_num <= GDB_REGNO_FPR31) { r->caller_save = true; if (riscv_supports_extension(target, 'D')) { r->size = 64; @@ -4559,119 +6050,14 @@ int riscv_init_registers(struct target *target) } else { r->exist = false; } - switch (number) { - case GDB_REGNO_FT0: - r->name = "ft0"; - break; - case GDB_REGNO_FT1: - r->name = "ft1"; - break; - case GDB_REGNO_FT2: - r->name = "ft2"; - break; - case GDB_REGNO_FT3: - r->name = "ft3"; - break; - case GDB_REGNO_FT4: - r->name = "ft4"; - break; - case GDB_REGNO_FT5: - r->name = "ft5"; - break; - case GDB_REGNO_FT6: - r->name = "ft6"; - break; - case GDB_REGNO_FT7: - r->name = "ft7"; - break; - case GDB_REGNO_FS0: - r->name = "fs0"; - break; - case GDB_REGNO_FS1: - r->name = "fs1"; - break; - case GDB_REGNO_FA0: - r->name = "fa0"; - break; - case GDB_REGNO_FA1: - r->name = "fa1"; - break; - case GDB_REGNO_FA2: - r->name = "fa2"; - break; - case GDB_REGNO_FA3: - r->name = "fa3"; - break; - case GDB_REGNO_FA4: - r->name = "fa4"; - break; - case GDB_REGNO_FA5: - r->name = "fa5"; - break; - case GDB_REGNO_FA6: - r->name = "fa6"; - break; - case GDB_REGNO_FA7: - r->name = "fa7"; - break; - case GDB_REGNO_FS2: - r->name = "fs2"; - break; - case GDB_REGNO_FS3: - r->name = "fs3"; - break; - case GDB_REGNO_FS4: - r->name = "fs4"; - break; - case GDB_REGNO_FS5: - r->name = "fs5"; - break; - case GDB_REGNO_FS6: - r->name = "fs6"; - break; - case GDB_REGNO_FS7: - r->name = "fs7"; - break; - case GDB_REGNO_FS8: - r->name = "fs8"; - break; - case GDB_REGNO_FS9: - r->name = "fs9"; - break; - case GDB_REGNO_FS10: - r->name = "fs10"; - break; - case GDB_REGNO_FS11: - r->name = "fs11"; - break; - case GDB_REGNO_FT8: - r->name = "ft8"; - break; - case GDB_REGNO_FT9: - r->name = "ft9"; - break; - case GDB_REGNO_FT10: - r->name = "ft10"; - break; - case GDB_REGNO_FT11: - r->name = "ft11"; - break; - } r->group = "float"; r->feature = &feature_fpu; - } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + } else if (reg_num >= GDB_REGNO_CSR0 && reg_num <= GDB_REGNO_CSR4095) { r->group = "csr"; r->feature = &feature_csr; - unsigned csr_number = number - GDB_REGNO_CSR0; + const unsigned int csr_num = reg_num - GDB_REGNO_CSR0; - while (csr_info[csr_info_index].number < csr_number && - csr_info_index < ARRAY_SIZE(csr_info) - 1) { - csr_info_index++; - } - if (csr_info[csr_info_index].number == csr_number) { - r->name = csr_info[csr_info_index].name; - } else { - sprintf(reg_name, "csr%d", csr_number); + if (!is_known_standard_csr(csr_num)) { /* Assume unnamed registers don't exist, unless we have some * configuration that tells us otherwise. That's important * because eg. Eclipse crashes if a target has too many @@ -4680,19 +6066,28 @@ int riscv_init_registers(struct target *target) r->exist = false; } - switch (csr_number) { + switch (csr_num) { + case CSR_DCSR: + case CSR_MVENDORID: + case CSR_MCOUNTINHIBIT: + r->size = 32; + break; + case CSR_FCSR: + r->size = 32; + /* fall through */ case CSR_FFLAGS: case CSR_FRM: - case CSR_FCSR: r->exist = riscv_supports_extension(target, 'F'); r->group = "float"; r->feature = &feature_fpu; break; + case CSR_SCOUNTEREN: + r->size = 32; + /* fall through */ case CSR_SSTATUS: case CSR_STVEC: case CSR_SIP: case CSR_SIE: - case CSR_SCOUNTEREN: case CSR_SSCRATCH: case CSR_SEPC: case CSR_SCAUSE: @@ -4781,68 +6176,140 @@ int riscv_init_registers(struct target *target) case CSR_VXSAT: case CSR_VXRM: case CSR_VL: + case CSR_VCSR: case CSR_VTYPE: case CSR_VLENB: - r->exist = riscv_supports_extension(target, 'V'); + r->exist = (info->vlenb > 0); + break; + case CSR_MCOUNTEREN: + r->size = 32; + r->exist = riscv_supports_extension(target, 'U'); + break; + + /* Interrupts M-Mode CSRs. */ + case CSR_MISELECT: + case CSR_MIREG: + case CSR_MTOPI: + case CSR_MVIEN: + case CSR_MVIP: + r->exist = info->mtopi_readable; + break; + case CSR_MTOPEI: + r->exist = info->mtopei_readable; + break; + case CSR_MIDELEGH: + case CSR_MVIENH: + case CSR_MVIPH: + r->exist = info->mtopi_readable && + riscv_xlen(target) == 32 && + riscv_supports_extension(target, 'S'); + break; + case CSR_MIEH: + case CSR_MIPH: + r->exist = info->mtopi_readable; + break; + /* Interrupts S-Mode CSRs. */ + case CSR_SISELECT: + case CSR_SIREG: + case CSR_STOPI: + r->exist = info->mtopi_readable && + riscv_supports_extension(target, 'S'); + break; + case CSR_STOPEI: + r->exist = info->mtopei_readable && + riscv_supports_extension(target, 'S'); + break; + case CSR_SIEH: + case CSR_SIPH: + r->exist = info->mtopi_readable && + riscv_xlen(target) == 32 && + riscv_supports_extension(target, 'S'); + break; + /* Interrupts Hypervisor and VS CSRs. */ + case CSR_HVIEN: + case CSR_HVICTL: + case CSR_HVIPRIO1: + case CSR_HVIPRIO2: + case CSR_VSISELECT: + case CSR_VSIREG: + case CSR_VSTOPI: + r->exist = info->mtopi_readable && + riscv_supports_extension(target, 'H'); + break; + case CSR_VSTOPEI: + r->exist = info->mtopei_readable && + riscv_supports_extension(target, 'H'); + break; + case CSR_HIDELEGH: + case CSR_HVIENH: + case CSR_HVIPH: + case CSR_HVIPRIO1H: + case CSR_HVIPRIO2H: + case CSR_VSIEH: + case CSR_VSIPH: + r->exist = info->mtopi_readable && + riscv_xlen(target) == 32 && + riscv_supports_extension(target, 'H'); break; } if (!r->exist && !list_empty(&info->expose_csr)) { range_list_t *entry; list_for_each_entry(entry, &info->expose_csr, list) - if ((entry->low <= csr_number) && (csr_number <= entry->high)) { - if (entry->name) { - *reg_name = 0; - r->name = entry->name; - } - - LOG_DEBUG("Exposing additional CSR %d (name=%s)", - csr_number, entry->name ? entry->name : reg_name); - + if (entry->low <= csr_num && csr_num <= entry->high) { + LOG_TARGET_DEBUG(target, "Exposing additional CSR %d (name=%s)", + csr_num, r->name); r->exist = true; break; } + } else if (r->exist && !list_empty(&info->hide_csr)) { + range_list_t *entry; + list_for_each_entry(entry, &info->hide_csr, list) + if (entry->low <= csr_num && csr_num <= entry->high) { + LOG_TARGET_DEBUG(target, "Hiding CSR %d (name=%s).", csr_num, r->name); + r->hidden = true; + break; + } } - } else if (number == GDB_REGNO_PRIV) { - sprintf(reg_name, "priv"); + } else if (reg_num == GDB_REGNO_PRIV) { r->group = "general"; r->feature = &feature_virtual; r->size = 8; - } else if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31) { + } else if (reg_num >= GDB_REGNO_V0 && reg_num <= GDB_REGNO_V31) { r->caller_save = false; - r->exist = riscv_supports_extension(target, 'V') && info->vlenb; + r->exist = (info->vlenb > 0); r->size = info->vlenb * 8; - sprintf(reg_name, "v%d", number - GDB_REGNO_V0); r->group = "vector"; r->feature = &feature_vector; r->reg_data_type = &info->type_vector; - } else if (number >= GDB_REGNO_COUNT) { + } else if (reg_num >= GDB_REGNO_COUNT) { /* Custom registers. */ + const unsigned int custom_reg_index = reg_num - GDB_REGNO_COUNT; + assert(!list_empty(&info->expose_custom)); + assert(custom_reg_index < info->custom_register_names.num_entries); range_list_t *range = list_first_entry(&info->expose_custom, range_list_t, list); - unsigned custom_number = range->low + custom_within_range; + const unsigned int custom_number = range->low + custom_within_range; r->group = "custom"; r->feature = &feature_custom; r->arch_info = calloc(1, sizeof(riscv_reg_info_t)); - if (!r->arch_info) + if (!r->arch_info) { + LOG_ERROR("Failed to allocate memory for r->arch_info"); return ERROR_FAIL; - ((riscv_reg_info_t *) r->arch_info)->target = target; - ((riscv_reg_info_t *) r->arch_info)->custom_number = custom_number; - sprintf(reg_name, "custom%d", custom_number); - - if (range->name) { - *reg_name = 0; - r->name = range->name; } + ((riscv_reg_info_t *)r->arch_info)->target = target; + ((riscv_reg_info_t *)r->arch_info)->custom_number = custom_number; - LOG_DEBUG("Exposing additional custom register %d (name=%s)", - number, range->name ? range->name : reg_name); + char **reg_names = info->custom_register_names.reg_names; + r->name = reg_names[custom_reg_index]; + + LOG_TARGET_DEBUG(target, "Exposing additional custom register %d (name=%s)", reg_num, r->name); custom_within_range++; if (custom_within_range > range->high - range->low) { @@ -4851,12 +6318,6 @@ int riscv_init_registers(struct target *target) } } - if (reg_name[0]) { - r->name = reg_name; - reg_name += strlen(reg_name) + 1; - assert(reg_name < info->reg_names + target->reg_cache->num_regs * - max_reg_name_len); - } r->value = calloc(1, DIV_ROUND_UP(r->size, 8)); } diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 74eff70075..60bea46dc6 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -10,22 +10,27 @@ struct riscv_program; #include "gdb_regs.h" #include "jtag/jtag.h" #include "target/register.h" +#include "target/semihosting_common.h" #include <helper/command.h> +#include <helper/bits.h> -/* The register cache is statically allocated. */ -#define RISCV_MAX_HARTS 1024 -#define RISCV_MAX_REGISTERS 5000 +#define RISCV_COMMON_MAGIC 0x52495356U + +#define RISCV_MAX_HARTS ((int)BIT(20)) #define RISCV_MAX_TRIGGERS 32 #define RISCV_MAX_HWBPS 16 +#define RISCV_MAX_DMS 100 #define DEFAULT_COMMAND_TIMEOUT_SEC 2 #define DEFAULT_RESET_TIMEOUT_SEC 30 #define RISCV_SATP_MODE(xlen) ((xlen) == 32 ? SATP32_MODE : SATP64_MODE) #define RISCV_SATP_PPN(xlen) ((xlen) == 32 ? SATP32_PPN : SATP64_PPN) +#define RISCV_HGATP_MODE(xlen) ((xlen) == 32 ? HGATP32_MODE : HGATP64_MODE) +#define RISCV_HGATP_PPN(xlen) ((xlen) == 32 ? HGATP32_PPN : HGATP64_PPN) #define RISCV_PGSHIFT 12 -# define PG_MAX_LEVEL 4 +#define PG_MAX_LEVEL 5 #define RISCV_NUM_MEM_ACCESS_METHODS 3 @@ -41,6 +46,12 @@ typedef uint64_t riscv_reg_t; typedef uint32_t riscv_insn_t; typedef uint64_t riscv_addr_t; +typedef enum { + YNM_MAYBE, + YNM_YES, + YNM_NO +} yes_no_maybe_t; + enum riscv_mem_access_method { RISCV_MEM_ACCESS_UNSPECIFIED, RISCV_MEM_ACCESS_PROGBUF, @@ -50,7 +61,7 @@ enum riscv_mem_access_method { enum riscv_halt_reason { RISCV_HALT_INTERRUPT, - RISCV_HALT_BREAKPOINT, + RISCV_HALT_EBREAK, RISCV_HALT_SINGLESTEP, RISCV_HALT_TRIGGER, RISCV_HALT_UNKNOWN, @@ -65,6 +76,13 @@ enum riscv_isrmasking_mode { RISCV_ISRMASK_STEPONLY, }; +enum riscv_hart_state { + RISCV_STATE_NON_EXISTENT, + RISCV_STATE_RUNNING, + RISCV_STATE_HALTED, + RISCV_STATE_UNAVAILABLE +}; + typedef struct { struct target *target; unsigned custom_number; @@ -93,27 +111,52 @@ typedef struct { char *name; } range_list_t; -typedef struct { - unsigned dtm_version; +#define DTM_DTMCS_VERSION_UNKNOWN ((unsigned int)-1) + +struct reg_name_table { + unsigned int num_entries; + char **reg_names; +}; + +struct riscv_info { + unsigned int common_magic; + + unsigned int dtm_version; struct command_context *cmd_ctx; void *version_specific; - /* Single buffer that contains all register names, instead of calling - * malloc for each register. Needs to be freed when reg_list is freed. */ - char *reg_names; + struct reg_name_table custom_register_names; + char **reg_names; /* It's possible that each core has a different supported ISA set. */ int xlen; riscv_reg_t misa; - /* Cached value of vlenb. 0 if vlenb is not readable for some reason. */ + /* Cached value of vlenb. 0 indicates there is no vector support. + * Note that you can have vector support without misa.V set, because + * Zve* extensions implement vector registers without setting misa.V. */ unsigned int vlenb; + bool mtopi_readable; + bool mtopei_readable; + /* The number of triggers per hart. */ unsigned int trigger_count; - /* For each physical trigger, contains -1 if the hwbp is available, or the - * unique_id of the breakpoint/watchpoint that is using it. + /* Data structure to record known unsupported tdata1+tdata2 trigger CSR values. + * This is to avoid repetitive attempts to set trigger configurations that are already + * known to be unsupported in the HW. + * A separate data structure is created for each trigger. */ + struct list_head *wp_triggers_negative_cache; + + /* record the tinfo of each trigger */ + unsigned int trigger_tinfo[RISCV_MAX_TRIGGERS]; + + /* For each physical trigger contains: + * -1: the hwbp is available + * -4: The trigger is used by the itrigger command + * -5: The trigger is used by the etrigger command + * >= 0: unique_id of the breakpoint/watchpoint that is using it. * Note that in RTOS mode the triggers are the same across all harts the * target controls, while otherwise only a single hart is controlled. */ int trigger_unique_id[RISCV_MAX_HWBPS]; @@ -122,8 +165,8 @@ typedef struct { * most recent halt was not caused by a trigger, then this is -1. */ uint32_t trigger_hit; - /* The number of entries in the debug buffer. */ - int debug_buffer_size; + /* The number of entries in the program buffer. */ + int progbuf_size; /* This hart contains an implicit ebreak at the end of the program buffer. */ bool impebreak; @@ -139,23 +182,44 @@ typedef struct { /* This target was selected using hasel. */ bool selected; + /* Used by riscv_openocd_poll(). */ + bool halted_needs_event_callback; + enum target_event halted_callback_event; + enum riscv_isrmasking_mode isrmask_mode; /* Helper functions that target the various RISC-V debug spec * implementations. */ - int (*get_register)(struct target *target, riscv_reg_t *value, int regid); - int (*set_register)(struct target *target, int regid, uint64_t value); - int (*get_register_buf)(struct target *target, uint8_t *buf, int regno); - int (*set_register_buf)(struct target *target, int regno, + int (*get_register)(struct target *target, riscv_reg_t *value, + enum gdb_regno regno); + int (*set_register)(struct target *target, enum gdb_regno regno, + riscv_reg_t value); + int (*get_register_buf)(struct target *target, uint8_t *buf, + enum gdb_regno regno); + int (*set_register_buf)(struct target *target, enum gdb_regno regno, const uint8_t *buf); int (*select_target)(struct target *target); - bool (*is_halted)(struct target *target); + int (*get_hart_state)(struct target *target, enum riscv_hart_state *state); /* Resume this target, as well as every other prepped target that can be * resumed near-simultaneously. Clear the prepped flag on any target that * was resumed. */ int (*resume_go)(struct target *target); int (*step_current_hart)(struct target *target); - int (*on_halt)(struct target *target); + + /* These get called from riscv_poll_hart(), which is a house of cards + * together with openocd_poll(), so be careful not to upset things too + * much. */ + int (*handle_became_halted)(struct target *target, + enum riscv_hart_state previous_riscv_state); + int (*handle_became_running)(struct target *target, + enum riscv_hart_state previous_riscv_state); + int (*handle_became_unavailable)(struct target *target, + enum riscv_hart_state previous_riscv_state); + + /* Called periodically (no guarantees about frequency), while there's + * nothing else going on. */ + int (*tick)(struct target *target); + /* Get this target as ready as possible to resume, without actually * resuming. */ int (*resume_prep)(struct target *target); @@ -163,15 +227,14 @@ typedef struct { int (*halt_go)(struct target *target); int (*on_step)(struct target *target); enum riscv_halt_reason (*halt_reason)(struct target *target); - int (*write_debug_buffer)(struct target *target, unsigned index, - riscv_insn_t d); - riscv_insn_t (*read_debug_buffer)(struct target *target, unsigned index); - int (*execute_debug_buffer)(struct target *target); - int (*invalidate_cached_debug_buffer)(struct target *target); - int (*dmi_write_u64_bits)(struct target *target); - void (*fill_dmi_write_u64)(struct target *target, char *buf, int a, uint64_t d); - void (*fill_dmi_read_u64)(struct target *target, char *buf, int a); - void (*fill_dmi_nop_u64)(struct target *target, char *buf); + int (*write_progbuf)(struct target *target, unsigned int index, riscv_insn_t d); + riscv_insn_t (*read_progbuf)(struct target *target, unsigned int index); + int (*execute_progbuf)(struct target *target, uint32_t *cmderr); + int (*invalidate_cached_progbuf)(struct target *target); + int (*get_dmi_scan_length)(struct target *target); + void (*fill_dm_write)(struct target *target, char *buf, uint64_t a, uint32_t d); + void (*fill_dm_read)(struct target *target, char *buf, uint64_t a); + void (*fill_dm_nop)(struct target *target, char *buf); int (*authdata_read)(struct target *target, uint32_t *value, unsigned int index); int (*authdata_write)(struct target *target, uint32_t value, unsigned int index); @@ -179,8 +242,11 @@ typedef struct { int (*dmi_read)(struct target *target, uint32_t *value, uint32_t address); int (*dmi_write)(struct target *target, uint32_t address, uint32_t value); - int (*test_sba_config_reg)(struct target *target, target_addr_t legal_address, - uint32_t num_words, target_addr_t illegal_address, bool run_sbbusyerror_test); + /* Get the DMI address of target's DM's register. + * The function should return the passed address + * if the target is not assigned a DM yet. + */ + uint32_t (*get_dmi_address)(const struct target *target, uint32_t dm_address); int (*sample_memory)(struct target *target, struct riscv_sample_buf *buf, @@ -190,8 +256,6 @@ typedef struct { int (*read_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment); - /* How many harts are attached to the DM that this target is attached to? */ - int (*hart_count)(struct target *target); unsigned (*data_bits)(struct target *target); COMMAND_HELPER((*print_info), struct target *target); @@ -232,12 +296,28 @@ typedef struct { * from range 0xc000 ... 0xffff. */ struct list_head expose_custom; + /* The list of registers to mark as "hidden". Hidden registers are available + * but do not appear in gdb targets description or reg command output. */ + struct list_head hide_csr; + riscv_sample_config_t sample_config; struct riscv_sample_buf sample_buf; /* Track when we were last asked to do something substantial. */ int64_t last_activity; -} riscv_info_t; + + yes_no_maybe_t vsew64_supported; + + bool range_trigger_fallback_encountered; + + bool riscv_ebreakm; + bool riscv_ebreaks; + bool riscv_ebreaku; + + bool wp_allow_equality_match_trigger; + bool wp_allow_napot_trigger; + bool wp_allow_ge_lt_trigger; +}; COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key, unsigned int value); @@ -251,6 +331,7 @@ typedef struct { const char *name; int level; unsigned va_bits; + /* log2(PTESIZE) */ unsigned pte_shift; unsigned vpn_shift[PG_MAX_LEVEL]; unsigned vpn_mask[PG_MAX_LEVEL]; @@ -267,35 +348,32 @@ extern int riscv_command_timeout_sec; extern int riscv_reset_timeout_sec; extern bool riscv_enable_virtual; -extern bool riscv_ebreakm; -extern bool riscv_ebreaks; -extern bool riscv_ebreaku; /* Everything needs the RISC-V specific info structure, so here's a nice macro * that provides that. */ -static inline riscv_info_t *riscv_info(const struct target *target) __attribute__((unused)); -static inline riscv_info_t *riscv_info(const struct target *target) +static inline struct riscv_info *riscv_info(const struct target *target) __attribute__((unused)); +static inline struct riscv_info *riscv_info(const struct target *target) { assert(target->arch_info); return target->arch_info; } -#define RISCV_INFO(R) riscv_info_t *R = riscv_info(target); +#define RISCV_INFO(R) struct riscv_info *R = riscv_info(target); + +static inline bool is_riscv(const struct riscv_info *riscv_info) +{ + return riscv_info->common_magic == RISCV_COMMON_MAGIC; +} -extern uint8_t ir_dtmcontrol[4]; extern struct scan_field select_dtmcontrol; -extern uint8_t ir_dbus[4]; extern struct scan_field select_dbus; -extern uint8_t ir_idcode[4]; extern struct scan_field select_idcode; -extern struct scan_field select_user4; extern struct scan_field *bscan_tunneled_select_dmi; extern uint32_t bscan_tunneled_select_dmi_num_fields; typedef enum { BSCAN_TUNNEL_NESTED_TAP, BSCAN_TUNNEL_DATA_REGISTER } bscan_tunnel_type_t; extern int bscan_tunnel_ir_width; -extern bscan_tunnel_type_t bscan_tunnel_type; -uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out); +int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ptr); void select_dmi_via_bscan(struct target *target); /*** OpenOCD Interface */ @@ -303,15 +381,6 @@ int riscv_openocd_poll(struct target *target); int riscv_halt(struct target *target); -int riscv_resume( - struct target *target, - int current, - target_addr_t address, - int handle_breakpoints, - int debug_execution, - bool single_hart -); - int riscv_openocd_step( struct target *target, int current, @@ -319,39 +388,26 @@ int riscv_openocd_step( int handle_breakpoints ); -int riscv_openocd_assert_reset(struct target *target); -int riscv_openocd_deassert_reset(struct target *target); - /*** RISC-V Interface ***/ -/* Initializes the shared RISC-V structure. */ -void riscv_info_init(struct target *target, riscv_info_t *r); - -/* Steps the hart that's currently selected in the RTOS, or if there is no RTOS - * then the only hart. */ -int riscv_step_rtos_hart(struct target *target); - bool riscv_supports_extension(struct target *target, char letter); /* Returns XLEN for the given (or current) hart. */ unsigned riscv_xlen(const struct target *target); -int riscv_xlen_of_hart(const struct target *target); - -/* Sets the current hart, which is the hart that will actually be used when - * issuing debug commands. */ -int riscv_set_current_hartid(struct target *target, int hartid); -int riscv_select_current_hart(struct target *target); -int riscv_current_hartid(const struct target *target); /*** Support functions for the RISC-V 'RTOS', which provides multihart support * without requiring multiple targets. */ -/* Lists the number of harts in the system, which are assumed to be - * consecutive and start with mhartid=0. */ -unsigned int riscv_count_harts(struct target *target); - -/** Set register, updating the cache. */ +/** + * Set the register value. For cacheable registers, only the cache is updated + * (write-back mode). + */ int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v); +/** + * Set the register value and immediately write it to the target + * (write-through mode). + */ +int riscv_write_register(struct target *target, enum gdb_regno i, riscv_reg_t v); /** Get register, from the cache if it's in there. */ int riscv_get_register(struct target *target, riscv_reg_t *value, enum gdb_regno r); @@ -363,45 +419,32 @@ int riscv_flush_registers(struct target *target); /* Checks the state of the current hart -- "is_halted" checks the actual * on-device register. */ -bool riscv_is_halted(struct target *target); -enum riscv_halt_reason riscv_halt_reason(struct target *target); +int riscv_get_hart_state(struct target *target, enum riscv_hart_state *state); /* These helper functions let the generic program interface get target-specific * information. */ -size_t riscv_debug_buffer_size(struct target *target); - -riscv_insn_t riscv_read_debug_buffer(struct target *target, int index); -int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn); -int riscv_execute_debug_buffer(struct target *target); +size_t riscv_progbuf_size(struct target *target); -void riscv_fill_dmi_nop_u64(struct target *target, char *buf); -void riscv_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d); -void riscv_fill_dmi_read_u64(struct target *target, char *buf, int a); -int riscv_dmi_write_u64_bits(struct target *target); +riscv_insn_t riscv_read_progbuf(struct target *target, int index); +int riscv_write_progbuf(struct target *target, int index, riscv_insn_t insn); +int riscv_execute_progbuf(struct target *target, uint32_t *cmderr); -/* Invalidates the register cache. */ -void riscv_invalidate_register_cache(struct target *target); +void riscv_fill_dm_nop(struct target *target, char *buf); +void riscv_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d); +void riscv_fill_dm_read(struct target *target, char *buf, uint64_t a); +int riscv_get_dmi_scan_length(struct target *target); int riscv_enumerate_triggers(struct target *target); -int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint); -int riscv_remove_breakpoint(struct target *target, - struct breakpoint *breakpoint); int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint); int riscv_remove_watchpoint(struct target *target, struct watchpoint *watchpoint); -int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_wp_address); int riscv_init_registers(struct target *target); void riscv_semihosting_init(struct target *target); -typedef enum { - SEMI_NONE, /* Not halted for a semihosting call. */ - SEMI_HANDLED, /* Call handled, and target was resumed. */ - SEMI_WAITING, /* Call handled, target is halted waiting until we can resume. */ - SEMI_ERROR /* Something went wrong. */ -} semihosting_result_t; -semihosting_result_t riscv_semihosting(struct target *target, int *retval); + +enum semihosting_result riscv_semihosting(struct target *target, int *retval); void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field, riscv_bscan_tunneled_scan_context_t *ctxt); diff --git a/src/target/riscv/riscv_semihosting.c b/src/target/riscv/riscv_semihosting.c index 2c53813eec..9c708c8a48 100644 --- a/src/target/riscv/riscv_semihosting.c +++ b/src/target/riscv/riscv_semihosting.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +// SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2018 by Liviu Ionescu * @@ -12,19 +12,6 @@ * * * Copyright (C) 2016 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * - * * - * 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/>. * ***************************************************************************/ /** @@ -44,7 +31,6 @@ #include <helper/log.h> #include "target/target.h" -#include "target/semihosting_common.h" #include "riscv.h" static int riscv_semihosting_setup(struct target *target, int enable); @@ -67,51 +53,49 @@ void riscv_semihosting_init(struct target *target) * @param retval Pointer to a location where the return code will be stored * @return non-zero value if a request was processed or an error encountered */ -semihosting_result_t riscv_semihosting(struct target *target, int *retval) +enum semihosting_result riscv_semihosting(struct target *target, int *retval) { struct semihosting *semihosting = target->semihosting; if (!semihosting) { - LOG_DEBUG(" -> NONE (!semihosting)"); - return SEMI_NONE; + LOG_TARGET_DEBUG(target, " -> NONE (!semihosting)"); + return SEMIHOSTING_NONE; } if (!semihosting->is_active) { - LOG_DEBUG(" -> NONE (!semihosting->is_active)"); - return SEMI_NONE; + LOG_TARGET_DEBUG(target, " -> NONE (!semihosting->is_active)"); + return SEMIHOSTING_NONE; } riscv_reg_t pc; int result = riscv_get_register(target, &pc, GDB_REGNO_PC); if (result != ERROR_OK) - return SEMI_ERROR; + return SEMIHOSTING_ERROR; - uint8_t tmp_buf[12]; + /* + * The instructions that trigger a semihosting call, + * always uncompressed, should look like: + */ + uint32_t magic[] = { + 0x01f01013, /* slli zero,zero,0x1f */ + 0x00100073, /* ebreak */ + 0x40705013 /* srai zero,zero,0x7 */ + }; /* Read three uncompressed instructions: The previous, the current one (pointed to by PC) and the next one */ for (int i = 0; i < 3; i++) { + uint8_t buf[4]; /* Instruction memories may not support arbitrary read size. Use any size that will work. */ - *retval = riscv_read_by_any_size(target, (pc - 4) + 4 * i, 4, tmp_buf + 4 * i); + target_addr_t address = (pc - 4) + 4 * i; + *retval = riscv_read_by_any_size(target, address, 4, buf); if (*retval != ERROR_OK) - return SEMI_ERROR; - } - - /* - * The instructions that trigger a semihosting call, - * always uncompressed, should look like: - * - * 01f01013 slli zero,zero,0x1f - * 00100073 ebreak - * 40705013 srai zero,zero,0x7 - */ - uint32_t pre = target_buffer_get_u32(target, tmp_buf); - uint32_t ebreak = target_buffer_get_u32(target, tmp_buf + 4); - uint32_t post = target_buffer_get_u32(target, tmp_buf + 8); - LOG_DEBUG("check %08x %08x %08x from 0x%" PRIx64 "-4", pre, ebreak, post, pc); - - if (pre != 0x01f01013 || ebreak != 0x00100073 || post != 0x40705013) { - /* Not the magic sequence defining semihosting. */ - LOG_DEBUG(" -> NONE (no magic)"); - return SEMI_NONE; + return SEMIHOSTING_ERROR; + uint32_t value = target_buffer_get_u32(target, buf); + LOG_TARGET_DEBUG(target, "compare 0x%08x from 0x%" PRIx64 " against 0x%08x", + value, address, magic[i]); + if (value != magic[i]) { + LOG_TARGET_DEBUG(target, " -> NONE (no magic)"); + return SEMIHOSTING_NONE; + } } /* @@ -125,14 +109,14 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval) result = riscv_get_register(target, &r0, GDB_REGNO_A0); if (result != ERROR_OK) { - LOG_DEBUG(" -> ERROR (couldn't read a0)"); - return SEMI_ERROR; + LOG_TARGET_ERROR(target, "Could not read semihosting operation code (register a0)"); + return SEMIHOSTING_ERROR; } result = riscv_get_register(target, &r1, GDB_REGNO_A1); if (result != ERROR_OK) { - LOG_DEBUG(" -> ERROR (couldn't read a1)"); - return SEMI_ERROR; + LOG_TARGET_ERROR(target, "Could not read semihosting operation code (register a1)"); + return SEMIHOSTING_ERROR; } semihosting->op = r0; @@ -145,32 +129,32 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval) *retval = semihosting_common(target); if (*retval != ERROR_OK) { - LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op); - return SEMI_ERROR; + LOG_TARGET_ERROR(target, "Failed semihosting operation (0x%02X)", semihosting->op); + return SEMIHOSTING_ERROR; } } else { /* Unknown operation number, not a semihosting call. */ - LOG_DEBUG(" -> NONE (unknown operation number)"); - return SEMI_NONE; + LOG_TARGET_ERROR(target, "Unknown semihosting operation requested (op = 0x%x)", semihosting->op); + return SEMIHOSTING_NONE; } } /* Resume right after the EBREAK 4 bytes instruction. */ *retval = riscv_set_register(target, GDB_REGNO_PC, pc + 4); if (*retval != ERROR_OK) - return SEMI_ERROR; + return SEMIHOSTING_ERROR; /* * Resume target if we are not waiting on a fileio * operation to complete. */ if (semihosting->is_resumable && !semihosting->hit_fileio) { - LOG_DEBUG(" -> HANDLED"); - return SEMI_HANDLED; + LOG_TARGET_DEBUG(target, " -> HANDLED"); + return SEMIHOSTING_HANDLED; } - LOG_DEBUG(" -> WAITING"); - return SEMI_WAITING; + LOG_TARGET_DEBUG(target, " -> WAITING"); + return SEMIHOSTING_WAITING; } /* ------------------------------------------------------------------------- @@ -182,7 +166,7 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval) */ static int riscv_semihosting_setup(struct target *target, int enable) { - LOG_DEBUG("[%s] enable=%d", target_name(target), enable); + LOG_TARGET_DEBUG(target, "enable=%d", enable); struct semihosting *semihosting = target->semihosting; if (semihosting) @@ -199,7 +183,7 @@ static int riscv_semihosting_post_result(struct target *target) return 0; } - LOG_DEBUG("0x%" PRIx64, semihosting->result); + LOG_TARGET_DEBUG(target, "Result: 0x%" PRIx64, semihosting->result); riscv_set_register(target, GDB_REGNO_A0, semihosting->result); return 0; } diff --git a/src/target/rtt.c b/src/target/rtt.c index 41830213d7..5ce049ae18 100644 --- a/src/target/rtt.c +++ b/src/target/rtt.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de> - * - * 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/>. */ #ifdef HAVE_CONFIG_H @@ -25,6 +14,7 @@ #include <helper/binarybuffer.h> #include <helper/command.h> #include <rtt/rtt.h> +#include <target/rtt.h> #include "target.h" @@ -252,43 +242,37 @@ int target_rtt_find_control_block(struct target *target, target_addr_t *address, size_t size, const char *id, bool *found, void *user_data) { + target_addr_t address_end = *address + size; uint8_t buf[1024]; *found = false; - size_t j = 0; - size_t cb_offset = 0; + size_t id_matched_length = 0; const size_t id_length = strlen(id); LOG_INFO("rtt: Searching for control block '%s'", id); - for (target_addr_t addr = 0; addr < size; addr = addr + sizeof(buf)) { + for (target_addr_t addr = *address; addr < address_end; addr += sizeof(buf)) { int ret; - const size_t buf_size = MIN(sizeof(buf), size - addr); - ret = target_read_buffer(target, *address + addr, buf_size, buf); + const size_t buf_size = MIN(sizeof(buf), address_end - addr); + ret = target_read_buffer(target, addr, buf_size, buf); if (ret != ERROR_OK) return ret; - size_t start = 0; - size_t i = 0; - - while (i < buf_size) { - if (buf[i] != id[j]) { - start++; - cb_offset++; - i = start; - j = 0; - - continue; + for (size_t buf_off = 0; buf_off < buf_size; buf_off++) { + if (id_matched_length > 0 && + buf[buf_off] != id[id_matched_length]) { + /* Start from beginning */ + id_matched_length = 0; } - i++; - j++; + if (buf[buf_off] == id[id_matched_length]) + id_matched_length++; - if (j == id_length) { - *address = *address + cb_offset; + if (id_matched_length == id_length) { + *address = addr + buf_off + 1 - id_length; *found = true; return ERROR_OK; } diff --git a/src/target/rtt.h b/src/target/rtt.h index 01224750f8..f3acda5468 100644 --- a/src/target/rtt.h +++ b/src/target/rtt.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Copyright (C) 2016-2020 by Marc Schink <dev@zapb.de> - * - * 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/>. */ #ifndef OPENOCD_TARGET_RTT_H diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index bc1f417ef0..f7acc6092d 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2018 by Liviu Ionescu * * <ilg@livius.net> * @@ -10,19 +12,6 @@ * * * Copyright (C) 2016 by Square, Inc. * * Steven Stallion <stallion@squareup.com> * - * * - * 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/>. * ***************************************************************************/ /** @@ -50,6 +39,7 @@ #include <helper/binarybuffer.h> #include <helper/log.h> +#include <server/gdb_server.h> #include <sys/stat.h> /** @@ -103,19 +93,6 @@ static int semihosting_common_fileio_info(struct target *target, static int semihosting_common_fileio_end(struct target *target, int result, int fileio_errno, bool ctrl_c); -static int semihosting_read_fields(struct target *target, size_t number, - uint8_t *fields); -static int semihosting_write_fields(struct target *target, size_t number, - uint8_t *fields); -static uint64_t semihosting_get_field(struct target *target, size_t index, - uint8_t *fields); -static void semihosting_set_field(struct target *target, uint64_t value, - size_t index, - uint8_t *fields); - -/* Attempts to include gdb_server.h failed. */ -extern int gdb_actual_connections; - /** * Initialize common semihosting support. * @@ -159,12 +136,14 @@ int semihosting_common_init(struct target *target, void *setup, semihosting->result = -1; semihosting->sys_errno = -1; semihosting->cmdline = NULL; + semihosting->basedir = NULL; /* If possible, update it in setup(). */ semihosting->setup_time = clock(); semihosting->setup = setup; semihosting->post_result = post_result; + semihosting->user_command_extension = NULL; target->semihosting = semihosting; @@ -244,7 +223,10 @@ static ssize_t semihosting_write(struct semihosting *semihosting, int fd, void * return semihosting_redirect_write(semihosting, buf, size); /* default write */ - return write(fd, buf, size); + int result = write(fd, buf, size); + if (result == -1) + semihosting->sys_errno = errno; + return result; } static ssize_t semihosting_redirect_read(struct semihosting *semihosting, void *buf, int size) @@ -289,7 +271,8 @@ static inline ssize_t semihosting_read(struct semihosting *semihosting, int fd, /* default read */ ssize_t result = read(fd, buf, size); - semihosting->sys_errno = errno; + if (result == -1) + semihosting->sys_errno = errno; return result; } @@ -315,6 +298,66 @@ static inline int semihosting_getchar(struct semihosting *semihosting, int fd) */ static char *semihosting_user_op_params; +const char *semihosting_opcode_to_str(const uint64_t opcode) +{ + switch (opcode) { + case SEMIHOSTING_SYS_CLOSE: + return "CLOSE"; + case SEMIHOSTING_SYS_CLOCK: + return "CLOCK"; + case SEMIHOSTING_SYS_ELAPSED: + return "ELAPSED"; + case SEMIHOSTING_SYS_ERRNO: + return "ERRNO"; + case SEMIHOSTING_SYS_EXIT: + return "EXIT"; + case SEMIHOSTING_SYS_EXIT_EXTENDED: + return "EXIT_EXTENDED"; + case SEMIHOSTING_SYS_FLEN: + return "FLEN"; + case SEMIHOSTING_SYS_GET_CMDLINE: + return "GET_CMDLINE"; + case SEMIHOSTING_SYS_HEAPINFO: + return "HEAPINFO"; + case SEMIHOSTING_SYS_ISERROR: + return "ISERROR"; + case SEMIHOSTING_SYS_ISTTY: + return "ISTTY"; + case SEMIHOSTING_SYS_OPEN: + return "OPEN"; + case SEMIHOSTING_SYS_READ: + return "READ"; + case SEMIHOSTING_SYS_READC: + return "READC"; + case SEMIHOSTING_SYS_REMOVE: + return "REMOVE"; + case SEMIHOSTING_SYS_RENAME: + return "RENAME"; + case SEMIHOSTING_SYS_SEEK: + return "SEEK"; + case SEMIHOSTING_SYS_SYSTEM: + return "SYSTEM"; + case SEMIHOSTING_SYS_TICKFREQ: + return "TICKFREQ"; + case SEMIHOSTING_SYS_TIME: + return "TIME"; + case SEMIHOSTING_SYS_TMPNAM: + return "TMPNAM"; + case SEMIHOSTING_SYS_WRITE: + return "WRITE"; + case SEMIHOSTING_SYS_WRITEC: + return "WRITEC"; + case SEMIHOSTING_SYS_WRITE0: + return "WRITE0"; + case SEMIHOSTING_USER_CMD_0X100 ... SEMIHOSTING_USER_CMD_0X1FF: + return "USER_CMD"; + case SEMIHOSTING_ARM_RESERVED_START ... SEMIHOSTING_ARM_RESERVED_END: + return "ARM_RESERVED_CMD"; + default: + return "<unknown>"; + } +} + /** * Portable implementation of ARM semihosting calls. * Performs the currently pending semihosting operation @@ -344,8 +387,9 @@ int semihosting_common(struct target *target) /* Enough space to hold 4 long words. */ uint8_t fields[4*8]; - LOG_DEBUG("op=0x%x, param=0x%" PRIx64, semihosting->op, - semihosting->param); + LOG_DEBUG("op=0x%x (%s), param=0x%" PRIx64, semihosting->op, + semihosting_opcode_to_str(semihosting->op), + semihosting->param); switch (semihosting->op) { @@ -409,12 +453,7 @@ int semihosting_common(struct target *target) (fd == 0) ? "stdin" : (fd == 1) ? "stdout" : "stderr"); /* Just pretend success */ - if (semihosting->is_fileio) { - semihosting->result = 0; - } else { - semihosting->result = 0; - semihosting->sys_errno = 0; - } + semihosting->result = 0; break; } /* Close the descriptor */ @@ -424,8 +463,9 @@ int semihosting_common(struct target *target) fileio_info->param_1 = fd; } else { semihosting->result = close(fd); - semihosting->sys_errno = errno; - LOG_DEBUG("close(%d)=%d", fd, (int)semihosting->result); + if (semihosting->result == -1) + semihosting->sys_errno = errno; + LOG_DEBUG("close(%d)=%" PRId64, fd, semihosting->result); } } break; @@ -512,7 +552,7 @@ int semihosting_common(struct target *target) int code = semihosting_get_field(target, 1, fields); if (type == ADP_STOPPED_APPLICATION_EXIT) { - if (!gdb_actual_connections) + if (!gdb_get_actual_connections()) exit(code); else { fprintf(stderr, @@ -527,7 +567,7 @@ int semihosting_common(struct target *target) } } else { if (semihosting->param == ADP_STOPPED_APPLICATION_EXIT) { - if (!gdb_actual_connections) + if (!gdb_get_actual_connections()) exit(0); else { fprintf(stderr, @@ -536,14 +576,14 @@ int semihosting_common(struct target *target) } else if (semihosting->param == ADP_STOPPED_RUN_TIME_ERROR) { /* Chosen more or less arbitrarily to have a nicer message, * otherwise all other return the same exit code 1. */ - if (!gdb_actual_connections) + if (!gdb_get_actual_connections()) exit(1); else { fprintf(stderr, "semihosting: *** application exited with error ***\n"); } } else { - if (!gdb_actual_connections) + if (!gdb_get_actual_connections()) exit(1); else { fprintf(stderr, @@ -603,7 +643,7 @@ int semihosting_common(struct target *target) int code = semihosting_get_field(target, 1, fields); if (type == ADP_STOPPED_APPLICATION_EXIT) { - if (!gdb_actual_connections) + if (!gdb_get_actual_connections()) exit(code); else { fprintf(stderr, @@ -650,10 +690,10 @@ int semihosting_common(struct target *target) semihosting->result = fstat(fd, &buf); if (semihosting->result == -1) { semihosting->sys_errno = errno; - LOG_DEBUG("fstat(%d)=%d", fd, (int)semihosting->result); + LOG_DEBUG("fstat(%d)=%" PRId64, fd, semihosting->result); break; } - LOG_DEBUG("fstat(%d)=%d", fd, (int)semihosting->result); + LOG_DEBUG("fstat(%d)=%" PRId64, fd, semihosting->result); semihosting->result = buf.st_size; } break; @@ -710,8 +750,7 @@ int semihosting_common(struct target *target) if (retval != ERROR_OK) return retval; } - LOG_DEBUG("SYS_GET_CMDLINE=[%s],%d", arg, - (int)semihosting->result); + LOG_DEBUG("SYS_GET_CMDLINE=[%s], %" PRId64, arg, semihosting->result); } break; @@ -801,9 +840,11 @@ int semihosting_common(struct target *target) if (retval != ERROR_OK) return retval; int fd = semihosting_get_field(target, 0, fields); - semihosting->result = isatty(fd); - semihosting->sys_errno = errno; - LOG_DEBUG("isatty(%d)=%d", fd, (int)semihosting->result); + // isatty() on Windows may return any non-zero value if fd is a terminal + semihosting->result = isatty(fd) ? 1 : 0; + if (semihosting->result == 0) + semihosting->sys_errno = errno; + LOG_DEBUG("isatty(%d)=%" PRId64, fd, semihosting->result); } break; @@ -870,17 +911,23 @@ int semihosting_common(struct target *target) semihosting->sys_errno = EINVAL; break; } - uint8_t *fn = malloc(len+1); + size_t basedir_len = semihosting->basedir ? strlen(semihosting->basedir) : 0; + uint8_t *fn = malloc(basedir_len + len + 2); if (!fn) { semihosting->result = -1; semihosting->sys_errno = ENOMEM; } else { - retval = target_read_memory(target, addr, 1, len, fn); + if (basedir_len > 0) { + strcpy((char *)fn, semihosting->basedir); + if (fn[basedir_len - 1] != '/') + fn[basedir_len++] = '/'; + } + retval = target_read_memory(target, addr, 1, len, fn + basedir_len); if (retval != ERROR_OK) { free(fn); return retval; } - fn[len] = 0; + fn[basedir_len + len] = 0; /* TODO: implement the :semihosting-features special file. * */ if (semihosting->is_fileio) { @@ -888,14 +935,16 @@ int semihosting_common(struct target *target) semihosting->result = -1; semihosting->sys_errno = EINVAL; } else if (strcmp((char *)fn, ":tt") == 0) { - if (mode == 0) + if (mode == 0) { semihosting->result = 0; - else if (mode == 4) + } else if (mode == 4) { semihosting->result = 1; - else if (mode == 8) + } else if (mode == 8) { semihosting->result = 2; - else + } else { semihosting->result = -1; + semihosting->sys_errno = EINVAL; + } } else { semihosting->hit_fileio = true; fileio_info->identifier = "open"; @@ -910,28 +959,23 @@ int semihosting_common(struct target *target) * - 0-3 ("r") for stdin, * - 4-7 ("w") for stdout, * - 8-11 ("a") for stderr */ + int fd; if (mode < 4) { - int fd = dup(STDIN_FILENO); - semihosting->result = fd; + fd = dup(STDIN_FILENO); semihosting->stdin_fd = fd; - semihosting->sys_errno = errno; - LOG_DEBUG("dup(STDIN)=%d", - (int)semihosting->result); + LOG_DEBUG("dup(STDIN)=%d", fd); } else if (mode < 8) { - int fd = dup(STDOUT_FILENO); - semihosting->result = fd; + fd = dup(STDOUT_FILENO); semihosting->stdout_fd = fd; - semihosting->sys_errno = errno; - LOG_DEBUG("dup(STDOUT)=%d", - (int)semihosting->result); + LOG_DEBUG("dup(STDOUT)=%d", fd); } else { - int fd = dup(STDERR_FILENO); - semihosting->result = fd; + fd = dup(STDERR_FILENO); semihosting->stderr_fd = fd; - semihosting->sys_errno = errno; - LOG_DEBUG("dup(STDERR)=%d", - (int)semihosting->result); + LOG_DEBUG("dup(STDERR)=%d", fd); } + semihosting->result = fd; + if (fd == -1) + semihosting->sys_errno = errno; } else { /* cygwin requires the permission setting * otherwise it will fail to reopen a previously @@ -939,9 +983,9 @@ int semihosting_common(struct target *target) semihosting->result = open((char *)fn, open_host_modeflags[mode], 0644); - semihosting->sys_errno = errno; - LOG_DEBUG("open('%s')=%d", fn, - (int)semihosting->result); + if (semihosting->result == -1) + semihosting->sys_errno = errno; + LOG_DEBUG("open('%s')=%" PRId64, fn, semihosting->result); } } free(fn); @@ -1004,11 +1048,11 @@ int semihosting_common(struct target *target) semihosting->sys_errno = ENOMEM; } else { semihosting->result = semihosting_read(semihosting, fd, buf, len); - LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%d", + LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%" PRId64, fd, addr, len, - (int)semihosting->result); + semihosting->result); if (semihosting->result >= 0) { retval = target_write_buffer(target, addr, semihosting->result, @@ -1044,7 +1088,7 @@ int semihosting_common(struct target *target) return ERROR_FAIL; } semihosting->result = semihosting_getchar(semihosting, semihosting->stdin_fd); - LOG_DEBUG("getchar()=%d", (int)semihosting->result); + LOG_DEBUG("getchar()=%" PRId64, semihosting->result); break; case SEMIHOSTING_SYS_REMOVE: /* 0x0E */ @@ -1089,9 +1133,9 @@ int semihosting_common(struct target *target) } fn[len] = 0; semihosting->result = remove((char *)fn); - semihosting->sys_errno = errno; - LOG_DEBUG("remove('%s')=%d", fn, - (int)semihosting->result); + if (semihosting->result == -1) + semihosting->sys_errno = errno; + LOG_DEBUG("remove('%s')=%" PRId64, fn, semihosting->result); free(fn); } @@ -1159,10 +1203,10 @@ int semihosting_common(struct target *target) fn2[len2] = 0; semihosting->result = rename((char *)fn1, (char *)fn2); - semihosting->sys_errno = errno; - LOG_DEBUG("rename('%s', '%s')=%d", fn1, fn2, - (int)semihosting->result); - + // rename() on Windows returns nonzero on error + if (semihosting->result != 0) + semihosting->sys_errno = errno; + LOG_DEBUG("rename('%s', '%s')=%" PRId64 " %d", fn1, fn2, semihosting->result, errno); free(fn1); free(fn2); } @@ -1206,9 +1250,9 @@ int semihosting_common(struct target *target) fileio_info->param_3 = SEEK_SET; } else { semihosting->result = lseek(fd, pos, SEEK_SET); - semihosting->sys_errno = errno; - LOG_DEBUG("lseek(%d, %d)=%d", fd, (int)pos, - (int)semihosting->result); + if (semihosting->result == -1) + semihosting->sys_errno = errno; + LOG_DEBUG("lseek(%d, %d)=%" PRId64, fd, (int)pos, semihosting->result); if (semihosting->result == pos) semihosting->result = 0; } @@ -1267,9 +1311,7 @@ int semihosting_common(struct target *target) cmd[len] = 0; semihosting->result = system( (const char *)cmd); - LOG_DEBUG("system('%s')=%d", - cmd, - (int)semihosting->result); + LOG_DEBUG("system('%s')=%" PRId64, cmd, semihosting->result); } free(cmd); @@ -1347,12 +1389,11 @@ int semihosting_common(struct target *target) return retval; } semihosting->result = semihosting_write(semihosting, fd, buf, len); - semihosting->sys_errno = errno; - LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%d", + LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%" PRId64, fd, addr, len, - (int)semihosting->result); + semihosting->result); if (semihosting->result >= 0) { /* The number of bytes that are NOT written. * */ @@ -1441,7 +1482,7 @@ int semihosting_common(struct target *target) } break; - case SEMIHOSTING_USER_CMD_0x100 ... SEMIHOSTING_USER_CMD_0x107: + case SEMIHOSTING_USER_CMD_0X100 ... SEMIHOSTING_USER_CMD_0X107: /** * This is a user defined operation (while user cmds 0x100-0x1ff * are possible, only 0x100-0x107 are currently implemented). @@ -1460,9 +1501,14 @@ int semihosting_common(struct target *target) * Return * On exit, the RETURN REGISTER contains the return status. */ - { - assert(!semihosting_user_op_params); + if (semihosting->user_command_extension) { + retval = semihosting->user_command_extension(target); + if (retval != ERROR_NOT_IMPLEMENTED) + break; + /* If custom user command not handled, we are looking for the TCL handler */ + } + assert(!semihosting_user_op_params); retval = semihosting_read_fields(target, 2, fields); if (retval != ERROR_OK) { LOG_ERROR("Failed to read fields for user defined command" @@ -1490,8 +1536,9 @@ int semihosting_common(struct target *target) retval = target_read_buffer(target, addr, len, (uint8_t *)(semihosting_user_op_params)); if (retval != ERROR_OK) { - LOG_ERROR("Failed to read from target, semihosting op=0x%x", - semihosting->op); + LOG_ERROR("Failed to read from target, semihosting op=0x%x (%s)", + semihosting->op, + semihosting_opcode_to_str(semihosting->op)); free(semihosting_user_op_params); semihosting_user_op_params = NULL; return retval; @@ -1500,11 +1547,8 @@ int semihosting_common(struct target *target) target_handle_event(target, semihosting->op); free(semihosting_user_op_params); semihosting_user_op_params = NULL; - semihosting->result = 0; break; - } - case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */ /* @@ -1632,7 +1676,6 @@ static int semihosting_common_fileio_end(struct target *target, int result, semihosting->hit_fileio = false; semihosting->result = result; - semihosting->sys_errno = fileio_errno; /* * Some fileio results do not match up with what the semihosting @@ -1641,17 +1684,11 @@ static int semihosting_common_fileio_end(struct target *target, int result, */ switch (semihosting->op) { case SEMIHOSTING_SYS_WRITE: /* 0x05 */ + case SEMIHOSTING_SYS_READ: /* 0x06 */ if (result < 0) - semihosting->result = fileio_info->param_3; + semihosting->result = fileio_info->param_3; /* Zero bytes read/written. */ else - semihosting->result = 0; - break; - - case SEMIHOSTING_SYS_READ: /* 0x06 */ - if (result == (int)fileio_info->param_3) - semihosting->result = 0; - if (result <= 0) - semihosting->result = fileio_info->param_3; + semihosting->result = (int64_t)fileio_info->param_3 - result; break; case SEMIHOSTING_SYS_SEEK: /* 0x0a */ @@ -1660,13 +1697,27 @@ static int semihosting_common_fileio_end(struct target *target, int result, break; } + bool fileio_failed = false; + if (semihosting->op == SEMIHOSTING_SYS_ISTTY) + fileio_failed = (semihosting->result == 0); + else if (semihosting->op == SEMIHOSTING_SYS_RENAME) + fileio_failed = (semihosting->result != 0); + else + fileio_failed = (semihosting->result == -1); + + if (fileio_failed) + semihosting->sys_errno = fileio_errno; + return semihosting->post_result(target); } +/* ------------------------------------------------------------------------- + * Utility functions. */ + /** * Read all fields of a command from target to buffer. */ -static int semihosting_read_fields(struct target *target, size_t number, +int semihosting_read_fields(struct target *target, size_t number, uint8_t *fields) { struct semihosting *semihosting = target->semihosting; @@ -1678,7 +1729,7 @@ static int semihosting_read_fields(struct target *target, size_t number, /** * Write all fields of a command from buffer to target. */ -static int semihosting_write_fields(struct target *target, size_t number, +int semihosting_write_fields(struct target *target, size_t number, uint8_t *fields) { struct semihosting *semihosting = target->semihosting; @@ -1690,7 +1741,7 @@ static int semihosting_write_fields(struct target *target, size_t number, /** * Extract a field from the buffer, considering register size and endianness. */ -static uint64_t semihosting_get_field(struct target *target, size_t index, +uint64_t semihosting_get_field(struct target *target, size_t index, uint8_t *fields) { struct semihosting *semihosting = target->semihosting; @@ -1703,7 +1754,7 @@ static uint64_t semihosting_get_field(struct target *target, size_t index, /** * Store a field in the buffer, considering register size and endianness. */ -static void semihosting_set_field(struct target *target, uint64_t value, +void semihosting_set_field(struct target *target, uint64_t value, size_t index, uint8_t *fields) { @@ -1827,7 +1878,7 @@ COMMAND_HANDLER(handle_common_semihosting_redirect_command) { struct target *target = get_current_target(CMD_CTX); - if (target == NULL) { + if (!target) { LOG_ERROR("No target selected"); return ERROR_FAIL; } @@ -2025,6 +2076,44 @@ COMMAND_HANDLER(handle_common_semihosting_read_user_param_command) return ERROR_OK; } +COMMAND_HANDLER(handle_common_semihosting_basedir_command) +{ + struct target *target = get_current_target(CMD_CTX); + + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!target) { + LOG_ERROR("No target selected"); + return ERROR_FAIL; + } + + struct semihosting *semihosting = target->semihosting; + if (!semihosting) { + command_print(CMD, "semihosting not supported for current target"); + return ERROR_FAIL; + } + + if (!semihosting->is_active) { + command_print(CMD, "semihosting not yet enabled for current target"); + return ERROR_FAIL; + } + + if (CMD_ARGC > 0) { + free(semihosting->basedir); + semihosting->basedir = strdup(CMD_ARGV[0]); + if (!semihosting->basedir) { + command_print(CMD, "semihosting failed to allocate memory for basedir!"); + return ERROR_FAIL; + } + } + + command_print(CMD, "semihosting base dir: %s", + semihosting->basedir ? semihosting->basedir : ""); + + return ERROR_OK; +} + const struct command_registration semihosting_common_handlers[] = { { .name = "semihosting", @@ -2068,5 +2157,12 @@ const struct command_registration semihosting_common_handlers[] = { .usage = "", .help = "read parameters in semihosting-user-cmd-0x10X callbacks", }, + { + .name = "semihosting_basedir", + .handler = handle_common_semihosting_basedir_command, + .mode = COMMAND_EXEC, + .usage = "[dir]", + .help = "set the base directory for semihosting I/O operations", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/semihosting_common.h b/src/target/semihosting_common.h index 459faf656a..a1848b4881 100644 --- a/src/target/semihosting_common.h +++ b/src/target/semihosting_common.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2018 by Liviu Ionescu * * <ilg@livius.net> * * * * Copyright (C) 2009 by Marvell Technology Group Ltd. * * Written by Nicolas Pitre <nico@marvell.com> * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_SEMIHOSTING_COMMON_H @@ -76,9 +65,11 @@ enum semihosting_operation_numbers { SEMIHOSTING_SYS_WRITE = 0x05, SEMIHOSTING_SYS_WRITEC = 0x03, SEMIHOSTING_SYS_WRITE0 = 0x04, - SEMIHOSTING_USER_CMD_0x100 = 0x100, /* First user cmd op code */ - SEMIHOSTING_USER_CMD_0x107 = 0x107, /* Last supported user cmd op code */ - SEMIHOSTING_USER_CMD_0x1FF = 0x1FF, /* Last user cmd op code */ + SEMIHOSTING_ARM_RESERVED_START = 0x32, + SEMIHOSTING_ARM_RESERVED_END = 0xFF, + SEMIHOSTING_USER_CMD_0X100 = 0x100, /* First user cmd op code */ + SEMIHOSTING_USER_CMD_0X107 = 0x107, /* Last supported user cmd op code */ + SEMIHOSTING_USER_CMD_0X1FF = 0x1FF, /* Last user cmd op code */ }; /** Maximum allowed Tcl command segment length in bytes*/ @@ -103,6 +94,13 @@ enum semihosting_redirect_config { SEMIHOSTING_REDIRECT_CFG_ALL, }; +enum semihosting_result { + SEMIHOSTING_NONE, /* Not halted for a semihosting call. */ + SEMIHOSTING_HANDLED, /* Call handled, and target was resumed. */ + SEMIHOSTING_WAITING, /* Call handled, target is halted waiting until we can resume. */ + SEMIHOSTING_ERROR /* Something went wrong. */ +}; + struct target; /* @@ -176,12 +174,42 @@ struct semihosting { /** The current time when 'execution starts' */ clock_t setup_time; + /** Base directory for semihosting I/O operations. */ + char *basedir; + + /** + * Target's extension of semihosting user commands. + * @returns ERROR_NOT_IMPLEMENTED when user command is not handled, otherwise + * sets semihosting->result and semihosting->sys_errno and returns ERROR_OK. + */ + int (*user_command_extension)(struct target *target); + int (*setup)(struct target *target, int enable); int (*post_result)(struct target *target); }; +/** + * @brief Convert the syscall opcode to a human-readable string + * @param[in] opcode Syscall opcode + * @return String representation of syscall opcode + */ +const char *semihosting_opcode_to_str(uint64_t opcode); + int semihosting_common_init(struct target *target, void *setup, void *post_result); int semihosting_common(struct target *target); +/* utility functions which may also be used by semihosting extensions (custom vendor-defined syscalls) */ +int semihosting_read_fields(struct target *target, size_t number, + uint8_t *fields); +int semihosting_write_fields(struct target *target, size_t number, + uint8_t *fields); +uint64_t semihosting_get_field(struct target *target, size_t index, + uint8_t *fields); +void semihosting_set_field(struct target *target, uint64_t value, + size_t index, + uint8_t *fields); + +extern const struct command_registration semihosting_common_handlers[]; + #endif /* OPENOCD_TARGET_SEMIHOSTING_COMMON_H */ diff --git a/src/target/smp.c b/src/target/smp.c index 3e1ded8bc3..50b19d01a0 100644 --- a/src/target/smp.c +++ b/src/target/smp.c @@ -1,19 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * * * Copyright (C) ST-Ericsson SA 2011 * * Author: Michel Jaouen <michel.jaouen@stericsson.com> for ST-Ericsson. * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -28,6 +18,7 @@ #include "smp.h" #include "helper/binarybuffer.h" +/* DEPRECATED: gdb_read_smp_packet/gdb_write_smp_packet to be removed */ /* implementation of new packet in gdb interface for smp feature */ /* */ /* j : smp status request */ @@ -53,11 +44,15 @@ /* maint packet jc */ /* packet j :smp status request */ +#define DEPRECATED_MSG "DEPRECATED: This method is deprecated in favor of the hwthread pseudo RTOS" int gdb_read_smp_packet(struct connection *connection, char const *packet, int packet_size) { struct target *target = get_target_from_connection(connection); int retval = ERROR_OK; + + LOG_WARNING(DEPRECATED_MSG); + if (target->smp) { if (strncmp(packet, "jc", 2) == 0) { const uint32_t len = sizeof(target->gdb_service->core[0]); @@ -83,6 +78,8 @@ int gdb_write_smp_packet(struct connection *connection, int coreid = 0; int retval = ERROR_OK; + LOG_WARNING(DEPRECATED_MSG); + /* skip command character */ if (target->smp) { if (strncmp(packet, "Jc", 2) == 0) { @@ -135,6 +132,9 @@ COMMAND_HANDLER(handle_smp_gdb_command) { struct target *target = get_current_target(CMD_CTX); int retval = ERROR_OK; + + LOG_WARNING(DEPRECATED_MSG); + if (!list_empty(target->smp_targets)) { if (CMD_ARGC == 1) { int coreid = 0; diff --git a/src/target/smp.h b/src/target/smp.h index 490a493105..20835a0522 100644 --- a/src/target/smp.h +++ b/src/target/smp.h @@ -1,19 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * * * Copyright (C) ST-Ericsson SA 2011 * * Author: Michel Jaouen <michel.jaouen@stericsson.com> for ST-Ericsson. * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_SMP_H @@ -30,8 +20,10 @@ extern const struct command_registration smp_command_handlers[]; +/* DEPRECATED */ int gdb_read_smp_packet(struct connection *connection, char const *packet, int packet_size); +/* DEPRECATED */ int gdb_write_smp_packet(struct connection *connection, char const *packet, int packet_size); diff --git a/src/target/startup.tcl b/src/target/startup.tcl index 0e46992b74..75e0edc77d 100644 --- a/src/target/startup.tcl +++ b/src/target/startup.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Defines basic Tcl procs for OpenOCD target module proc new_target_name { } { @@ -112,10 +114,21 @@ proc ocd_process_reset_inner { MODE } { continue } - # don't wait for targets where examination is deferred - # they can not be halted anyway at this point - if { ![$t was_examined] && [$t examine_deferred] } { - continue + if { ![$t was_examined] } { + # don't wait for targets where examination is deferred + # they can not be halted anyway at this point + if { [$t examine_deferred] } { + continue + } + # try to re-examine or target state will be unknown + $t invoke-event examine-start + set err [catch "$t arp_examine allow-defer"] + if { $err } { + $t invoke-event examine-fail + return -code error [format "TARGET: %s - Not examined" $t] + } else { + $t invoke-event examine-end + } } # Wait up to 1 second for target to halt. Why 1sec? Cause @@ -206,31 +219,44 @@ proc init_target_events {} { proc init_board {} { } -proc mem2array {arrayname bitwidth address count {phys ""}} { - echo "DEPRECATED! use 'read_memory' not 'mem2array'" - - upvar $arrayname $arrayname - set $arrayname "" - set i 0 - - foreach elem [read_memory $address $bitwidth $count {*}$phys] { - set ${arrayname}($i) $elem - incr i - } -} - -proc array2mem {arrayname bitwidth address count {phys ""}} { - echo "DEPRECATED! use 'write_memory' not 'array2mem'" - - upvar $arrayname $arrayname - set data "" +lappend _telnet_autocomplete_skip _post_init_target_array_mem +proc _post_init_target_array_mem {} { + set targets [target names] + lappend targets "" - for {set i 0} {$i < $count} {incr i} { - lappend data [expr $${arrayname}($i)] + foreach t $targets { + if {$t != ""} { + set t "$t " + } + eval [format {lappend ::_telnet_autocomplete_skip "%smem2array"} $t] + eval [format {proc {%smem2array} {arrayname bitwidth address count {phys ""}} { + echo "DEPRECATED! use 'read_memory' not 'mem2array'" + + upvar $arrayname $arrayname + set $arrayname "" + set i 0 + + foreach elem [%sread_memory $address $bitwidth $count {*}$phys] { + set ${arrayname}($i) $elem + incr i + } + }} $t $t] + eval [format {lappend ::_telnet_autocomplete_skip "%sarray2mem"} $t] + eval [format {proc {%sarray2mem} {arrayname bitwidth address count {phys ""}} { + echo "DEPRECATED! use 'write_memory' not 'array2mem'" + + upvar $arrayname $arrayname + set data "" + + for {set i 0} {$i < $count} {incr i} { + lappend data [expr $${arrayname}($i)] + } + + %swrite_memory $address $bitwidth $data {*}$phys + }} $t $t] } - - write_memory $address $bitwidth $data {*}$phys } +lappend post_init_commands _post_init_target_array_mem # smp_on/smp_off were already DEPRECATED in v0.11.0 through http://openocd.zylin.com/4615 lappend _telnet_autocomplete_skip "aarch64 smp_on" diff --git a/src/target/stm8.c b/src/target/stm8.c index 4102082ffc..227101b6f0 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * OpenOCD STM8 target driver * Copyright (C) 2017 Ake Rehnman * ake.rehnman(at)gmail.com -* -* 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/>. */ #ifdef HAVE_CONFIG_H @@ -553,12 +542,12 @@ static int stm8_get_core_reg(struct reg *reg) int retval; struct stm8_core_reg *stm8_reg = reg->arch_info; struct target *target = stm8_reg->target; - struct stm8_common *stm8_target = target_to_stm8(target); + struct stm8_common *stm8 = target_to_stm8(target); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; - retval = stm8_target->read_core_reg(target, stm8_reg->num); + retval = stm8->read_core_reg(target, stm8_reg->num); return retval; } @@ -1005,7 +994,7 @@ static int stm8_resume(struct target *target, int current, handle_breakpoints, debug_execution); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1169,7 +1158,7 @@ static int stm8_write_core_reg(struct target *target, unsigned int num) return ERROR_OK; } -static const char *stm8_get_gdb_arch(struct target *target) +static const char *stm8_get_gdb_arch(const struct target *target) { return "stm8"; } @@ -1314,7 +1303,7 @@ static int stm8_step(struct target *target, int current, struct breakpoint *breakpoint = NULL; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1529,7 +1518,7 @@ static int stm8_remove_breakpoint(struct target *target, struct stm8_common *stm8 = target_to_stm8(target); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1665,7 +1654,7 @@ static int stm8_remove_watchpoint(struct target *target, struct stm8_common *stm8 = target_to_stm8(target); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1795,7 +1784,7 @@ static int stm8_checksum_memory(struct target *target, target_addr_t address, /* run to exit point. return error if exit point was not reached. */ static int stm8_run_and_wait(struct target *target, uint32_t entry_point, - int timeout_ms, uint32_t exit_point, struct stm8_common *stm8) + unsigned int timeout_ms, uint32_t exit_point, struct stm8_common *stm8) { uint32_t pc; int retval; @@ -1830,7 +1819,7 @@ static int stm8_run_and_wait(struct target *target, uint32_t entry_point, static int stm8_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, - target_addr_t exit_point, int timeout_ms, void *arch_info) + target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { struct stm8_common *stm8 = target_to_stm8(target); diff --git a/src/target/stm8.h b/src/target/stm8.h index b18ff58f99..55e1071aba 100644 --- a/src/target/stm8.h +++ b/src/target/stm8.h @@ -1,20 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * OpenOCD STM8 target driver * Copyright (C) 2017 Ake Rehnman * ake.rehnman(at)gmail.com -* -* 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/>. */ #ifndef OPENOCD_TARGET_STM8_H @@ -22,11 +11,12 @@ struct target; -#define STM8_COMMON_MAGIC 0x53544D38 +#define STM8_COMMON_MAGIC 0x53544D38U #define STM8_NUM_CORE_REGS 6 struct stm8_common { - uint32_t common_magic; + unsigned int common_magic; + void *arch_info; struct reg_cache *core_cache; uint32_t core_regs[STM8_NUM_CORE_REGS]; diff --git a/src/target/target.c b/src/target/target.c index a97474e84c..9458409f83 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -22,19 +24,6 @@ * * * Copyright (C) 2011 Andreas Fritiofson * * andreas.fritiofson@gmail.com * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -42,6 +31,7 @@ #endif #include <helper/align.h> +#include <helper/nvp.h> #include <helper/time_support.h> #include <jtag/jtag.h> #include <flash/nor/core.h> @@ -57,6 +47,7 @@ #include "transport/transport.h" #include "arm_cti.h" #include "smp.h" +#include "semihosting_common.h" /* default halt wait timeout (ms) */ #define DEFAULT_HALT_TIMEOUT 5000 @@ -65,55 +56,12 @@ static int target_read_buffer_default(struct target *target, target_addr_t addre uint32_t count, uint8_t *buffer); static int target_write_buffer_default(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer); -static int target_array2mem(Jim_Interp *interp, struct target *target, - int argc, Jim_Obj * const *argv); -static int target_mem2array(Jim_Interp *interp, struct target *target, - int argc, Jim_Obj * const *argv); static int target_register_user_commands(struct command_context *cmd_ctx); static int target_get_gdb_fileio_info_default(struct target *target, struct gdb_fileio_info *fileio_info); static int target_gdb_fileio_end_default(struct target *target, int retcode, int fileio_errno, bool ctrl_c); -/* targets */ -extern struct target_type arm7tdmi_target; -extern struct target_type arm720t_target; -extern struct target_type arm9tdmi_target; -extern struct target_type arm920t_target; -extern struct target_type arm966e_target; -extern struct target_type arm946e_target; -extern struct target_type arm926ejs_target; -extern struct target_type fa526_target; -extern struct target_type feroceon_target; -extern struct target_type dragonite_target; -extern struct target_type xscale_target; -extern struct target_type cortexm_target; -extern struct target_type cortexa_target; -extern struct target_type aarch64_target; -extern struct target_type cortexr4_target; -extern struct target_type arm11_target; -extern struct target_type ls1_sap_target; -extern struct target_type mips_m4k_target; -extern struct target_type mips_mips64_target; -extern struct target_type avr_target; -extern struct target_type dsp563xx_target; -extern struct target_type dsp5680xx_target; -extern struct target_type testee_target; -extern struct target_type avr32_ap7k_target; -extern struct target_type hla_target; -extern struct target_type nds32_v2_target; -extern struct target_type nds32_v3_target; -extern struct target_type nds32_v3m_target; -extern struct target_type or1k_target; -extern struct target_type quark_x10xx_target; -extern struct target_type quark_d20xx_target; -extern struct target_type stm8_target; -extern struct target_type riscv_target; -extern struct target_type mem_ap_target; -extern struct target_type esirisc_target; -extern struct target_type arcv2_target; -extern struct target_type vexriscv_target; - static struct target_type *target_types[] = { &arm7tdmi_target, &arm9tdmi_target, @@ -126,6 +74,7 @@ static struct target_type *target_types[] = { &feroceon_target, &dragonite_target, &xscale_target, + &xtensa_chip_target, &cortexm_target, &cortexa_target, &cortexr4_target, @@ -138,9 +87,9 @@ static struct target_type *target_types[] = { &testee_target, &avr32_ap7k_target, &hla_target, - &nds32_v2_target, - &nds32_v3_target, - &nds32_v3m_target, + &esp32_target, + &esp32s2_target, + &esp32s3_target, &or1k_target, &quark_x10xx_target, &quark_d20xx_target, @@ -150,6 +99,7 @@ static struct target_type *target_types[] = { &esirisc_target, &arcv2_target, &aarch64_target, + &armv8r_target, &mips_mips64_target, &vexriscv_target, NULL, @@ -164,7 +114,12 @@ static LIST_HEAD(target_trace_callback_list); static const unsigned int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL; static LIST_HEAD(empty_smp_targets); -static const struct jim_nvp nvp_assert[] = { +enum nvp_assert { + NVP_DEASSERT, + NVP_ASSERT, +}; + +static const struct nvp nvp_assert[] = { { .name = "assert", NVP_ASSERT }, { .name = "deassert", NVP_DEASSERT }, { .name = "T", NVP_ASSERT }, @@ -174,7 +129,7 @@ static const struct jim_nvp nvp_assert[] = { { .name = NULL, .value = -1 } }; -static const struct jim_nvp nvp_error_target[] = { +static const struct nvp nvp_error_target[] = { { .value = ERROR_TARGET_INVALID, .name = "err-invalid" }, { .value = ERROR_TARGET_INIT_FAILED, .name = "err-init-failed" }, { .value = ERROR_TARGET_TIMEOUT, .name = "err-timeout" }, @@ -191,9 +146,9 @@ static const struct jim_nvp nvp_error_target[] = { static const char *target_strerror_safe(int err) { - const struct jim_nvp *n; + const struct nvp *n; - n = jim_nvp_value2name_simple(nvp_error_target, err); + n = nvp_value2name(nvp_error_target, err); if (!n->name) return "unknown"; else @@ -240,28 +195,29 @@ static const struct jim_nvp nvp_target_event[] = { { .value = TARGET_EVENT_TRACE_CONFIG, .name = "trace-config" }, - { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x100, .name = "semihosting-user-cmd-0x100" }, - { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x101, .name = "semihosting-user-cmd-0x101" }, - { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x102, .name = "semihosting-user-cmd-0x102" }, - { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x103, .name = "semihosting-user-cmd-0x103" }, - { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x104, .name = "semihosting-user-cmd-0x104" }, - { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x105, .name = "semihosting-user-cmd-0x105" }, - { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x106, .name = "semihosting-user-cmd-0x106" }, - { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x107, .name = "semihosting-user-cmd-0x107" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X100, .name = "semihosting-user-cmd-0x100" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X101, .name = "semihosting-user-cmd-0x101" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X102, .name = "semihosting-user-cmd-0x102" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X103, .name = "semihosting-user-cmd-0x103" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X104, .name = "semihosting-user-cmd-0x104" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X105, .name = "semihosting-user-cmd-0x105" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X106, .name = "semihosting-user-cmd-0x106" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0X107, .name = "semihosting-user-cmd-0x107" }, { .name = NULL, .value = -1 } }; -static const struct jim_nvp nvp_target_state[] = { +static const struct nvp nvp_target_state[] = { { .name = "unknown", .value = TARGET_UNKNOWN }, { .name = "running", .value = TARGET_RUNNING }, { .name = "halted", .value = TARGET_HALTED }, { .name = "reset", .value = TARGET_RESET }, { .name = "debug-running", .value = TARGET_DEBUG_RUNNING }, + { .name = "unavailable", .value = TARGET_UNAVAILABLE }, { .name = NULL, .value = -1 }, }; -static const struct jim_nvp nvp_target_debug_reason[] = { +static const struct nvp nvp_target_debug_reason[] = { { .name = "debug-request", .value = DBG_REASON_DBGRQ }, { .name = "breakpoint", .value = DBG_REASON_BREAKPOINT }, { .name = "watchpoint", .value = DBG_REASON_WATCHPOINT }, @@ -282,7 +238,7 @@ static const struct jim_nvp nvp_target_endian[] = { { .name = NULL, .value = -1 }, }; -static const struct jim_nvp nvp_reset_modes[] = { +static const struct nvp nvp_reset_modes[] = { { .name = "unknown", .value = RESET_UNKNOWN }, { .name = "run", .value = RESET_RUN }, { .name = "halt", .value = RESET_HALT }, @@ -290,11 +246,11 @@ static const struct jim_nvp nvp_reset_modes[] = { { .name = NULL, .value = -1 }, }; -const char *debug_reason_name(struct target *t) +const char *debug_reason_name(const struct target *t) { const char *cp; - cp = jim_nvp_value2name_simple(nvp_target_debug_reason, + cp = nvp_value2name(nvp_target_debug_reason, t->debug_reason)->name; if (!cp) { LOG_ERROR("Invalid debug reason: %d", (int)(t->debug_reason)); @@ -303,10 +259,10 @@ const char *debug_reason_name(struct target *t) return cp; } -const char *target_state_name(struct target *t) +const char *target_state_name(const struct target *t) { const char *cp; - cp = jim_nvp_value2name_simple(nvp_target_state, t->state)->name; + cp = nvp_value2name(nvp_target_state, t->state)->name; if (!cp) { LOG_ERROR("Invalid target state: %d", (int)(t->state)); cp = "(*BUG*unknown*BUG*)"; @@ -332,7 +288,7 @@ const char *target_event_name(enum target_event event) const char *target_reset_mode_name(enum target_reset_mode reset_mode) { const char *cp; - cp = jim_nvp_value2name_simple(nvp_reset_modes, reset_mode)->name; + cp = nvp_value2name(nvp_reset_modes, reset_mode)->name; if (!cp) { LOG_ERROR("Invalid target reset mode: %d", (int)(reset_mode)); cp = "(*BUG*unknown*BUG*)"; @@ -340,23 +296,6 @@ const char *target_reset_mode_name(enum target_reset_mode reset_mode) return cp; } -/* determine the number of the new target */ -static int new_target_number(void) -{ - struct target *t; - int x; - - /* number is 0 based */ - x = -1; - t = all_targets; - while (t) { - if (x < t->target_number) - x = t->target_number; - t = t->next; - } - return x + 1; -} - static void append_to_list_all_targets(struct target *target) { struct target **t = &all_targets; @@ -492,7 +431,7 @@ void target_buffer_set_u16_array(struct target *target, uint8_t *buffer, uint32_ target_buffer_set_u16(target, &buffer[i * 2], srcbuf[i]); } -/* return a pointer to a configured target; id is name or number */ +/* return a pointer to a configured target; id is name or index in all_targets */ struct target *get_target(const char *id) { struct target *target; @@ -505,36 +444,17 @@ struct target *get_target(const char *id) return target; } - /* It's OK to remove this fallback sometime after August 2010 or so */ - - /* no match, try as number */ - unsigned num; - if (parse_uint(id, &num) != ERROR_OK) + /* try as index */ + unsigned int index, counter; + if (parse_uint(id, &index) != ERROR_OK) return NULL; - for (target = all_targets; target; target = target->next) { - if (target->target_number == (int)num) { - LOG_WARNING("use '%s' as target identifier, not '%u'", - target_name(target), num); - return target; - } - } - - return NULL; -} - -/* returns a pointer to the n-th configured target */ -struct target *get_target_by_num(int num) -{ - struct target *target = all_targets; - - while (target) { - if (target->target_number == num) - return target; - target = target->next; - } + for (target = all_targets, counter = index; + target && counter; + target = target->next, --counter) + ; - return NULL; + return target; } struct target *get_current_target(struct command_context *cmd_ctx) @@ -660,10 +580,10 @@ int target_resume(struct target *target, int current, target_addr_t address, * Disable polling during resume() to guarantee the execution of handlers * in the correct order. */ - bool save_poll = jtag_poll_get_enabled(); - jtag_poll_set_enabled(false); + bool save_poll_mask = jtag_poll_mask(); retval = target->type->resume(target, current, address, handle_breakpoints, debug_execution); - jtag_poll_set_enabled(save_poll); + jtag_poll_unmask(save_poll_mask); + if (retval != ERROR_OK) return retval; @@ -676,8 +596,8 @@ static int target_process_reset(struct command_invocation *cmd, enum target_rese { char buf[100]; int retval; - struct jim_nvp *n; - n = jim_nvp_value2name_simple(nvp_reset_modes, reset_mode); + const struct nvp *n; + n = nvp_value2name(nvp_reset_modes, reset_mode); if (!n->name) { LOG_ERROR("invalid reset mode"); return ERROR_FAIL; @@ -691,14 +611,12 @@ static int target_process_reset(struct command_invocation *cmd, enum target_rese * more predictable, i.e. dr/irscan & pathmove in events will * not have JTAG operations injected into the middle of a sequence. */ - bool save_poll = jtag_poll_get_enabled(); - - jtag_poll_set_enabled(false); + bool save_poll_mask = jtag_poll_mask(); sprintf(buf, "ocd_process_reset %s", n->name); retval = Jim_Eval(cmd->ctx->interp, buf); - jtag_poll_set_enabled(save_poll); + jtag_poll_unmask(save_poll_mask); if (retval != JIM_OK) { Jim_MakeErrorMessage(cmd->ctx->interp); @@ -755,10 +673,14 @@ static int default_check_reset(struct target *target) * Keep in sync */ int target_examine_one(struct target *target) { + LOG_TARGET_DEBUG(target, "Examination started"); + target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START); int retval = target->type->examine(target); if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "Examination failed"); + LOG_TARGET_DEBUG(target, "examine() returned error code %d", retval); target_reset_examined(target); target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_FAIL); return retval; @@ -768,6 +690,7 @@ int target_examine_one(struct target *target) target_set_examined(target); target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END); + LOG_TARGET_INFO(target, "Examination succeed"); return ERROR_OK; } @@ -821,7 +744,7 @@ int target_examine(void) return retval; } -const char *target_type_name(struct target *target) +const char *target_type_name(const struct target *target) { return target->type->name; } @@ -862,7 +785,7 @@ int target_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, target_addr_t entry_point, target_addr_t exit_point, - int timeout_ms, void *arch_info) + unsigned int timeout_ms, void *arch_info) { int retval = ERROR_FAIL; @@ -946,7 +869,7 @@ int target_start_algorithm(struct target *target, int target_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - target_addr_t exit_point, int timeout_ms, + target_addr_t exit_point, unsigned int timeout_ms, void *arch_info) { int retval = ERROR_FAIL; @@ -1378,7 +1301,7 @@ int target_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { if ((target->state != TARGET_HALTED) && (breakpoint->type != BKPT_HARD)) { - LOG_WARNING("target %s is not halted (add breakpoint)", target_name(target)); + LOG_TARGET_ERROR(target, "not halted (add breakpoint)"); return ERROR_TARGET_NOT_HALTED; } return target->type->add_breakpoint(target, breakpoint); @@ -1388,7 +1311,7 @@ int target_add_context_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted (add context breakpoint)", target_name(target)); + LOG_TARGET_ERROR(target, "not halted (add context breakpoint)"); return ERROR_TARGET_NOT_HALTED; } return target->type->add_context_breakpoint(target, breakpoint); @@ -1398,7 +1321,7 @@ int target_add_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted (add hybrid breakpoint)", target_name(target)); + LOG_TARGET_ERROR(target, "not halted (add hybrid breakpoint)"); return ERROR_TARGET_NOT_HALTED; } return target->type->add_hybrid_breakpoint(target, breakpoint); @@ -1414,7 +1337,7 @@ int target_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted (add watchpoint)", target_name(target)); + LOG_TARGET_ERROR(target, "not halted (add watchpoint)"); return ERROR_TARGET_NOT_HALTED; } return target->type->add_watchpoint(target, watchpoint); @@ -1428,7 +1351,7 @@ int target_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted (hit watchpoint)", target->cmd_name); + LOG_TARGET_ERROR(target, "not halted (hit watchpoint)"); return ERROR_TARGET_NOT_HALTED; } @@ -1442,7 +1365,7 @@ int target_hit_watchpoint(struct target *target, return target->type->hit_watchpoint(target, hit_watchpoint); } -const char *target_get_gdb_arch(struct target *target) +const char *target_get_gdb_arch(const struct target *target) { if (!target->type->get_gdb_arch) return NULL; @@ -1482,7 +1405,7 @@ int target_get_gdb_reg_list_noread(struct target *target, return target_get_gdb_reg_list(target, reg_list, reg_list_size, reg_class); } -bool target_supports_gdb_connection(struct target *target) +bool target_supports_gdb_connection(const struct target *target) { /* * exclude all the targets that don't provide get_gdb_reg_list @@ -1510,7 +1433,7 @@ int target_step(struct target *target, int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted (gdb fileio)", target->cmd_name); + LOG_TARGET_ERROR(target, "not halted (gdb fileio)"); return ERROR_TARGET_NOT_HALTED; } return target->type->get_gdb_fileio_info(target, fileio_info); @@ -1519,7 +1442,7 @@ int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fi int target_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted (gdb fileio end)", target->cmd_name); + LOG_TARGET_ERROR(target, "not halted (gdb fileio end)"); return ERROR_TARGET_NOT_HALTED; } return target->type->gdb_fileio_end(target, retcode, fileio_errno, ctrl_c); @@ -1875,7 +1798,7 @@ int target_call_reset_callbacks(struct target *target, enum target_reset_mode re struct target_reset_callback *callback; LOG_DEBUG("target reset %i (%s)", reset_mode, - jim_nvp_value2name_simple(nvp_reset_modes, reset_mode)->name); + nvp_value2name(nvp_reset_modes, reset_mode)->name); list_for_each_entry(callback, &target_reset_callback_list, list) callback->callback(target, reset_mode, callback->priv); @@ -1959,13 +1882,13 @@ static int target_call_timer_callbacks_check_time(int checktime) return ERROR_OK; } -int target_call_timer_callbacks() +int target_call_timer_callbacks(void) { return target_call_timer_callbacks_check_time(1); } /* invoke periodic callbacks immediately */ -int target_call_timer_callbacks_now() +int target_call_timer_callbacks_now(void) { return target_call_timer_callbacks_check_time(0); } @@ -2086,7 +2009,7 @@ int target_alloc_working_area_try(struct target *target, uint32_t size, struct w struct working_area *new_wa = malloc(sizeof(*new_wa)); if (new_wa) { new_wa->next = NULL; - new_wa->size = target->working_area_size & ~3UL; /* 4-byte align */ + new_wa->size = ALIGN_DOWN(target->working_area_size, 4); /* 4-byte align */ new_wa->address = target->working_area; new_wa->backup = NULL; new_wa->user = NULL; @@ -2097,8 +2020,7 @@ int target_alloc_working_area_try(struct target *target, uint32_t size, struct w } /* only allocate multiples of 4 byte */ - if (size % 4) - size = (size + 3) & (~3UL); + size = ALIGN_UP(size, 4); struct working_area *c = target->working_areas; @@ -2252,7 +2174,7 @@ uint32_t target_get_working_area_avail(struct target *target) uint32_t max_size = 0; if (!c) - return target->working_area_size; + return ALIGN_DOWN(target->working_area_size, 4); while (c) { if (c->free && max_size < c->size) @@ -2266,9 +2188,14 @@ uint32_t target_get_working_area_avail(struct target *target) static void target_destroy(struct target *target) { + breakpoint_remove_all(target); + watchpoint_remove_all(target); + if (target->type->deinit_target) target->type->deinit_target(target); + if (target->semihosting) + free(target->semihosting->basedir); free(target->semihosting); jtag_unregister_event_callback(jtag_enable_callback, target); @@ -2598,7 +2525,7 @@ int target_blank_check_memory(struct target *target, } if (!target->type->blank_check_memory) - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + return ERROR_NOT_IMPLEMENTED; return target->type->blank_check_memory(target, blocks, num_blocks, erased_value); } @@ -2892,10 +2819,10 @@ COMMAND_HANDLER(handle_targets_command) } } - struct target *target = all_targets; + unsigned int index = 0; command_print(CMD, " TargetName Type Endian TapName State "); command_print(CMD, "-- ------------------ ---------- ------ ------------------ ------------"); - while (target) { + for (struct target *target = all_targets; target; target = target->next, ++index) { const char *state; char marker = ' '; @@ -2910,7 +2837,7 @@ COMMAND_HANDLER(handle_targets_command) /* keep columns lined up to match the headers above */ command_print(CMD, "%2d%c %-18s %-10s %-6s %-18s %s", - target->target_number, + index, marker, target_name(target), target_type_name(target), @@ -2918,7 +2845,6 @@ COMMAND_HANDLER(handle_targets_command) target->endianness)->name, target->tap->dotted_name, state); - target = target->next; } return retval; @@ -3065,9 +2991,12 @@ static int handle_target(void *priv) /* Increase interval between polling up to 5000ms */ target->backoff.interval = MAX(polling_interval, MIN(target->backoff.interval * 2 + 1, 5000)); - /* Tell GDB to halt the debugger. This allows the user to run - * monitor commands to handle the situation. */ - target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); + /* Do *not* tell gdb the target halted. This might just + * be a hiccup. We have no reason to believe the target + * is halted, and if it is running while gdb thinks it's + * halted things just get unnecessarily confused. gdb + * users can hit ^C if the need to interact with the + * target. */ } target->backoff.next_attempt = timeval_ms() + target->backoff.interval; LOG_TARGET_DEBUG(target, "target_poll() -> %d, next attempt in %dms", @@ -3077,8 +3006,7 @@ static int handle_target(void *priv) target_reset_examined(target); retval = target_examine_one(target); if (retval != ERROR_OK) { - LOG_TARGET_DEBUG(target, "Examination failed, GDB will be halted. " - "Polling again in %dms", + LOG_TARGET_DEBUG(target, "Examination failed. Polling again in %dms", target->backoff.interval); return retval; } @@ -3093,6 +3021,10 @@ COMMAND_HANDLER(handle_reg_command) LOG_DEBUG("-"); struct target *target = get_current_target(CMD_CTX); + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } struct reg *reg = NULL; /* list all available registers for the current target */ @@ -3111,23 +3043,21 @@ COMMAND_HANDLER(handle_reg_command) if (reg->exist == false || reg->hidden) continue; /* only print cached values if they are valid */ - if (reg->exist) { - if (reg->valid) { - char *value = buf_to_hex_str(reg->value, - reg->size); - command_print(CMD, - "(%i) %s (/%" PRIu32 "): 0x%s%s", - count, reg->name, - reg->size, value, - reg->dirty - ? " (dirty)" - : ""); - free(value); - } else { - command_print(CMD, "(%i) %s (/%" PRIu32 ")", - count, reg->name, - reg->size) ; - } + if (reg->valid) { + char *value = buf_to_hex_str(reg->value, + reg->size); + command_print(CMD, + "(%i) %s (/%" PRIu32 "): 0x%s%s", + count, reg->name, + reg->size, value, + reg->dirty + ? " (dirty)" + : ""); + free(value); + } else { + command_print(CMD, "(%i) %s (/%" PRIu32 ")", + count, reg->name, + reg->size); } } cache = cache->next; @@ -3159,7 +3089,7 @@ COMMAND_HANDLER(handle_reg_command) if (!reg) { command_print(CMD, "%i is out of bounds, the current target " "has only %i registers (0 - %i)", num, count, count - 1); - return ERROR_OK; + return ERROR_FAIL; } } else { /* access a single register by its name */ @@ -3178,13 +3108,13 @@ COMMAND_HANDLER(handle_reg_command) if ((CMD_ARGC == 1) || ((CMD_ARGC == 2) && !((CMD_ARGV[1][0] >= '0') && (CMD_ARGV[1][0] <= '9')))) { if ((CMD_ARGC == 2) && (strcmp(CMD_ARGV[1], "force") == 0)) - reg->valid = 0; + reg->valid = false; - if (reg->valid == 0) { + if (!reg->valid) { int retval = reg->type->get(reg); if (retval != ERROR_OK) { - LOG_DEBUG("Couldn't get register %s.", reg->name); - return retval; + LOG_ERROR("Could not read register '%s'", reg->name); + return retval; } } char *value = buf_to_hex_str(reg->value, reg->size); @@ -3218,7 +3148,7 @@ COMMAND_HANDLER(handle_reg_command) not_found: command_print(CMD, "register %s not found in current target", CMD_ARGV[0]); - return ERROR_OK; + return ERROR_FAIL; } COMMAND_HANDLER(handle_poll_command) @@ -3272,7 +3202,7 @@ COMMAND_HANDLER(handle_wait_halt_command) * * After 500ms, keep_alive() is invoked */ -int target_wait_state(struct target *target, enum target_state state, int ms) +int target_wait_state(struct target *target, enum target_state state, unsigned int ms) { int retval; int64_t then = 0, cur; @@ -3289,15 +3219,15 @@ int target_wait_state(struct target *target, enum target_state state, int ms) once = false; then = timeval_ms(); LOG_DEBUG("waiting for target %s...", - jim_nvp_value2name_simple(nvp_target_state, state)->name); + nvp_value2name(nvp_target_state, state)->name); } - if (cur-then > 500) + if (cur - then > 500) keep_alive(); if ((cur-then) > ms) { LOG_ERROR("timed out while waiting for target %s", - jim_nvp_value2name_simple(nvp_target_state, state)->name); + nvp_value2name(nvp_target_state, state)->name); return ERROR_FAIL; } } @@ -3333,7 +3263,7 @@ COMMAND_HANDLER(handle_soft_reset_halt_command) { struct target *target = get_current_target(CMD_CTX); - LOG_USER("requesting target halt and executing a soft reset"); + LOG_TARGET_INFO(target, "requesting target halt and executing a soft reset"); target_soft_reset_halt(target); @@ -3347,8 +3277,8 @@ COMMAND_HANDLER(handle_reset_command) enum target_reset_mode reset_mode = RESET_RUN; if (CMD_ARGC == 1) { - const struct jim_nvp *n; - n = jim_nvp_name2value_simple(nvp_reset_modes, CMD_ARGV[0]); + const struct nvp *n; + n = nvp_name2value(nvp_reset_modes, CMD_ARGV[0]); if ((!n->name) || (n->value == RESET_UNKNOWN)) return ERROR_COMMAND_SYNTAX_ERROR; reset_mode = n->value; @@ -3970,24 +3900,24 @@ static int handle_bp_command_list(struct command_invocation *cmd) if (breakpoint->type == BKPT_SOFT) { char *buf = buf_to_hex_str(breakpoint->orig_instr, breakpoint->length); - command_print(cmd, "IVA breakpoint: " TARGET_ADDR_FMT ", 0x%x, 0x%s", + command_print(cmd, "Software breakpoint(IVA): addr=" TARGET_ADDR_FMT ", len=0x%x, orig_instr=0x%s", breakpoint->address, breakpoint->length, buf); free(buf); } else { if ((breakpoint->address == 0) && (breakpoint->asid != 0)) - command_print(cmd, "Context breakpoint: 0x%8.8" PRIx32 ", 0x%x, %u", + command_print(cmd, "Context breakpoint: asid=0x%8.8" PRIx32 ", len=0x%x, num=%u", breakpoint->asid, breakpoint->length, breakpoint->number); else if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { - command_print(cmd, "Hybrid breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %u", + command_print(cmd, "Hybrid breakpoint(IVA): addr=" TARGET_ADDR_FMT ", len=0x%x, num=%u", breakpoint->address, breakpoint->length, breakpoint->number); command_print(cmd, "\t|--->linked with ContextID: 0x%8.8" PRIx32, breakpoint->asid); } else - command_print(cmd, "Breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %u", + command_print(cmd, "Hardware breakpoint(IVA): addr=" TARGET_ADDR_FMT ", len=0x%x, num=%u", breakpoint->address, breakpoint->length, breakpoint->number); } @@ -4011,7 +3941,7 @@ static int handle_bp_command_set(struct command_invocation *cmd, } else if (addr == 0) { if (!target->type->add_context_breakpoint) { - LOG_ERROR("Context breakpoint not available"); + LOG_TARGET_ERROR(target, "Context breakpoint not available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = context_breakpoint_add(target, asid, length, hw); @@ -4021,7 +3951,7 @@ static int handle_bp_command_set(struct command_invocation *cmd, } else { if (!target->type->add_hybrid_breakpoint) { - LOG_ERROR("Hybrid breakpoint not available"); + LOG_TARGET_ERROR(target, "Hybrid breakpoint not available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = hybrid_breakpoint_add(target, addr, asid, length, hw); @@ -4078,21 +4008,31 @@ COMMAND_HANDLER(handle_bp_command) COMMAND_HANDLER(handle_rbp_command) { + int retval; + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); if (!strcmp(CMD_ARGV[0], "all")) { - breakpoint_remove_all(target); + retval = breakpoint_remove_all(target); + + if (retval != ERROR_OK) { + command_print(CMD, "Error encountered during removal of all breakpoints."); + command_print(CMD, "Some breakpoints may have remained set."); + } } else { target_addr_t addr; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); - breakpoint_remove(target, addr); + retval = breakpoint_remove(target, addr); + + if (retval != ERROR_OK) + command_print(CMD, "Error during removal of breakpoint at address " TARGET_ADDR_FMT, addr); } - return ERROR_OK; + return retval; } COMMAND_HANDLER(handle_wp_command) @@ -4103,13 +4043,14 @@ COMMAND_HANDLER(handle_wp_command) struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { + char wp_type = (watchpoint->rw == WPT_READ ? 'r' : (watchpoint->rw == WPT_WRITE ? 'w' : 'a')); command_print(CMD, "address: " TARGET_ADDR_FMT ", len: 0x%8.8" PRIx32 - ", r/w/a: %i, value: 0x%8.8" PRIx32 - ", mask: 0x%8.8" PRIx32, + ", r/w/a: %c, value: 0x%8.8" PRIx64 + ", mask: 0x%8.8" PRIx64, watchpoint->address, watchpoint->length, - (int)watchpoint->rw, + wp_type, watchpoint->value, watchpoint->mask); watchpoint = watchpoint->next; @@ -4120,15 +4061,20 @@ COMMAND_HANDLER(handle_wp_command) enum watchpoint_rw type = WPT_ACCESS; target_addr_t addr = 0; uint32_t length = 0; - uint32_t data_value = 0x0; - uint32_t data_mask = 0xffffffff; + uint64_t data_value = 0x0; + uint64_t data_mask = WATCHPOINT_IGNORE_DATA_VALUE_MASK; + bool mask_specified = false; switch (CMD_ARGC) { case 5: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], data_mask); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[4], data_mask); + mask_specified = true; /* fall through */ case 4: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], data_value); + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[3], data_value); + // if user specified only data value without mask - the mask should be 0 + if (!mask_specified) + data_mask = 0; /* fall through */ case 3: switch (CMD_ARGV[2][0]) { @@ -4142,7 +4088,7 @@ COMMAND_HANDLER(handle_wp_command) type = WPT_ACCESS; break; default: - LOG_ERROR("invalid watchpoint mode ('%c')", CMD_ARGV[2][0]); + LOG_TARGET_ERROR(target, "invalid watchpoint mode ('%c')", CMD_ARGV[2][0]); return ERROR_COMMAND_SYNTAX_ERROR; } /* fall through */ @@ -4158,23 +4104,37 @@ COMMAND_HANDLER(handle_wp_command) int retval = watchpoint_add(target, addr, length, type, data_value, data_mask); if (retval != ERROR_OK) - LOG_ERROR("Failure setting watchpoints"); + LOG_TARGET_ERROR(target, "Failure setting watchpoints"); return retval; } COMMAND_HANDLER(handle_rwp_command) { + int retval; + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - target_addr_t addr; - COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); - struct target *target = get_current_target(CMD_CTX); - watchpoint_remove(target, addr); + if (!strcmp(CMD_ARGV[0], "all")) { + retval = watchpoint_remove_all(target); - return ERROR_OK; + if (retval != ERROR_OK) { + command_print(CMD, "Error encountered during removal of all watchpoints."); + command_print(CMD, "Some watchpoints may have remained set."); + } + } else { + target_addr_t addr; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); + + retval = watchpoint_remove(target, addr); + + if (retval != ERROR_OK) + command_print(CMD, "Error during removal of watchpoint at address " TARGET_ADDR_FMT, addr); + } + + return retval; } /** @@ -4257,11 +4217,19 @@ static void write_gmon(uint32_t *samples, uint32_t sample_num, const char *filen /* max should be (largest sample + 1) * Refer to binutils/gprof/hist.c (find_histogram_for_pc) */ - max++; + if (max < UINT32_MAX) + max++; + + /* gprof requires (max - min) >= 2 */ + while ((max - min) < 2) { + if (max < UINT32_MAX) + max++; + else + min--; + } } - int address_space = max - min; - assert(address_space >= 2); + uint32_t address_space = max - min; /* FIXME: What is the reasonable number of buckets? * The profiling result will be more accurate if there are enough buckets. */ @@ -4329,7 +4297,7 @@ COMMAND_HANDLER(handle_profile_command) if ((CMD_ARGC != 2) && (CMD_ARGC != 4)) return ERROR_COMMAND_SYNTAX_ERROR; - const uint32_t MAX_PROFILE_SAMPLE_NUM = 10000; + const uint32_t MAX_PROFILE_SAMPLE_NUM = 1000000; uint32_t offset; uint32_t num_of_samples; int retval = ERROR_OK; @@ -4337,6 +4305,19 @@ COMMAND_HANDLER(handle_profile_command) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], offset); + uint32_t start_address = 0; + uint32_t end_address = 0; + bool with_range = false; + if (CMD_ARGC == 4) { + with_range = true; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], start_address); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], end_address); + if (start_address > end_address || (end_address - start_address) < 2) { + command_print(CMD, "Error: end - start < 2"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } + uint32_t *samples = malloc(sizeof(uint32_t) * MAX_PROFILE_SAMPLE_NUM); if (!samples) { LOG_ERROR("No memory to store samples."); @@ -4389,15 +4370,6 @@ COMMAND_HANDLER(handle_profile_command) return retval; } - uint32_t start_address = 0; - uint32_t end_address = 0; - bool with_range = false; - if (CMD_ARGC == 4) { - with_range = true; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], start_address); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], end_address); - } - write_gmon(samples, num_of_samples, CMD_ARGV[1], with_range, start_address, end_address, target, duration_ms); command_print(CMD, "Wrote %s", CMD_ARGV[1]); @@ -4406,210 +4378,147 @@ COMMAND_HANDLER(handle_profile_command) return retval; } -static int new_u64_array_element(Jim_Interp *interp, const char *varname, int idx, uint64_t val) +COMMAND_HANDLER(handle_target_read_memory) { - char *namebuf; - Jim_Obj *obj_name, *obj_val; - int result; + /* + * CMD_ARGV[0] = memory address + * CMD_ARGV[1] = desired element width in bits + * CMD_ARGV[2] = number of elements to read + * CMD_ARGV[3] = optional "phys" + */ - namebuf = alloc_printf("%s(%d)", varname, idx); - if (!namebuf) - return JIM_ERR; + if (CMD_ARGC < 3 || CMD_ARGC > 4) + return ERROR_COMMAND_SYNTAX_ERROR; - obj_name = Jim_NewStringObj(interp, namebuf, -1); - jim_wide wide_val = val; - obj_val = Jim_NewWideObj(interp, wide_val); - if (!obj_name || !obj_val) { - free(namebuf); - return JIM_ERR; - } + /* Arg 1: Memory address. */ + target_addr_t addr; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], addr); - Jim_IncrRefCount(obj_name); - Jim_IncrRefCount(obj_val); - result = Jim_SetVariable(interp, obj_name, obj_val); - Jim_DecrRefCount(interp, obj_name); - Jim_DecrRefCount(interp, obj_val); - free(namebuf); - /* printf("%s(%d) <= 0%08x\n", varname, idx, val); */ - return result; -} + /* Arg 2: Bit width of one element. */ + unsigned int width_bits; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], width_bits); -static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv) -{ - int e; + /* Arg 3: Number of elements to read. */ + unsigned int count; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], count); - LOG_WARNING("DEPRECATED! use 'read_memory' not 'mem2array'"); + /* Arg 4: Optional 'phys'. */ + bool is_phys = false; + if (CMD_ARGC == 4) { + if (strcmp(CMD_ARGV[3], "phys")) { + command_print(CMD, "invalid argument '%s', must be 'phys'", CMD_ARGV[3]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } - /* argv[0] = name of array to receive the data - * argv[1] = desired element width in bits - * argv[2] = memory address - * argv[3] = count of times to read - * argv[4] = optional "phys" - */ - if (argc < 4 || argc > 5) { - Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]"); - return JIM_ERR; + is_phys = true; } - /* Arg 0: Name of the array variable */ - const char *varname = Jim_GetString(argv[0], NULL); - - /* Arg 1: Bit width of one element */ - long l; - e = Jim_GetLong(interp, argv[1], &l); - if (e != JIM_OK) - return e; - const unsigned int width_bits = l; - - if (width_bits != 8 && - width_bits != 16 && - width_bits != 32 && - width_bits != 64) { - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), - "Invalid width param. Must be one of: 8, 16, 32 or 64.", NULL); - return JIM_ERR; + switch (width_bits) { + case 8: + case 16: + case 32: + case 64: + break; + default: + command_print(CMD, "invalid width, must be 8, 16, 32 or 64"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - const unsigned int width = width_bits / 8; - - /* Arg 2: Memory address */ - jim_wide wide_addr; - e = Jim_GetWide(interp, argv[2], &wide_addr); - if (e != JIM_OK) - return e; - target_addr_t addr = (target_addr_t)wide_addr; - - /* Arg 3: Number of elements to read */ - e = Jim_GetLong(interp, argv[3], &l); - if (e != JIM_OK) - return e; - size_t len = l; - /* Arg 4: phys */ - bool is_phys = false; - if (argc > 4) { - int str_len = 0; - const char *phys = Jim_GetString(argv[4], &str_len); - if (!strncmp(phys, "phys", str_len)) - is_phys = true; - else - return JIM_ERR; - } + const unsigned int width = width_bits / 8; - /* Argument checks */ - if (len == 0) { - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: zero width read?", NULL); - return JIM_ERR; - } - if ((addr + (len * width)) < addr) { - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: addr + len - wraps to zero?", NULL); - return JIM_ERR; - } - if (len > 65536) { - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), - "mem2array: too large read request, exceeds 64K items", NULL); - return JIM_ERR; + if ((addr + (count * width)) < addr) { + command_print(CMD, "read_memory: addr + count wraps to zero"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - if ((width == 1) || - ((width == 2) && ((addr & 1) == 0)) || - ((width == 4) && ((addr & 3) == 0)) || - ((width == 8) && ((addr & 7) == 0))) { - /* alignment correct */ - } else { - char buf[100]; - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - sprintf(buf, "mem2array address: " TARGET_ADDR_FMT " is not aligned for %" PRIu32 " byte reads", - addr, - width); - Jim_AppendStrings(interp, Jim_GetResult(interp), buf, NULL); - return JIM_ERR; + if (count > 65536) { + command_print(CMD, "read_memory: too large read request, exceeds 64K elements"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - /* Transfer loop */ - - /* index counter */ - size_t idx = 0; + struct target *target = get_current_target(CMD_CTX); const size_t buffersize = 4096; uint8_t *buffer = malloc(buffersize); - if (!buffer) - return JIM_ERR; - /* assume ok */ - e = JIM_OK; - while (len) { - /* Slurp... in buffer size chunks */ + if (!buffer) { + LOG_ERROR("Failed to allocate memory"); + return ERROR_FAIL; + } + + char *separator = ""; + while (count > 0) { const unsigned int max_chunk_len = buffersize / width; - const size_t chunk_len = MIN(len, max_chunk_len); /* in elements.. */ + const size_t chunk_len = MIN(count, max_chunk_len); int retval; + if (is_phys) retval = target_read_phys_memory(target, addr, width, chunk_len, buffer); else retval = target_read_memory(target, addr, width, chunk_len, buffer); + if (retval != ERROR_OK) { - /* BOO !*/ - LOG_ERROR("mem2array: Read @ " TARGET_ADDR_FMT ", w=%u, cnt=%zu, failed", - addr, - width, - chunk_len); - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL); - e = JIM_ERR; - break; - } else { - for (size_t i = 0; i < chunk_len ; i++, idx++) { - uint64_t v = 0; - switch (width) { - case 8: - v = target_buffer_get_u64(target, &buffer[i*width]); - break; - case 4: - v = target_buffer_get_u32(target, &buffer[i*width]); - break; - case 2: - v = target_buffer_get_u16(target, &buffer[i*width]); - break; - case 1: - v = buffer[i] & 0x0ff; - break; - } - new_u64_array_element(interp, varname, idx, v); + LOG_DEBUG("read_memory: read at " TARGET_ADDR_FMT " with width=%u and count=%zu failed", + addr, width_bits, chunk_len); + /* + * FIXME: we append the errmsg to the list of value already read. + * Add a way to flush and replace old output, but LOG_DEBUG() it + */ + command_print(CMD, "read_memory: failed to read memory"); + free(buffer); + return retval; + } + + for (size_t i = 0; i < chunk_len ; i++) { + uint64_t v = 0; + + switch (width) { + case 8: + v = target_buffer_get_u64(target, &buffer[i * width]); + break; + case 4: + v = target_buffer_get_u32(target, &buffer[i * width]); + break; + case 2: + v = target_buffer_get_u16(target, &buffer[i * width]); + break; + case 1: + v = buffer[i]; + break; } - len -= chunk_len; - addr += chunk_len * width; + + command_print_sameline(CMD, "%s0x%" PRIx64, separator, v); + separator = " "; } + + count -= chunk_len; + addr += chunk_len * width; } free(buffer); - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - - return e; + return ERROR_OK; } -static int target_jim_read_memory(Jim_Interp *interp, int argc, +static int target_jim_write_memory(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { /* * argv[1] = memory address * argv[2] = desired element width in bits - * argv[3] = number of elements to read + * argv[3] = list of data to write * argv[4] = optional "phys" */ if (argc < 4 || argc > 5) { - Jim_WrongNumArgs(interp, 1, argv, "address width count ['phys']"); + Jim_WrongNumArgs(interp, 1, argv, "address width data ['phys']"); return JIM_ERR; } /* Arg 1: Memory address. */ - jim_wide wide_addr; int e; + jim_wide wide_addr; e = Jim_GetWide(interp, argv[1], &wide_addr); if (e != JIM_OK) @@ -4625,14 +4534,7 @@ static int target_jim_read_memory(Jim_Interp *interp, int argc, return e; const unsigned int width_bits = l; - - /* Arg 3: Number of elements to read. */ - e = Jim_GetLong(interp, argv[3], &l); - - if (e != JIM_OK) - return e; - - size_t count = l; + size_t count = Jim_ListLength(interp, argv[3]); /* Arg 4: Optional 'phys'. */ bool is_phys = false; @@ -4662,12 +4564,12 @@ static int target_jim_read_memory(Jim_Interp *interp, int argc, const unsigned int width = width_bits / 8; if ((addr + (count * width)) < addr) { - Jim_SetResultString(interp, "read_memory: addr + count wraps to zero", -1); + Jim_SetResultString(interp, "write_memory: addr + len wraps to zero", -1); return JIM_ERR; } if (count > 65536) { - Jim_SetResultString(interp, "read_memory: too large read request, exeeds 64K elements", -1); + Jim_SetResultString(interp, "write_memory: too large memory write request, exceeds 64K elements", -1); return JIM_ERR; } @@ -4683,381 +4585,38 @@ static int target_jim_read_memory(Jim_Interp *interp, int argc, return JIM_ERR; } - Jim_Obj *result_list = Jim_NewListObj(interp, NULL, 0); - Jim_IncrRefCount(result_list); + size_t j = 0; while (count > 0) { const unsigned int max_chunk_len = buffersize / width; const size_t chunk_len = MIN(count, max_chunk_len); - int retval; - - if (is_phys) - retval = target_read_phys_memory(target, addr, width, chunk_len, buffer); - else - retval = target_read_memory(target, addr, width, chunk_len, buffer); - - if (retval != ERROR_OK) { - LOG_ERROR("read_memory: read at " TARGET_ADDR_FMT " with width=%u and count=%zu failed", - addr, width_bits, chunk_len); - Jim_SetResultString(interp, "read_memory: failed to read memory", -1); - e = JIM_ERR; - break; - } + for (size_t i = 0; i < chunk_len; i++, j++) { + Jim_Obj *tmp = Jim_ListGetIndex(interp, argv[3], j); + jim_wide element_wide; + Jim_GetWide(interp, tmp, &element_wide); - for (size_t i = 0; i < chunk_len ; i++) { - uint64_t v = 0; + const uint64_t v = element_wide; switch (width) { case 8: - v = target_buffer_get_u64(target, &buffer[i * width]); + target_buffer_set_u64(target, &buffer[i * width], v); break; case 4: - v = target_buffer_get_u32(target, &buffer[i * width]); + target_buffer_set_u32(target, &buffer[i * width], v); break; case 2: - v = target_buffer_get_u16(target, &buffer[i * width]); + target_buffer_set_u16(target, &buffer[i * width], v); break; case 1: - v = buffer[i]; + buffer[i] = v & 0x0ff; break; } - - char value_buf[11]; - snprintf(value_buf, sizeof(value_buf), "0x%" PRIx64, v); - - Jim_ListAppendElement(interp, result_list, - Jim_NewStringObj(interp, value_buf, -1)); } count -= chunk_len; - addr += chunk_len * width; - } - - free(buffer); - if (e != JIM_OK) { - Jim_DecrRefCount(interp, result_list); - return e; - } - - Jim_SetResult(interp, result_list); - Jim_DecrRefCount(interp, result_list); - - return JIM_OK; -} - -static int get_u64_array_element(Jim_Interp *interp, const char *varname, size_t idx, uint64_t *val) -{ - char *namebuf = alloc_printf("%s(%zu)", varname, idx); - if (!namebuf) - return JIM_ERR; - - Jim_Obj *obj_name = Jim_NewStringObj(interp, namebuf, -1); - if (!obj_name) { - free(namebuf); - return JIM_ERR; - } - - Jim_IncrRefCount(obj_name); - Jim_Obj *obj_val = Jim_GetVariable(interp, obj_name, JIM_ERRMSG); - Jim_DecrRefCount(interp, obj_name); - free(namebuf); - if (!obj_val) - return JIM_ERR; - - jim_wide wide_val; - int result = Jim_GetWide(interp, obj_val, &wide_val); - *val = wide_val; - return result; -} - -static int target_array2mem(Jim_Interp *interp, struct target *target, - int argc, Jim_Obj *const *argv) -{ - int e; - - LOG_WARNING("DEPRECATED! use 'write_memory' not 'array2mem'"); - - /* argv[0] = name of array from which to read the data - * argv[1] = desired element width in bits - * argv[2] = memory address - * argv[3] = number of elements to write - * argv[4] = optional "phys" - */ - if (argc < 4 || argc > 5) { - Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]"); - return JIM_ERR; - } - - /* Arg 0: Name of the array variable */ - const char *varname = Jim_GetString(argv[0], NULL); - - /* Arg 1: Bit width of one element */ - long l; - e = Jim_GetLong(interp, argv[1], &l); - if (e != JIM_OK) - return e; - const unsigned int width_bits = l; - - if (width_bits != 8 && - width_bits != 16 && - width_bits != 32 && - width_bits != 64) { - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), - "Invalid width param. Must be one of: 8, 16, 32 or 64.", NULL); - return JIM_ERR; - } - const unsigned int width = width_bits / 8; - - /* Arg 2: Memory address */ - jim_wide wide_addr; - e = Jim_GetWide(interp, argv[2], &wide_addr); - if (e != JIM_OK) - return e; - target_addr_t addr = (target_addr_t)wide_addr; - - /* Arg 3: Number of elements to write */ - e = Jim_GetLong(interp, argv[3], &l); - if (e != JIM_OK) - return e; - size_t len = l; - - /* Arg 4: Phys */ - bool is_phys = false; - if (argc > 4) { - int str_len = 0; - const char *phys = Jim_GetString(argv[4], &str_len); - if (!strncmp(phys, "phys", str_len)) - is_phys = true; - else - return JIM_ERR; - } - - /* Argument checks */ - if (len == 0) { - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), - "array2mem: zero width read?", NULL); - return JIM_ERR; - } - - if ((addr + (len * width)) < addr) { - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), - "array2mem: addr + len - wraps to zero?", NULL); - return JIM_ERR; - } - - if (len > 65536) { - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), - "array2mem: too large memory write request, exceeds 64K items", NULL); - return JIM_ERR; - } - - if ((width == 1) || - ((width == 2) && ((addr & 1) == 0)) || - ((width == 4) && ((addr & 3) == 0)) || - ((width == 8) && ((addr & 7) == 0))) { - /* alignment correct */ - } else { - char buf[100]; - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - sprintf(buf, "array2mem address: " TARGET_ADDR_FMT " is not aligned for %" PRIu32 " byte reads", - addr, - width); - Jim_AppendStrings(interp, Jim_GetResult(interp), buf, NULL); - return JIM_ERR; - } - - /* Transfer loop */ - - /* assume ok */ - e = JIM_OK; - - const size_t buffersize = 4096; - uint8_t *buffer = malloc(buffersize); - if (!buffer) - return JIM_ERR; - - /* index counter */ - size_t idx = 0; - - while (len) { - /* Slurp... in buffer size chunks */ - const unsigned int max_chunk_len = buffersize / width; - - const size_t chunk_len = MIN(len, max_chunk_len); /* in elements.. */ - - /* Fill the buffer */ - for (size_t i = 0; i < chunk_len; i++, idx++) { - uint64_t v = 0; - if (get_u64_array_element(interp, varname, idx, &v) != JIM_OK) { - free(buffer); - return JIM_ERR; - } - switch (width) { - case 8: - target_buffer_set_u64(target, &buffer[i * width], v); - break; - case 4: - target_buffer_set_u32(target, &buffer[i * width], v); - break; - case 2: - target_buffer_set_u16(target, &buffer[i * width], v); - break; - case 1: - buffer[i] = v & 0x0ff; - break; - } - } - len -= chunk_len; - - /* Write the buffer to memory */ - int retval; - if (is_phys) - retval = target_write_phys_memory(target, addr, width, chunk_len, buffer); - else - retval = target_write_memory(target, addr, width, chunk_len, buffer); - if (retval != ERROR_OK) { - /* BOO !*/ - LOG_ERROR("array2mem: Write @ " TARGET_ADDR_FMT ", w=%u, cnt=%zu, failed", - addr, - width, - chunk_len); - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: cannot read memory", NULL); - e = JIM_ERR; - break; - } - addr += chunk_len * width; - } - - free(buffer); - - Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - - return e; -} - -static int target_jim_write_memory(Jim_Interp *interp, int argc, - Jim_Obj * const *argv) -{ - /* - * argv[1] = memory address - * argv[2] = desired element width in bits - * argv[3] = list of data to write - * argv[4] = optional "phys" - */ - - if (argc < 4 || argc > 5) { - Jim_WrongNumArgs(interp, 1, argv, "address width data ['phys']"); - return JIM_ERR; - } - - /* Arg 1: Memory address. */ - int e; - jim_wide wide_addr; - e = Jim_GetWide(interp, argv[1], &wide_addr); - - if (e != JIM_OK) - return e; - - target_addr_t addr = (target_addr_t)wide_addr; - - /* Arg 2: Bit width of one element. */ - long l; - e = Jim_GetLong(interp, argv[2], &l); - - if (e != JIM_OK) - return e; - - const unsigned int width_bits = l; - size_t count = Jim_ListLength(interp, argv[3]); - - /* Arg 4: Optional 'phys'. */ - bool is_phys = false; - - if (argc > 4) { - const char *phys = Jim_GetString(argv[4], NULL); - - if (strcmp(phys, "phys")) { - Jim_SetResultFormatted(interp, "invalid argument '%s', must be 'phys'", phys); - return JIM_ERR; - } - - is_phys = true; - } - - switch (width_bits) { - case 8: - case 16: - case 32: - case 64: - break; - default: - Jim_SetResultString(interp, "invalid width, must be 8, 16, 32 or 64", -1); - return JIM_ERR; - } - - const unsigned int width = width_bits / 8; - - if ((addr + (count * width)) < addr) { - Jim_SetResultString(interp, "write_memory: addr + len wraps to zero", -1); - return JIM_ERR; - } - - if (count > 65536) { - Jim_SetResultString(interp, "write_memory: too large memory write request, exceeds 64K elements", -1); - return JIM_ERR; - } - - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx != NULL); - struct target *target = get_current_target(cmd_ctx); - - const size_t buffersize = 4096; - uint8_t *buffer = malloc(buffersize); - - if (!buffer) { - LOG_ERROR("Failed to allocate memory"); - return JIM_ERR; - } - - size_t j = 0; - - while (count > 0) { - const unsigned int max_chunk_len = buffersize / width; - const size_t chunk_len = MIN(count, max_chunk_len); - - for (size_t i = 0; i < chunk_len; i++, j++) { - Jim_Obj *tmp = Jim_ListGetIndex(interp, argv[3], j); - jim_wide element_wide; - Jim_GetWide(interp, tmp, &element_wide); - - const uint64_t v = element_wide; - - switch (width) { - case 8: - target_buffer_set_u64(target, &buffer[i * width], v); - break; - case 4: - target_buffer_set_u32(target, &buffer[i * width], v); - break; - case 2: - target_buffer_set_u16(target, &buffer[i * width], v); - break; - case 1: - buffer[i] = v & 0x0ff; - break; - } - } - - count -= chunk_len; - - int retval; + int retval; if (is_phys) retval = target_write_phys_memory(target, addr, width, chunk_len, buffer); @@ -5090,8 +4649,7 @@ void target_handle_event(struct target *target, enum target_event e) for (teap = target->event_action; teap; teap = teap->next) { if (teap->event == e) { - LOG_DEBUG("target(%d): %s (%s) event: %d (%s) action: %s", - target->target_number, + LOG_DEBUG("target: %s (%s) event: %d (%s) action: %s", target_name(target), target_type_name(target), e, @@ -5179,7 +4737,7 @@ static int target_jim_get_reg(Jim_Interp *interp, int argc, return JIM_ERR; } - if (force) { + if (force || !reg->valid) { int retval = reg->type->get(reg); if (retval != ERROR_OK) { @@ -5225,10 +4783,18 @@ static int target_jim_set_reg(Jim_Interp *interp, int argc, } int tmp; +#if JIM_VERSION >= 80 Jim_Obj **dict = Jim_DictPairs(interp, argv[1], &tmp); if (!dict) return JIM_ERR; +#else + Jim_Obj **dict; + int ret = Jim_DictPairs(interp, argv[1], &dict, &tmp); + + if (ret != JIM_OK) + return ret; +#endif const unsigned int length = tmp; struct command_context *cmd_ctx = current_command_context(interp); @@ -5270,7 +4836,7 @@ static int target_jim_set_reg(Jim_Interp *interp, int argc, /** * Returns true only if the target has a handler for the specified event. */ -bool target_has_event_action(struct target *target, enum target_event event) +bool target_has_event_action(const struct target *target, enum target_event event) { struct target_event_action *teap; @@ -5502,13 +5068,13 @@ static int target_configure(struct jim_getopt_info *goi, struct target *target) e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; - /* make this exactly 1 or 0 */ - target->backup_working_area = (!!w); + /* make this boolean */ + target->backup_working_area = (w != 0); } else { if (goi->argc != 0) goto no_params; } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->backup_working_area)); + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->backup_working_area ? 1 : 0)); /* loop for more e*/ break; @@ -5671,167 +5237,117 @@ static int jim_target_configure(Jim_Interp *interp, int argc, Jim_Obj * const *a return target_configure(&goi, target); } -static int jim_target_mem2array(Jim_Interp *interp, - int argc, Jim_Obj *const *argv) -{ - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - return target_mem2array(interp, target, argc - 1, argv + 1); -} - -static int jim_target_array2mem(Jim_Interp *interp, - int argc, Jim_Obj *const *argv) -{ - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - return target_array2mem(interp, target, argc - 1, argv + 1); -} - -static int jim_target_tap_disabled(Jim_Interp *interp) -{ - Jim_SetResultFormatted(interp, "[TAP is disabled]"); - return JIM_ERR; -} - -static int jim_target_examine(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_target_examine) { bool allow_defer = false; - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - if (goi.argc > 1) { - const char *cmd_name = Jim_GetString(argv[0], NULL); - Jim_SetResultFormatted(goi.interp, - "usage: %s ['allow-defer']", cmd_name); - return JIM_ERR; - } - if (goi.argc > 0 && - strcmp(Jim_GetString(argv[1], NULL), "allow-defer") == 0) { - /* consume it */ - Jim_Obj *obj; - int e = jim_getopt_obj(&goi, &obj); - if (e != JIM_OK) - return e; + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (CMD_ARGC == 1) { + if (strcmp(CMD_ARGV[0], "allow-defer")) + return ERROR_COMMAND_ARGUMENT_INVALID; allow_defer = true; } - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - if (!target->tap->enabled) - return jim_target_tap_disabled(interp); + struct target *target = get_current_target(CMD_CTX); + if (!target->tap->enabled) { + command_print(CMD, "[TAP is disabled]"); + return ERROR_FAIL; + } if (allow_defer && target->defer_examine) { LOG_INFO("Deferring arp_examine of %s", target_name(target)); LOG_INFO("Use arp_examine command to examine it manually!"); - return JIM_OK; + return ERROR_OK; } - int e = target->type->examine(target); - if (e != ERROR_OK) { + int retval = target->type->examine(target); + if (retval != ERROR_OK) { target_reset_examined(target); - return JIM_ERR; + return retval; } target_set_examined(target); - return JIM_OK; + return ERROR_OK; } -static int jim_target_was_examined(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(handle_target_was_examined) { - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; - Jim_SetResultBool(interp, target_was_examined(target)); - return JIM_OK; + struct target *target = get_current_target(CMD_CTX); + + command_print(CMD, "%d", target_was_examined(target) ? 1 : 0); + + return ERROR_OK; } -static int jim_target_examine_deferred(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(handle_target_examine_deferred) { - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; - Jim_SetResultBool(interp, target->defer_examine); - return JIM_OK; + struct target *target = get_current_target(CMD_CTX); + + command_print(CMD, "%d", target->defer_examine ? 1 : 0); + + return ERROR_OK; } -static int jim_target_halt_gdb(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_target_halt_gdb) { - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); - return JIM_ERR; - } - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; - if (target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT) != ERROR_OK) - return JIM_ERR; + struct target *target = get_current_target(CMD_CTX); - return JIM_OK; + return target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } -static int jim_target_poll(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_target_poll) { - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); - return JIM_ERR; + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + if (!target->tap->enabled) { + command_print(CMD, "[TAP is disabled]"); + return ERROR_FAIL; } - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - if (!target->tap->enabled) - return jim_target_tap_disabled(interp); - int e; if (!(target_was_examined(target))) - e = ERROR_TARGET_NOT_EXAMINED; - else - e = target->type->poll(target); - if (e != ERROR_OK) - return JIM_ERR; - return JIM_OK; + return ERROR_TARGET_NOT_EXAMINED; + + return target->type->poll(target); } -static int jim_target_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_target_reset) { - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; - if (goi.argc != 2) { - Jim_WrongNumArgs(interp, 0, argv, - "([tT]|[fF]|assert|deassert) BOOL"); - return JIM_ERR; + const struct nvp *n = nvp_name2value(nvp_assert, CMD_ARGV[0]); + if (!n->name) { + nvp_unknown_command_print(CMD, nvp_assert, NULL, CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; } - struct jim_nvp *n; - int e = jim_getopt_nvp(&goi, nvp_assert, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(&goi, nvp_assert, 1); - return e; - } /* the halt or not param */ - jim_wide a; - e = jim_getopt_wide(&goi, &a); - if (e != JIM_OK) - return e; + int a; + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], a); - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - if (!target->tap->enabled) - return jim_target_tap_disabled(interp); + struct target *target = get_current_target(CMD_CTX); + if (!target->tap->enabled) { + command_print(CMD, "[TAP is disabled]"); + return ERROR_FAIL; + } if (!target->type->assert_reset || !target->type->deassert_reset) { - Jim_SetResultFormatted(interp, - "No target-specific reset for %s", - target_name(target)); - return JIM_ERR; + command_print(CMD, "No target-specific reset for %s", target_name(target)); + return ERROR_FAIL; } if (target->defer_examine) @@ -5844,66 +5360,53 @@ static int jim_target_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) /* do the assert */ if (n->value == NVP_ASSERT) - e = target->type->assert_reset(target); - else - e = target->type->deassert_reset(target); - return (e == ERROR_OK) ? JIM_OK : JIM_ERR; + return target->type->assert_reset(target); + return target->type->deassert_reset(target); } -static int jim_target_halt(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_target_halt) { - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); - return JIM_ERR; + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + if (!target->tap->enabled) { + command_print(CMD, "[TAP is disabled]"); + return ERROR_FAIL; } - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - if (!target->tap->enabled) - return jim_target_tap_disabled(interp); - int e = target->type->halt(target); - return (e == ERROR_OK) ? JIM_OK : JIM_ERR; + + return target->type->halt(target); } -static int jim_target_wait_state(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_target_wait_state) { - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; - /* params: <name> statename timeoutmsecs */ - if (goi.argc != 2) { - const char *cmd_name = Jim_GetString(argv[0], NULL); - Jim_SetResultFormatted(goi.interp, - "%s <state_name> <timeout_in_msec>", cmd_name); - return JIM_ERR; + const struct nvp *n = nvp_name2value(nvp_target_state, CMD_ARGV[0]); + if (!n->name) { + nvp_unknown_command_print(CMD, nvp_target_state, NULL, CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; } - struct jim_nvp *n; - int e = jim_getopt_nvp(&goi, nvp_target_state, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(&goi, nvp_target_state, 1); - return e; + unsigned int a; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], a); + + struct target *target = get_current_target(CMD_CTX); + if (!target->tap->enabled) { + command_print(CMD, "[TAP is disabled]"); + return ERROR_FAIL; } - jim_wide a; - e = jim_getopt_wide(&goi, &a); - if (e != JIM_OK) - return e; - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - if (!target->tap->enabled) - return jim_target_tap_disabled(interp); - e = target_wait_state(target, n->value, a); - if (e != ERROR_OK) { - Jim_Obj *obj = Jim_NewIntObj(interp, e); - Jim_SetResultFormatted(goi.interp, - "target: %s wait %s fails (%#s) %s", + int retval = target_wait_state(target, n->value, a); + if (retval != ERROR_OK) { + command_print(CMD, + "target: %s wait %s fails (%d) %s", target_name(target), n->name, - obj, target_strerror_safe(e)); - return JIM_ERR; + retval, target_strerror_safe(retval)); + return retval; } - return JIM_OK; + return ERROR_OK; } /* List for human, Events defined for this target. * scripts/programs should use 'name cget -event NAME' @@ -5913,8 +5416,7 @@ COMMAND_HANDLER(handle_target_event_list) struct target *target = get_current_target(CMD_CTX); struct target_event_action *teap = target->event_action; - command_print(CMD, "Event actions for target (%d) %s\n", - target->target_number, + command_print(CMD, "Event actions for target %s\n", target_name(target)); command_print(CMD, "%-25s | Body", "Event"); command_print(CMD, "------------------------- | " @@ -5928,18 +5430,41 @@ COMMAND_HANDLER(handle_target_event_list) command_print(CMD, "***END***"); return ERROR_OK; } -static int jim_target_current_state(Jim_Interp *interp, int argc, Jim_Obj *const *argv) + +COMMAND_HANDLER(handle_target_current_state) { - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); - return JIM_ERR; + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + + command_print(CMD, "%s", target_state_name(target)); + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_target_debug_reason) +{ + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + + + const char *debug_reason = nvp_value2name(nvp_target_debug_reason, + target->debug_reason)->name; + + if (!debug_reason) { + command_print(CMD, "bug: invalid debug reason (%d)", + target->debug_reason); + return ERROR_FAIL; } - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - Jim_SetResultString(interp, target_state_name(target), -1); - return JIM_OK; + + command_print(CMD, "%s", debug_reason); + + return ERROR_OK; } + static int jim_target_invoke_event(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct jim_getopt_info goi; @@ -6033,22 +5558,6 @@ static const struct command_registration target_instance_command_handlers[] = { .help = "Display target memory as 8-bit bytes", .usage = "address [count]", }, - { - .name = "array2mem", - .mode = COMMAND_EXEC, - .jim_handler = jim_target_array2mem, - .help = "Writes Tcl array of 8/16/32 bit numbers " - "to target memory", - .usage = "arrayname bitwidth address count", - }, - { - .name = "mem2array", - .mode = COMMAND_EXEC, - .jim_handler = jim_target_mem2array, - .help = "Loads Tcl array of 8/16/32 bit numbers " - "from target memory", - .usage = "arrayname bitwidth address count", - }, { .name = "get_reg", .mode = COMMAND_EXEC, @@ -6066,7 +5575,7 @@ static const struct command_registration target_instance_command_handlers[] = { { .name = "read_memory", .mode = COMMAND_EXEC, - .jim_handler = target_jim_read_memory, + .handler = handle_target_read_memory, .help = "Read Tcl list of 8/16/32/64 bit numbers from target memory", .usage = "address width count ['phys']", }, @@ -6087,57 +5596,72 @@ static const struct command_registration target_instance_command_handlers[] = { { .name = "curstate", .mode = COMMAND_EXEC, - .jim_handler = jim_target_current_state, + .handler = handle_target_current_state, .help = "displays the current state of this target", + .usage = "", + }, + { + .name = "debug_reason", + .mode = COMMAND_EXEC, + .handler = handle_target_debug_reason, + .help = "displays the debug reason of this target", + .usage = "", }, { .name = "arp_examine", .mode = COMMAND_EXEC, - .jim_handler = jim_target_examine, + .handler = handle_target_examine, .help = "used internally for reset processing", .usage = "['allow-defer']", }, { .name = "was_examined", .mode = COMMAND_EXEC, - .jim_handler = jim_target_was_examined, + .handler = handle_target_was_examined, .help = "used internally for reset processing", + .usage = "", }, { .name = "examine_deferred", .mode = COMMAND_EXEC, - .jim_handler = jim_target_examine_deferred, + .handler = handle_target_examine_deferred, .help = "used internally for reset processing", + .usage = "", }, { .name = "arp_halt_gdb", .mode = COMMAND_EXEC, - .jim_handler = jim_target_halt_gdb, + .handler = handle_target_halt_gdb, .help = "used internally for reset processing to halt GDB", + .usage = "", }, { .name = "arp_poll", .mode = COMMAND_EXEC, - .jim_handler = jim_target_poll, + .handler = handle_target_poll, .help = "used internally for reset processing", + .usage = "", }, { .name = "arp_reset", .mode = COMMAND_EXEC, - .jim_handler = jim_target_reset, + .handler = handle_target_reset, .help = "used internally for reset processing", + .usage = "'assert'|'deassert' halt", }, { .name = "arp_halt", .mode = COMMAND_EXEC, - .jim_handler = jim_target_halt, + .handler = handle_target_halt, .help = "used internally for reset processing", + .usage = "", }, { .name = "arp_waitstate", .mode = COMMAND_EXEC, - .jim_handler = jim_target_wait_state, + .handler = handle_target_wait_state, .help = "used internally for reset processing", + .usage = "statename timeoutmsecs", }, { .name = "invoke-event", @@ -6182,7 +5706,7 @@ static int target_create(struct jim_getopt_info *goi) if (e != JIM_OK) return e; struct transport *tr = get_current_transport(); - if (tr->override_target) { + if (tr && tr->override_target) { e = tr->override_target(&cp); if (e != ERROR_OK) { LOG_ERROR("The selected transport doesn't support this target"); @@ -6225,9 +5749,6 @@ static int target_create(struct jim_getopt_info *goi) /* set empty smp cluster */ target->smp_targets = &empty_smp_targets; - /* set target number */ - target->target_number = new_target_number(); - /* allocate memory for each unique target type */ target->type = malloc(sizeof(struct target_type)); if (!target->type) { @@ -6244,7 +5765,7 @@ static int target_create(struct jim_getopt_info *goi) target->working_area = 0x0; target->working_area_size = 0x0; target->working_areas = NULL; - target->backup_working_area = 0; + target->backup_working_area = false; target->state = TARGET_UNKNOWN; target->debug_reason = DBG_REASON_UNDEFINED; @@ -6386,100 +5907,124 @@ static int target_create(struct jim_getopt_info *goi) return JIM_OK; } -static int jim_target_current(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_target_current) { - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); - return JIM_ERR; - } - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; - struct target *target = get_current_target_or_null(cmd_ctx); + struct target *target = get_current_target_or_null(CMD_CTX); if (target) - Jim_SetResultString(interp, target_name(target), -1); - return JIM_OK; + command_print(CMD, "%s", target_name(target)); + + return ERROR_OK; } -static int jim_target_types(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_target_types) { - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); - return JIM_ERR; - } - Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); - for (unsigned x = 0; target_types[x]; x++) { - Jim_ListAppendElement(interp, Jim_GetResult(interp), - Jim_NewStringObj(interp, target_types[x]->name, -1)); - } - return JIM_OK; + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + for (unsigned int x = 0; target_types[x]; x++) + command_print(CMD, "%s", target_types[x]->name); + + return ERROR_OK; } -static int jim_target_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_target_names) { - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); - return JIM_ERR; - } - Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + struct target *target = all_targets; while (target) { - Jim_ListAppendElement(interp, Jim_GetResult(interp), - Jim_NewStringObj(interp, target_name(target), -1)); + command_print(CMD, "%s", target_name(target)); target = target->next; } - return JIM_OK; + + return ERROR_OK; } -static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +static struct target_list * +__attribute__((warn_unused_result)) +create_target_list_node(const char *targetname) +{ + struct target *target = get_target(targetname); + LOG_DEBUG("%s ", targetname); + if (!target) + return NULL; + + struct target_list *new = malloc(sizeof(struct target_list)); + if (!new) { + LOG_ERROR("Out of memory"); + return new; + } + + new->target = target; + return new; +} + +static int get_target_with_common_rtos_type(struct command_invocation *cmd, + struct list_head *lh, struct target **result) { - int i; - const char *targetname; - int retval, len; - static int smp_group = 1; struct target *target = NULL; - struct target_list *head, *new; + struct target_list *curr; + foreach_smp_target(curr, lh) { + struct rtos *curr_rtos = curr->target->rtos; + if (curr_rtos) { + if (target && target->rtos && target->rtos->type != curr_rtos->type) { + command_print(cmd, "Different rtos types in members of one smp target!"); + return ERROR_FAIL; + } + target = curr->target; + } + } + *result = target; + return ERROR_OK; +} - retval = 0; - LOG_DEBUG("%d", argc); - /* argv[1] = target to associate in smp - * argv[2] = target to associate in smp - * argv[3] ... +COMMAND_HANDLER(handle_target_smp) +{ + static int smp_group = 1; + + if (CMD_ARGC == 0) { + LOG_DEBUG("Empty SMP target"); + return ERROR_OK; + } + LOG_DEBUG("%d", CMD_ARGC); + /* CMD_ARGC[0] = target to associate in smp + * CMD_ARGC[1] = target to associate in smp + * CMD_ARGC[2] ... */ struct list_head *lh = malloc(sizeof(*lh)); if (!lh) { LOG_ERROR("Out of memory"); - return JIM_ERR; + return ERROR_FAIL; } INIT_LIST_HEAD(lh); - for (i = 1; i < argc; i++) { - - targetname = Jim_GetString(argv[i], &len); - target = get_target(targetname); - LOG_DEBUG("%s ", targetname); - if (target) { - new = malloc(sizeof(struct target_list)); - new->target = target; + for (unsigned int i = 0; i < CMD_ARGC; i++) { + struct target_list *new = create_target_list_node(CMD_ARGV[i]); + if (new) list_add_tail(&new->lh, lh); - } } /* now parse the list of cpu and put the target in smp mode*/ - foreach_smp_target(head, lh) { - target = head->target; + struct target_list *curr; + foreach_smp_target(curr, lh) { + struct target *target = curr->target; target->smp = smp_group; target->smp_targets = lh; } smp_group++; - if (target && target->rtos) - retval = rtos_smp_init(head->target); + struct target *rtos_target; + int retval = get_target_with_common_rtos_type(CMD, lh, &rtos_target); + if (retval == ERROR_OK && rtos_target) + retval = rtos_smp_init(rtos_target); return retval; } - static int jim_target_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct jim_getopt_info goi; @@ -6510,26 +6055,29 @@ static const struct command_registration target_subcommand_handlers[] = { { .name = "current", .mode = COMMAND_ANY, - .jim_handler = jim_target_current, + .handler = handle_target_current, .help = "Returns the currently selected target", + .usage = "", }, { .name = "types", .mode = COMMAND_ANY, - .jim_handler = jim_target_types, + .handler = handle_target_types, .help = "Returns the available target types as " "a list of strings", + .usage = "", }, { .name = "names", .mode = COMMAND_ANY, - .jim_handler = jim_target_names, + .handler = handle_target_names, .help = "Returns the names of all targets as a list of strings", + .usage = "", }, { .name = "smp", .mode = COMMAND_ANY, - .jim_handler = jim_target_smp, + .handler = handle_target_smp, .usage = "targetname1 targetname2 ...", .help = "gather several target in a smp list" }, @@ -6731,8 +6279,8 @@ COMMAND_HANDLER(handle_ps_command) struct target *target = get_current_target(CMD_CTX); char *display; if (target->state != TARGET_HALTED) { - LOG_INFO("target not halted !!"); - return ERROR_OK; + command_print(CMD, "Error: [%s] not halted", target_name(target)); + return ERROR_TARGET_NOT_HALTED; } if ((target->rtos) && (target->rtos->type) @@ -6763,8 +6311,8 @@ COMMAND_HANDLER(handle_test_mem_access_command) int retval = ERROR_OK; if (target->state != TARGET_HALTED) { - LOG_INFO("target not halted !!"); - return ERROR_FAIL; + command_print(CMD, "Error: [%s] not halted", target_name(target)); + return ERROR_TARGET_NOT_HALTED; } if (CMD_ARGC != 1) @@ -6944,8 +6492,8 @@ static const struct command_registration target_exec_command_handlers[] = { .mode = COMMAND_ANY, .help = "Load image into server memory for later use by " "fast_load; primarily for profiling", - .usage = "filename address ['bin'|'ihex'|'elf'|'s19'] " - "[min_address [max_length]]", + .usage = "filename [address ['bin'|'ihex'|'elf'|'s19' " + "[min_address [max_length]]]]", }, { .name = "fast_load", @@ -7105,21 +6653,21 @@ static const struct command_registration target_exec_command_handlers[] = { .handler = handle_wp_command, .mode = COMMAND_EXEC, .help = "list (no params) or create watchpoints", - .usage = "[address length [('r'|'w'|'a') value [mask]]]", + .usage = "[address length [('r'|'w'|'a') [value [mask]]]]", }, { .name = "rwp", .handler = handle_rwp_command, .mode = COMMAND_EXEC, .help = "remove watchpoint", - .usage = "address", + .usage = "'all' | address", }, { .name = "load_image", .handler = handle_load_image_command, .mode = COMMAND_EXEC, - .usage = "filename address ['bin'|'ihex'|'elf'|'s19'] " - "[min_address] [max_length]", + .usage = "filename [address ['bin'|'ihex'|'elf'|'s19' " + "[min_address [max_length]]]]", }, { .name = "dump_image", @@ -7162,7 +6710,7 @@ static const struct command_registration target_exec_command_handlers[] = { { .name = "read_memory", .mode = COMMAND_EXEC, - .jim_handler = target_jim_read_memory, + .handler = handle_target_read_memory, .help = "Read Tcl list of 8/16/32/64 bit numbers from target memory", .usage = "address width count ['phys']", }, @@ -7212,3 +6760,29 @@ static int target_register_user_commands(struct command_context *cmd_ctx) return register_commands(cmd_ctx, NULL, target_exec_command_handlers); } + +const char *target_debug_reason_str(enum target_debug_reason reason) +{ + switch (reason) { + case DBG_REASON_DBGRQ: + return "DBGRQ"; + case DBG_REASON_BREAKPOINT: + return "BREAKPOINT"; + case DBG_REASON_WATCHPOINT: + return "WATCHPOINT"; + case DBG_REASON_WPTANDBKPT: + return "WPTANDBKPT"; + case DBG_REASON_SINGLESTEP: + return "SINGLESTEP"; + case DBG_REASON_NOTHALTED: + return "NOTHALTED"; + case DBG_REASON_EXIT: + return "EXIT"; + case DBG_REASON_EXC_CATCH: + return "EXC_CATCH"; + case DBG_REASON_UNDEFINED: + return "UNDEFINED"; + default: + return "UNKNOWN!"; + } +} diff --git a/src/target/target.h b/src/target/target.h index 726a14d3f6..303d5e60c0 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -13,19 +15,6 @@ * * * Copyright (C) ST-Ericsson SA 2011 * * michel.jaouen@stericsson.com : smp minimum 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_TARGET_H @@ -56,6 +45,8 @@ struct gdb_fileio_info; * not sure how this is used with all the recent changes) * TARGET_DEBUG_RUNNING = 4: the target is running, but it is executing code on * behalf of the debugger (e.g. algorithm for flashing) + * TARGET_UNAVAILABLE = 5: The target is unavailable for some reason. It might + * be powered down, for instance. * * also see: target_state_name(); */ @@ -66,11 +57,7 @@ enum target_state { TARGET_HALTED = 2, TARGET_RESET = 3, TARGET_DEBUG_RUNNING = 4, -}; - -enum nvp_assert { - NVP_DEASSERT, - NVP_ASSERT, + TARGET_UNAVAILABLE = 5 }; enum target_reset_mode { @@ -131,7 +118,6 @@ enum target_register_class { struct target { struct target_type *type; /* target type definition (name, access functions) */ char *cmd_name; /* tcl Name of target */ - int target_number; /* DO NOT USE! field to be removed in 2010 */ struct jtag_tap *tap; /* where on the jtag chain is this */ int32_t coreid; /* which device on the TAP? */ @@ -165,7 +151,7 @@ struct target { bool working_area_phys_spec; /* physical address specified? */ target_addr_t working_area_phys; /* physical address */ uint32_t working_area_size; /* size in bytes */ - uint32_t backup_working_area; /* whether the content of the working area has to be preserved */ + bool backup_working_area; /* whether the content of the working area has to be preserved */ struct working_area *working_areas;/* list of allocated working areas */ enum target_debug_reason debug_reason;/* reason why the target entered debug state */ enum target_endianness endianness; /* target endianness */ @@ -203,10 +189,14 @@ struct target { * poll too quickly because we'll just overwhelm the user with error * messages. */ struct backoff_timer backoff; - int smp; /* add some target attributes for smp support */ + int smp; /* Unique non-zero number for each SMP group */ struct list_head *smp_targets; /* list all targets in this smp group/cluster * The head of the list is shared between the * cluster, thus here there is a pointer */ + bool smp_halt_event_postponed; /* Some SMP implementations (currently Cortex-M) stores + * 'halted' events and emits them after all targets of + * the SMP group has been polled */ + /* the gdb service is there in case of smp, we have only one gdb server * for all smp target * the target attached to the gdb is changing dynamically by changing @@ -238,19 +228,19 @@ struct gdb_fileio_info { }; /** Returns a description of the endianness for the specified target. */ -static inline const char *target_endianness(struct target *target) +static inline const char *target_endianness(const struct target *target) { return (target->endianness == TARGET_ENDIAN_UNKNOWN) ? "unknown" : (target->endianness == TARGET_BIG_ENDIAN) ? "big endian" : "little endian"; } /** Returns the instance-specific name of the specified target. */ -static inline const char *target_name(struct target *target) +static inline const char *target_name(const struct target *target) { return target->cmd_name; } -const char *debug_reason_name(struct target *t); +const char *debug_reason_name(const struct target *t); enum target_event { @@ -300,14 +290,14 @@ enum target_event { TARGET_EVENT_TRACE_CONFIG, - TARGET_EVENT_SEMIHOSTING_USER_CMD_0x100 = 0x100, /* semihosting allows user cmds from 0x100 to 0x1ff */ - TARGET_EVENT_SEMIHOSTING_USER_CMD_0x101 = 0x101, - TARGET_EVENT_SEMIHOSTING_USER_CMD_0x102 = 0x102, - TARGET_EVENT_SEMIHOSTING_USER_CMD_0x103 = 0x103, - TARGET_EVENT_SEMIHOSTING_USER_CMD_0x104 = 0x104, - TARGET_EVENT_SEMIHOSTING_USER_CMD_0x105 = 0x105, - TARGET_EVENT_SEMIHOSTING_USER_CMD_0x106 = 0x106, - TARGET_EVENT_SEMIHOSTING_USER_CMD_0x107 = 0x107, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0X100 = 0x100, /* semihosting allows user cmds from 0x100 to 0x1ff */ + TARGET_EVENT_SEMIHOSTING_USER_CMD_0X101 = 0x101, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0X102 = 0x102, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0X103 = 0x103, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0X104 = 0x104, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0X105 = 0x105, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0X106 = 0x106, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0X107 = 0x107, }; struct target_event_action { @@ -317,7 +307,7 @@ struct target_event_action { struct target_event_action *next; }; -bool target_has_event_action(struct target *target, enum target_event event); +bool target_has_event_action(const struct target *target, enum target_event event); struct target_event_callback { int (*callback)(struct target *target, enum target_event event, void *priv); @@ -427,7 +417,6 @@ int target_call_timer_callbacks_now(void); */ int64_t target_timer_next_event(void); -struct target *get_target_by_num(int num); struct target *get_current_target(struct command_context *cmd_ctx); struct target *get_current_target_or_null(struct command_context *cmd_ctx); struct target *get_target(const char *id); @@ -438,7 +427,7 @@ struct target *get_target(const char *id); * This routine is a wrapper for the target->type->name field. * Note that this is not an instance-specific name for his target. */ -const char *target_type_name(struct target *target); +const char *target_type_name(const struct target *target); /** * Examine the specified @a target, letting it perform any @@ -449,7 +438,7 @@ const char *target_type_name(struct target *target); int target_examine_one(struct target *target); /** @returns @c true if target_set_examined() has been called. */ -static inline bool target_was_examined(struct target *target) +static inline bool target_was_examined(const struct target *target) { return target->examined; } @@ -518,7 +507,7 @@ int target_hit_watchpoint(struct target *target, * * This routine is a wrapper for target->type->get_gdb_arch. */ -const char *target_get_gdb_arch(struct target *target); +const char *target_get_gdb_arch(const struct target *target); /** * Obtain the registers for GDB. @@ -544,7 +533,7 @@ int target_get_gdb_reg_list_noread(struct target *target, * * Some target do not implement the necessary code required by GDB. */ -bool target_supports_gdb_connection(struct target *target); +bool target_supports_gdb_connection(const struct target *target); /** * Step the target. @@ -562,7 +551,7 @@ int target_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, target_addr_t entry_point, target_addr_t exit_point, - int timeout_ms, void *arch_info); + unsigned int timeout_ms, void *arch_info); /** * Starts an algorithm in the background on the @a target given. @@ -583,7 +572,7 @@ int target_start_algorithm(struct target *target, int target_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, - target_addr_t exit_point, int timeout_ms, + target_addr_t exit_point, unsigned int timeout_ms, void *arch_info); /** @@ -675,7 +664,7 @@ int target_checksum_memory(struct target *target, int target_blank_check_memory(struct target *target, struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value); -int target_wait_state(struct target *target, enum target_state state, int ms); +int target_wait_state(struct target *target, enum target_state state, unsigned int ms); /** * Obtain file-I/O information from target for GDB to do syscall. @@ -711,7 +700,7 @@ unsigned target_address_bits(struct target *target); unsigned int target_data_bits(struct target *target); /** Return the *name* of this targets current state */ -const char *target_state_name(struct target *target); +const char *target_state_name(const struct target *target); /** Return the *name* of a target event enumeration value */ const char *target_event_name(enum target_event event); @@ -813,9 +802,13 @@ int target_profiling_default(struct target *target, uint32_t *samples, uint32_t #define ERROR_TARGET_NOT_EXAMINED (-311) #define ERROR_TARGET_DUPLICATE_BREAKPOINT (-312) #define ERROR_TARGET_ALGO_EXIT (-313) +#define ERROR_TARGET_SIZE_NOT_SUPPORTED (-314) +#define ERROR_TARGET_PACKING_NOT_SUPPORTED (-315) extern bool get_target_reset_nag(void); #define TARGET_DEFAULT_POLLING_INTERVAL 100 +const char *target_debug_reason_str(enum target_debug_reason reason); + #endif /* OPENOCD_TARGET_TARGET_H */ diff --git a/src/target/target_request.c b/src/target/target_request.c index 562b046aad..72c84216fa 100644 --- a/src/target/target_request.c +++ b/src/target/target_request.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/target_request.h b/src/target/target_request.h index 1b1317338e..62d5c74b1e 100644 --- a/src/target/target_request.h +++ b/src/target/target_request.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_TARGET_REQUEST_H diff --git a/src/target/target_type.h b/src/target/target_type.h index d6b6086b3c..2bc09ff422 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_TARGET_TYPE_H @@ -94,7 +83,7 @@ struct target_type { * if dynamic allocation is used for this value, it must be managed by * the target, ideally by caching the result for subsequent calls. */ - const char *(*get_gdb_arch)(struct target *target); + const char *(*get_gdb_arch)(const struct target *target); /** * Target register access for GDB. Do @b not call this function @@ -192,7 +181,7 @@ struct target_type { int (*run_algorithm)(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, target_addr_t entry_point, - target_addr_t exit_point, int timeout_ms, void *arch_info); + target_addr_t exit_point, unsigned int timeout_ms, void *arch_info); int (*start_algorithm)(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, target_addr_t entry_point, @@ -200,7 +189,7 @@ struct target_type { int (*wait_algorithm)(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, target_addr_t exit_point, - int timeout_ms, void *arch_info); + unsigned int timeout_ms, void *arch_info); const struct command_registration *commands; @@ -242,6 +231,17 @@ struct target_type { /** * Free all the resources allocated by the target. * + * WARNING: deinit_target is called unconditionally regardless the target has + * ever been examined/initialised or not. + * If a problem has prevented establishing JTAG/SWD/... communication + * or + * if the target was created with -defer-examine flag and has never been + * examined + * then it is not possible to communicate with the target. + * + * If you need to talk to the target during deinit, first check if + * target_was_examined()! + * * @param target The target to deinit */ void (*deinit_target)(struct target *target); @@ -286,6 +286,15 @@ struct target_type { */ int (*gdb_fileio_end)(struct target *target, int retcode, int fileio_errno, bool ctrl_c); + /* Parse target-specific GDB query commands. + * The string pointer "response_p" is always assigned by the called function + * to a pointer to a NULL-terminated string, even when the function returns + * an error. The string memory is not freed by the caller, so this function + * must pay attention for possible memory leaks if the string memory is + * dynamically allocated. + */ + int (*gdb_query_custom)(struct target *target, const char *packet, char **response_p); + /* do target profiling */ int (*profiling)(struct target *target, uint32_t *samples, @@ -302,4 +311,44 @@ struct target_type { unsigned int (*data_bits)(struct target *target); }; +extern struct target_type aarch64_target; +extern struct target_type arcv2_target; +extern struct target_type arm11_target; +extern struct target_type arm720t_target; +extern struct target_type arm7tdmi_target; +extern struct target_type arm920t_target; +extern struct target_type arm926ejs_target; +extern struct target_type arm946e_target; +extern struct target_type arm966e_target; +extern struct target_type arm9tdmi_target; +extern struct target_type armv8r_target; +extern struct target_type avr32_ap7k_target; +extern struct target_type avr_target; +extern struct target_type cortexa_target; +extern struct target_type cortexm_target; +extern struct target_type cortexr4_target; +extern struct target_type dragonite_target; +extern struct target_type dsp563xx_target; +extern struct target_type dsp5680xx_target; +extern struct target_type esirisc_target; +extern struct target_type esp32s2_target; +extern struct target_type esp32s3_target; +extern struct target_type esp32_target; +extern struct target_type fa526_target; +extern struct target_type feroceon_target; +extern struct target_type hla_target; +extern struct target_type ls1_sap_target; +extern struct target_type mem_ap_target; +extern struct target_type mips_m4k_target; +extern struct target_type mips_mips64_target; +extern struct target_type or1k_target; +extern struct target_type quark_d20xx_target; +extern struct target_type quark_x10xx_target; +extern struct target_type riscv_target; +extern struct target_type stm8_target; +extern struct target_type testee_target; +extern struct target_type vexriscv_target; +extern struct target_type xscale_target; +extern struct target_type xtensa_chip_target; + #endif /* OPENOCD_TARGET_TARGET_TYPE_H */ diff --git a/src/target/testee.c b/src/target/testee.c index 236ac9aba9..687565271d 100644 --- a/src/target/testee.c +++ b/src/target/testee.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/trace.c b/src/target/trace.c index f2ceb03d95..333a787f92 100644 --- a/src/target/trace.c +++ b/src/target/trace.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H diff --git a/src/target/trace.h b/src/target/trace.h index 45308c0d8e..e3d787eddf 100644 --- a/src/target/trace.h +++ b/src/target/trace.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_TRACE_H diff --git a/src/target/vexriscv.c b/src/target/vexriscv.c index 100f660f0f..62f360889b 100644 --- a/src/target/vexriscv.c +++ b/src/target/vexriscv.c @@ -2190,12 +2190,10 @@ static int vexriscv_run_and_wait(struct target *target, target_addr_t entry_poin return ERROR_OK; } - - int vexriscv_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, - target_addr_t exit_point, int timeout_ms, void *arch_info){ + target_addr_t exit_point, unsigned int timeout_ms, void *arch_info){ struct vexriscv_common *vexriscv = target_to_vexriscv(target); int retval; LOG_DEBUG("Running algorithm"); @@ -2380,7 +2378,7 @@ static const struct command_registration vexriscv_exec_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -extern const struct command_registration semihosting_common_handlers[]; +//extern const struct command_registration semihosting_common_handlers[]; const struct command_registration vexriscv_command_handlers[] = { { diff --git a/src/target/x86_32_common.c b/src/target/x86_32_common.c index d119be148f..ecaf52b3ab 100644 --- a/src/target/x86_32_common.c +++ b/src/target/x86_32_common.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright(c) 2013 Intel Corporation. * @@ -7,19 +9,6 @@ * Julien Carreno (julien.carreno@intel.com) * Jeffrey Maxwell (jeffrey.r.maxwell@intel.com) * - * 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/>. - * * Contact Information: * Intel Corporation */ diff --git a/src/target/x86_32_common.h b/src/target/x86_32_common.h index 14e6e35f77..7392447a68 100644 --- a/src/target/x86_32_common.h +++ b/src/target/x86_32_common.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Copyright(c) 2013-2016 Intel Corporation. * @@ -7,19 +9,6 @@ * Julien Carreno (julien.carreno@intel.com) * Jeffrey Maxwell (jeffrey.r.maxwell@intel.com) * - * 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/>. - * * Contact Information: * Intel Corporation */ @@ -159,7 +148,7 @@ enum { PMCR, }; -#define X86_32_COMMON_MAGIC 0x86328632 +#define X86_32_COMMON_MAGIC 0x86328632U enum { /* memory read/write */ @@ -211,7 +200,8 @@ struct swbp_mem_patch { #define NUM_PM_REGS 18 /* regs used in save/restore */ struct x86_32_common { - uint32_t common_magic; + unsigned int common_magic; + void *arch_info; enum x86_core_type core_type; struct reg_cache *cache; diff --git a/src/target/xscale.c b/src/target/xscale.c index 78bd09922e..fbf43516d0 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2006, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -7,19 +9,6 @@ * * * Copyright (C) 2009 Michael Schwingen * * michael@schwingen.org * - * * - * 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/>. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -1129,7 +1118,7 @@ static int xscale_resume(struct target *target, int current, LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1393,7 +1382,7 @@ static int xscale_step(struct target *target, int current, int retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1643,7 +1632,7 @@ static int xscale_full_context(struct target *target) LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1716,7 +1705,7 @@ static int xscale_restore_banked(struct target *target) int i, j; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1792,7 +1781,7 @@ static int xscale_read_memory(struct target *target, target_addr_t address, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1891,7 +1880,7 @@ static int xscale_write_memory(struct target *target, target_addr_t address, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2084,7 +2073,7 @@ static int xscale_set_breakpoint(struct target *target, struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2174,7 +2163,7 @@ static int xscale_unset_breakpoint(struct target *target, struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2221,7 +2210,7 @@ static int xscale_remove_breakpoint(struct target *target, struct breakpoint *br struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { - LOG_ERROR("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2243,7 +2232,7 @@ static int xscale_set_watchpoint(struct target *target, uint32_t dbcon_value = buf_get_u32(dbcon->value, 0, 32); if (target->state != TARGET_HALTED) { - LOG_ERROR("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2307,7 +2296,7 @@ static int xscale_add_watchpoint(struct target *target, return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - if (watchpoint->value) + if (watchpoint->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) LOG_WARNING("xscale does not support value, mask arguments; ignoring"); /* check that length is a power of two */ @@ -2347,7 +2336,7 @@ static int xscale_unset_watchpoint(struct target *target, uint32_t dbcon_value = buf_get_u32(dbcon->value, 0, 32); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2380,7 +2369,7 @@ static int xscale_remove_watchpoint(struct target *target, struct watchpoint *wa struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { - LOG_ERROR("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2501,7 +2490,7 @@ static int xscale_read_trace(struct target *target) unsigned int num_checkpoints = 0; if (target->state != TARGET_HALTED) { - LOG_WARNING("target must be stopped to read trace data"); + LOG_TARGET_ERROR(target, "must be stopped to read trace data"); return ERROR_TARGET_NOT_HALTED; } @@ -3142,8 +3131,8 @@ static int xscale_mmu(struct target *target, int *enabled) struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_INVALID; + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; } *enabled = xscale->armv4_5_mmu.mmu_enabled; return ERROR_OK; @@ -3160,8 +3149,8 @@ COMMAND_HANDLER(xscale_handle_mmu_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } if (CMD_ARGC >= 1) { @@ -3190,8 +3179,8 @@ COMMAND_HANDLER(xscale_handle_idcache_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } bool icache = false; @@ -3358,8 +3347,8 @@ COMMAND_HANDLER(xscale_handle_trace_buffer_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } if (CMD_ARGC >= 1) { @@ -3462,8 +3451,8 @@ COMMAND_HANDLER(xscale_handle_dump_trace_command) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } if (CMD_ARGC < 1) @@ -3525,8 +3514,8 @@ COMMAND_HANDLER(xscale_handle_cp15) return retval; if (target->state != TARGET_HALTED) { - command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; + command_print(CMD, "Error: target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_TARGET_NOT_HALTED; } uint32_t reg_no = 0; struct reg *reg = NULL; diff --git a/src/target/xscale.h b/src/target/xscale.h index a86edb2fba..36a69bca39 100644 --- a/src/target/xscale.h +++ b/src/target/xscale.h @@ -1,22 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_TARGET_XSCALE_H @@ -26,7 +15,7 @@ #include "armv4_5_mmu.h" #include "trace.h" -#define XSCALE_COMMON_MAGIC 0x58534341 +#define XSCALE_COMMON_MAGIC 0x58534341U /* These four JTAG instructions are architecturally defined. * Lengths are core-specific; originally 5 bits, later 7. @@ -82,11 +71,11 @@ struct xscale_trace { }; struct xscale_common { + unsigned int common_magic; + /* armv4/5 common stuff */ struct arm arm; - int common_magic; - /* XScale registers (CP15, DBG) */ struct reg_cache *reg_cache; diff --git a/src/target/xtensa/Makefile.am b/src/target/xtensa/Makefile.am new file mode 100644 index 0000000000..22504e78b2 --- /dev/null +++ b/src/target/xtensa/Makefile.am @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +noinst_LTLIBRARIES += %D%/libxtensa.la +%C%_libxtensa_la_SOURCES = \ + %D%/xtensa.c \ + %D%/xtensa.h \ + %D%/xtensa_chip.c \ + %D%/xtensa_chip.h \ + %D%/xtensa_debug_module.c \ + %D%/xtensa_debug_module.h \ + %D%/xtensa_fileio.c \ + %D%/xtensa_fileio.h \ + %D%/xtensa_regs.h diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c new file mode 100644 index 0000000000..fb7748aa2d --- /dev/null +++ b/src/target/xtensa/xtensa.c @@ -0,0 +1,4550 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Generic Xtensa target API for OpenOCD * + * Copyright (C) 2020-2022 Cadence Design Systems, Inc. * + * Copyright (C) 2016-2019 Espressif Systems Ltd. * + * Derived from esp108.c * + * Author: Angus Gratton gus@projectgus.com * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <helper/time_support.h> +#include <helper/align.h> +#include <target/register.h> +#include <target/algorithm.h> + +#include "xtensa_chip.h" +#include "xtensa.h" + +/* Swap 4-bit Xtensa opcodes and fields */ +#define XT_NIBSWAP8(V) \ + ((((V) & 0x0F) << 4) \ + | (((V) & 0xF0) >> 4)) + +#define XT_NIBSWAP16(V) \ + ((((V) & 0x000F) << 12) \ + | (((V) & 0x00F0) << 4) \ + | (((V) & 0x0F00) >> 4) \ + | (((V) & 0xF000) >> 12)) + +#define XT_NIBSWAP24(V) \ + ((((V) & 0x00000F) << 20) \ + | (((V) & 0x0000F0) << 12) \ + | (((V) & 0x000F00) << 4) \ + | (((V) & 0x00F000) >> 4) \ + | (((V) & 0x0F0000) >> 12) \ + | (((V) & 0xF00000) >> 20)) + +/* _XT_INS_FORMAT_*() + * Instruction formatting converted from little-endian inputs + * and shifted to the MSB-side of DIR for BE systems. + */ +#define _XT_INS_FORMAT_RSR(X, OPCODE, SR, T) \ + (XT_ISBE(X) ? (XT_NIBSWAP24(OPCODE) \ + | (((T) & 0x0F) << 16) \ + | (((SR) & 0xFF) << 8)) << 8 \ + : (OPCODE) \ + | (((SR) & 0xFF) << 8) \ + | (((T) & 0x0F) << 4)) + +#define _XT_INS_FORMAT_RRR(X, OPCODE, ST, R) \ + (XT_ISBE(X) ? (XT_NIBSWAP24(OPCODE) \ + | ((XT_NIBSWAP8((ST) & 0xFF)) << 12) \ + | (((R) & 0x0F) << 8)) << 8 \ + : (OPCODE) \ + | (((ST) & 0xFF) << 4) \ + | (((R) & 0x0F) << 12)) + +#define _XT_INS_FORMAT_RRRN(X, OPCODE, S, T, IMM4) \ + (XT_ISBE(X) ? (XT_NIBSWAP16(OPCODE) \ + | (((T) & 0x0F) << 8) \ + | (((S) & 0x0F) << 4) \ + | ((IMM4) & 0x0F)) << 16 \ + : (OPCODE) \ + | (((T) & 0x0F) << 4) \ + | (((S) & 0x0F) << 8) \ + | (((IMM4) & 0x0F) << 12)) + +#define _XT_INS_FORMAT_RRI8(X, OPCODE, R, S, T, IMM8) \ + (XT_ISBE(X) ? (XT_NIBSWAP24(OPCODE) \ + | (((T) & 0x0F) << 16) \ + | (((S) & 0x0F) << 12) \ + | (((R) & 0x0F) << 8) \ + | ((IMM8) & 0xFF)) << 8 \ + : (OPCODE) \ + | (((IMM8) & 0xFF) << 16) \ + | (((R) & 0x0F) << 12) \ + | (((S) & 0x0F) << 8) \ + | (((T) & 0x0F) << 4)) + +#define _XT_INS_FORMAT_RRI4(X, OPCODE, IMM4, R, S, T) \ + (XT_ISBE(X) ? (XT_NIBSWAP24(OPCODE) \ + | (((T) & 0x0F) << 16) \ + | (((S) & 0x0F) << 12) \ + | (((R) & 0x0F) << 8)) << 8 \ + | ((IMM4) & 0x0F) \ + : (OPCODE) \ + | (((IMM4) & 0x0F) << 20) \ + | (((R) & 0x0F) << 12) \ + | (((S) & 0x0F) << 8) \ + | (((T) & 0x0F) << 4)) + +/* Xtensa processor instruction opcodes +*/ +/* "Return From Debug Operation" to Normal */ +#define XT_INS_RFDO(X) (XT_ISBE(X) ? 0x000e1f << 8 : 0xf1e000) +/* "Return From Debug and Dispatch" - allow sw debugging stuff to take over */ +#define XT_INS_RFDD(X) (XT_ISBE(X) ? 0x010e1f << 8 : 0xf1e010) + +/* Load to DDR register, increase addr register */ +#define XT_INS_LDDR32P(X, S) (XT_ISBE(X) ? (0x0E0700 | ((S) << 12)) << 8 : (0x0070E0 | ((S) << 8))) +/* Store from DDR register, increase addr register */ +#define XT_INS_SDDR32P(X, S) (XT_ISBE(X) ? (0x0F0700 | ((S) << 12)) << 8 : (0x0070F0 | ((S) << 8))) + +/* Load 32-bit Indirect from A(S)+4*IMM8 to A(T) */ +#define XT_INS_L32I(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x002002, 0, S, T, IMM8) +/* Load 16-bit Unsigned from A(S)+2*IMM8 to A(T) */ +#define XT_INS_L16UI(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x001002, 0, S, T, IMM8) +/* Load 8-bit Unsigned from A(S)+IMM8 to A(T) */ +#define XT_INS_L8UI(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x000002, 0, S, T, IMM8) + +/* Store 32-bit Indirect to A(S)+4*IMM8 from A(T) */ +#define XT_INS_S32I(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x006002, 0, S, T, IMM8) +/* Store 16-bit to A(S)+2*IMM8 from A(T) */ +#define XT_INS_S16I(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x005002, 0, S, T, IMM8) +/* Store 8-bit to A(S)+IMM8 from A(T) */ +#define XT_INS_S8I(X, S, T, IMM8) _XT_INS_FORMAT_RRI8(X, 0x004002, 0, S, T, IMM8) + +/* Cache Instructions */ +#define XT_INS_IHI(X, S, IMM8) _XT_INS_FORMAT_RRI8(X, 0x0070E2, 0, S, 0, IMM8) +#define XT_INS_DHWBI(X, S, IMM8) _XT_INS_FORMAT_RRI8(X, 0x007052, 0, S, 0, IMM8) +#define XT_INS_DHWB(X, S, IMM8) _XT_INS_FORMAT_RRI8(X, 0x007042, 0, S, 0, IMM8) +#define XT_INS_ISYNC(X) (XT_ISBE(X) ? 0x000200 << 8 : 0x002000) + +/* Control Instructions */ +#define XT_INS_JX(X, S) (XT_ISBE(X) ? (0x050000 | ((S) << 12)) : (0x0000a0 | ((S) << 8))) +#define XT_INS_CALL0(X, IMM18) (XT_ISBE(X) ? (0x500000 | ((IMM18) & 0x3ffff)) : (0x000005 | (((IMM18) & 0x3ffff) << 6))) + +/* Read Special Register */ +#define XT_INS_RSR(X, SR, T) _XT_INS_FORMAT_RSR(X, 0x030000, SR, T) +/* Write Special Register */ +#define XT_INS_WSR(X, SR, T) _XT_INS_FORMAT_RSR(X, 0x130000, SR, T) +/* Swap Special Register */ +#define XT_INS_XSR(X, SR, T) _XT_INS_FORMAT_RSR(X, 0x610000, SR, T) + +/* Rotate Window by (-8..7) */ +#define XT_INS_ROTW(X, N) (XT_ISBE(X) ? ((0x000804) | (((N) & 15) << 16)) << 8 : ((0x408000) | (((N) & 15) << 4))) + +/* Read User Register */ +#define XT_INS_RUR(X, UR, T) _XT_INS_FORMAT_RRR(X, 0xE30000, UR, T) +/* Write User Register */ +#define XT_INS_WUR(X, UR, T) _XT_INS_FORMAT_RSR(X, 0xF30000, UR, T) + +/* Read Floating-Point Register */ +#define XT_INS_RFR(X, FR, T) _XT_INS_FORMAT_RRR(X, 0xFA0000, ((FR << 4) | 0x4), T) +/* Write Floating-Point Register */ +#define XT_INS_WFR(X, FR, T) _XT_INS_FORMAT_RRR(X, 0xFA0000, ((T << 4) | 0x5), FR) + +#define XT_INS_L32E(X, R, S, T) _XT_INS_FORMAT_RRI4(X, 0x090000, 0, R, S, T) +#define XT_INS_S32E(X, R, S, T) _XT_INS_FORMAT_RRI4(X, 0x490000, 0, R, S, T) +#define XT_INS_L32E_S32E_MASK(X) (XT_ISBE(X) ? 0xF000FF << 8 : 0xFF000F) + +#define XT_INS_RFWO(X) (XT_ISBE(X) ? 0x004300 << 8 : 0x003400) +#define XT_INS_RFWU(X) (XT_ISBE(X) ? 0x005300 << 8 : 0x003500) +#define XT_INS_RFWO_RFWU_MASK(X) (XT_ISBE(X) ? 0xFFFFFF << 8 : 0xFFFFFF) + +#define XT_WATCHPOINTS_NUM_MAX 2 + +/* Special register number macro for DDR, PS, WB, A3, A4 registers. + * These get used a lot so making a shortcut is useful. + */ +#define XT_SR_DDR (xtensa_regs[XT_REG_IDX_DDR].reg_num) +#define XT_SR_PS (xtensa_regs[XT_REG_IDX_PS].reg_num) +#define XT_SR_WB (xtensa_regs[XT_REG_IDX_WINDOWBASE].reg_num) +#define XT_REG_A0 (xtensa_regs[XT_REG_IDX_AR0].reg_num) +#define XT_REG_A3 (xtensa_regs[XT_REG_IDX_AR3].reg_num) +#define XT_REG_A4 (xtensa_regs[XT_REG_IDX_AR4].reg_num) + +#define XT_PS_REG_NUM (0xe6U) +#define XT_EPS_REG_NUM_BASE (0xc0U) /* (EPS2 - 2), for adding DBGLEVEL */ +#define XT_EPC_REG_NUM_BASE (0xb0U) /* (EPC1 - 1), for adding DBGLEVEL */ +#define XT_PC_REG_NUM_VIRTUAL (0xffU) /* Marker for computing PC (EPC[DBGLEVEL) */ +#define XT_PC_DBREG_NUM_BASE (0x20U) /* External (i.e., GDB) access */ +#define XT_NX_IBREAKC_BASE (0xc0U) /* (IBREAKC0..IBREAKC1) for NX */ + +#define XT_SW_BREAKPOINTS_MAX_NUM 32 +#define XT_HW_IBREAK_MAX_NUM 2 +#define XT_HW_DBREAK_MAX_NUM 2 + +struct xtensa_reg_desc xtensa_regs[XT_NUM_REGS] = { + XT_MK_REG_DESC("pc", XT_PC_REG_NUM_VIRTUAL, XT_REG_SPECIAL, 0), + XT_MK_REG_DESC("ar0", 0x00, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar1", 0x01, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar2", 0x02, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar3", 0x03, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar4", 0x04, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar5", 0x05, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar6", 0x06, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar7", 0x07, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar8", 0x08, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar9", 0x09, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar10", 0x0A, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar11", 0x0B, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar12", 0x0C, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar13", 0x0D, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar14", 0x0E, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar15", 0x0F, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar16", 0x10, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar17", 0x11, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar18", 0x12, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar19", 0x13, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar20", 0x14, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar21", 0x15, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar22", 0x16, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar23", 0x17, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar24", 0x18, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar25", 0x19, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar26", 0x1A, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar27", 0x1B, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar28", 0x1C, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar29", 0x1D, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar30", 0x1E, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar31", 0x1F, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar32", 0x20, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar33", 0x21, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar34", 0x22, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar35", 0x23, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar36", 0x24, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar37", 0x25, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar38", 0x26, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar39", 0x27, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar40", 0x28, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar41", 0x29, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar42", 0x2A, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar43", 0x2B, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar44", 0x2C, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar45", 0x2D, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar46", 0x2E, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar47", 0x2F, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar48", 0x30, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar49", 0x31, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar50", 0x32, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar51", 0x33, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar52", 0x34, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar53", 0x35, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar54", 0x36, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar55", 0x37, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar56", 0x38, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar57", 0x39, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar58", 0x3A, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar59", 0x3B, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar60", 0x3C, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar61", 0x3D, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar62", 0x3E, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("ar63", 0x3F, XT_REG_GENERAL, 0), + XT_MK_REG_DESC("windowbase", 0x48, XT_REG_SPECIAL, 0), + XT_MK_REG_DESC("windowstart", 0x49, XT_REG_SPECIAL, 0), + XT_MK_REG_DESC("ps", XT_PS_REG_NUM, XT_REG_SPECIAL, 0), /* PS (not mapped through EPS[]) */ + XT_MK_REG_DESC("ibreakenable", 0x60, XT_REG_SPECIAL, 0), + XT_MK_REG_DESC("ddr", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD), + XT_MK_REG_DESC("ibreaka0", 0x80, XT_REG_SPECIAL, 0), + XT_MK_REG_DESC("ibreaka1", 0x81, XT_REG_SPECIAL, 0), + XT_MK_REG_DESC("dbreaka0", 0x90, XT_REG_SPECIAL, 0), + XT_MK_REG_DESC("dbreaka1", 0x91, XT_REG_SPECIAL, 0), + XT_MK_REG_DESC("dbreakc0", 0xA0, XT_REG_SPECIAL, 0), + XT_MK_REG_DESC("dbreakc1", 0xA1, XT_REG_SPECIAL, 0), + XT_MK_REG_DESC("cpenable", 0xE0, XT_REG_SPECIAL, 0), + XT_MK_REG_DESC("exccause", 0xE8, XT_REG_SPECIAL, 0), + XT_MK_REG_DESC("debugcause", 0xE9, XT_REG_SPECIAL, 0), + XT_MK_REG_DESC("icount", 0xEC, XT_REG_SPECIAL, 0), + XT_MK_REG_DESC("icountlevel", 0xED, XT_REG_SPECIAL, 0), + + /* WARNING: For these registers, regnum points to the + * index of the corresponding ARx registers, NOT to + * the processor register number! */ + XT_MK_REG_DESC("a0", XT_REG_IDX_AR0, XT_REG_RELGEN, 0), + XT_MK_REG_DESC("a1", XT_REG_IDX_AR1, XT_REG_RELGEN, 0), + XT_MK_REG_DESC("a2", XT_REG_IDX_AR2, XT_REG_RELGEN, 0), + XT_MK_REG_DESC("a3", XT_REG_IDX_AR3, XT_REG_RELGEN, 0), + XT_MK_REG_DESC("a4", XT_REG_IDX_AR4, XT_REG_RELGEN, 0), + XT_MK_REG_DESC("a5", XT_REG_IDX_AR5, XT_REG_RELGEN, 0), + XT_MK_REG_DESC("a6", XT_REG_IDX_AR6, XT_REG_RELGEN, 0), + XT_MK_REG_DESC("a7", XT_REG_IDX_AR7, XT_REG_RELGEN, 0), + XT_MK_REG_DESC("a8", XT_REG_IDX_AR8, XT_REG_RELGEN, 0), + XT_MK_REG_DESC("a9", XT_REG_IDX_AR9, XT_REG_RELGEN, 0), + XT_MK_REG_DESC("a10", XT_REG_IDX_AR10, XT_REG_RELGEN, 0), + XT_MK_REG_DESC("a11", XT_REG_IDX_AR11, XT_REG_RELGEN, 0), + XT_MK_REG_DESC("a12", XT_REG_IDX_AR12, XT_REG_RELGEN, 0), + XT_MK_REG_DESC("a13", XT_REG_IDX_AR13, XT_REG_RELGEN, 0), + XT_MK_REG_DESC("a14", XT_REG_IDX_AR14, XT_REG_RELGEN, 0), + XT_MK_REG_DESC("a15", XT_REG_IDX_AR15, XT_REG_RELGEN, 0), +}; + +/** + * Types of memory used at xtensa target + */ +enum xtensa_mem_region_type { + XTENSA_MEM_REG_IROM = 0x0, + XTENSA_MEM_REG_IRAM, + XTENSA_MEM_REG_DROM, + XTENSA_MEM_REG_DRAM, + XTENSA_MEM_REG_SRAM, + XTENSA_MEM_REG_SROM, + XTENSA_MEM_REGS_NUM +}; + +/* Register definition as union for list allocation */ +union xtensa_reg_val_u { + xtensa_reg_val_t val; + uint8_t buf[4]; +}; + +static const struct xtensa_keyval_info_s xt_qerr[XT_QERR_NUM] = { + { .chrval = "E00", .intval = ERROR_FAIL }, + { .chrval = "E01", .intval = ERROR_FAIL }, + { .chrval = "E02", .intval = ERROR_COMMAND_ARGUMENT_INVALID }, + { .chrval = "E03", .intval = ERROR_FAIL }, +}; + +/* Set to true for extra debug logging */ +static const bool xtensa_extra_debug_log; + +/** + * Gets a config for the specific mem type + */ +static inline const struct xtensa_local_mem_config *xtensa_get_mem_config( + struct xtensa *xtensa, + enum xtensa_mem_region_type type) +{ + switch (type) { + case XTENSA_MEM_REG_IROM: + return &xtensa->core_config->irom; + case XTENSA_MEM_REG_IRAM: + return &xtensa->core_config->iram; + case XTENSA_MEM_REG_DROM: + return &xtensa->core_config->drom; + case XTENSA_MEM_REG_DRAM: + return &xtensa->core_config->dram; + case XTENSA_MEM_REG_SRAM: + return &xtensa->core_config->sram; + case XTENSA_MEM_REG_SROM: + return &xtensa->core_config->srom; + default: + return NULL; + } +} + +/** + * Extracts an exact xtensa_local_mem_region_config from xtensa_local_mem_config + * for a given address + * Returns NULL if nothing found + */ +static inline const struct xtensa_local_mem_region_config *xtensa_memory_region_find( + const struct xtensa_local_mem_config *mem, + target_addr_t address) +{ + for (unsigned int i = 0; i < mem->count; i++) { + const struct xtensa_local_mem_region_config *region = &mem->regions[i]; + if (address >= region->base && address < (region->base + region->size)) + return region; + } + return NULL; +} + +/** + * Returns a corresponding xtensa_local_mem_region_config from the xtensa target + * for a given address + * Returns NULL if nothing found + */ +static inline const struct xtensa_local_mem_region_config *xtensa_target_memory_region_find( + struct xtensa *xtensa, + target_addr_t address) +{ + const struct xtensa_local_mem_region_config *result; + const struct xtensa_local_mem_config *mcgf; + for (unsigned int mtype = 0; mtype < XTENSA_MEM_REGS_NUM; mtype++) { + mcgf = xtensa_get_mem_config(xtensa, mtype); + result = xtensa_memory_region_find(mcgf, address); + if (result) + return result; + } + return NULL; +} + +static inline bool xtensa_is_cacheable(const struct xtensa_cache_config *cache, + const struct xtensa_local_mem_config *mem, + target_addr_t address) +{ + if (!cache->size) + return false; + return xtensa_memory_region_find(mem, address); +} + +static inline bool xtensa_is_icacheable(struct xtensa *xtensa, target_addr_t address) +{ + return xtensa_is_cacheable(&xtensa->core_config->icache, &xtensa->core_config->iram, address) || + xtensa_is_cacheable(&xtensa->core_config->icache, &xtensa->core_config->irom, address) || + xtensa_is_cacheable(&xtensa->core_config->icache, &xtensa->core_config->sram, address) || + xtensa_is_cacheable(&xtensa->core_config->icache, &xtensa->core_config->srom, address); +} + +static inline bool xtensa_is_dcacheable(struct xtensa *xtensa, target_addr_t address) +{ + return xtensa_is_cacheable(&xtensa->core_config->dcache, &xtensa->core_config->dram, address) || + xtensa_is_cacheable(&xtensa->core_config->dcache, &xtensa->core_config->drom, address) || + xtensa_is_cacheable(&xtensa->core_config->dcache, &xtensa->core_config->sram, address) || + xtensa_is_cacheable(&xtensa->core_config->dcache, &xtensa->core_config->srom, address); +} + +static int xtensa_core_reg_get(struct reg *reg) +{ + /* We don't need this because we read all registers on halt anyway. */ + struct xtensa *xtensa = (struct xtensa *)reg->arch_info; + struct target *target = xtensa->target; + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + if (!reg->exist) { + if (strncmp(reg->name, "?0x", 3) == 0) { + unsigned int regnum = strtoul(reg->name + 1, NULL, 0); + LOG_WARNING("Read unknown register 0x%04x ignored", regnum); + return ERROR_OK; + } + return ERROR_COMMAND_ARGUMENT_INVALID; + } + return ERROR_OK; +} + +static int xtensa_core_reg_set(struct reg *reg, uint8_t *buf) +{ + struct xtensa *xtensa = (struct xtensa *)reg->arch_info; + struct target *target = xtensa->target; + + assert(reg->size <= 64 && "up to 64-bit regs are supported only!"); + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + if (!reg->exist) { + if (strncmp(reg->name, "?0x", 3) == 0) { + unsigned int regnum = strtoul(reg->name + 1, NULL, 0); + LOG_WARNING("Write unknown register 0x%04x ignored", regnum); + return ERROR_OK; + } + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + buf_cpy(buf, reg->value, reg->size); + + if (xtensa->core_config->windowed) { + /* If the user updates a potential scratch register, track for conflicts */ + for (enum xtensa_ar_scratch_set_e s = 0; s < XT_AR_SCRATCH_NUM; s++) { + if (strcmp(reg->name, xtensa->scratch_ars[s].chrval) == 0) { + LOG_DEBUG("Scratch reg %s [0x%08" PRIx32 "] set from gdb", reg->name, + buf_get_u32(reg->value, 0, 32)); + LOG_DEBUG("scratch_ars mapping: a3/%s, a4/%s", + xtensa->scratch_ars[XT_AR_SCRATCH_AR3].chrval, + xtensa->scratch_ars[XT_AR_SCRATCH_AR4].chrval); + xtensa->scratch_ars[s].intval = true; + break; + } + } + } + reg->dirty = true; + reg->valid = true; + + return ERROR_OK; +} + +static const struct reg_arch_type xtensa_reg_type = { + .get = xtensa_core_reg_get, + .set = xtensa_core_reg_set, +}; + +/* Convert a register index that's indexed relative to windowbase, to the real address. */ +static enum xtensa_reg_id xtensa_windowbase_offset_to_canonical(struct xtensa *xtensa, + enum xtensa_reg_id reg_idx, + int windowbase) +{ + unsigned int idx; + if (reg_idx >= XT_REG_IDX_AR0 && reg_idx <= XT_REG_IDX_ARLAST) { + idx = reg_idx - XT_REG_IDX_AR0; + } else if (reg_idx >= XT_REG_IDX_A0 && reg_idx <= XT_REG_IDX_A15) { + idx = reg_idx - XT_REG_IDX_A0; + } else { + LOG_ERROR("Error: can't convert register %d to non-windowbased register!", reg_idx); + return -1; + } + /* Each windowbase value represents 4 registers on LX and 8 on NX */ + int base_inc = (xtensa->core_config->core_type == XT_LX) ? 4 : 8; + return ((idx + windowbase * base_inc) & (xtensa->core_config->aregs_num - 1)) + XT_REG_IDX_AR0; +} + +static enum xtensa_reg_id xtensa_canonical_to_windowbase_offset(struct xtensa *xtensa, + enum xtensa_reg_id reg_idx, + int windowbase) +{ + return xtensa_windowbase_offset_to_canonical(xtensa, reg_idx, -windowbase); +} + +static void xtensa_mark_register_dirty(struct xtensa *xtensa, enum xtensa_reg_id reg_idx) +{ + struct reg *reg_list = xtensa->core_cache->reg_list; + reg_list[reg_idx].dirty = true; +} + +static void xtensa_queue_exec_ins(struct xtensa *xtensa, uint32_t ins) +{ + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DIR0EXEC, ins); +} + +static void xtensa_queue_exec_ins_wide(struct xtensa *xtensa, uint8_t *ops, uint8_t oplen) +{ + const int max_oplen = 64; /* 8 DIRx regs: max width 64B */ + if ((oplen > 0) && (oplen <= max_oplen)) { + uint8_t ops_padded[max_oplen]; + memcpy(ops_padded, ops, oplen); + memset(ops_padded + oplen, 0, max_oplen - oplen); + unsigned int oplenw = DIV_ROUND_UP(oplen, sizeof(uint32_t)); + for (int32_t i = oplenw - 1; i > 0; i--) + xtensa_queue_dbg_reg_write(xtensa, + XDMREG_DIR0 + i, + target_buffer_get_u32(xtensa->target, &ops_padded[sizeof(uint32_t)*i])); + /* Write DIR0EXEC last */ + xtensa_queue_dbg_reg_write(xtensa, + XDMREG_DIR0EXEC, + target_buffer_get_u32(xtensa->target, &ops_padded[0])); + } +} + +static int xtensa_queue_pwr_reg_write(struct xtensa *xtensa, unsigned int reg, uint32_t data) +{ + struct xtensa_debug_module *dm = &xtensa->dbg_mod; + return dm->pwr_ops->queue_reg_write(dm, reg, data); +} + +/* NOTE: Assumes A3 has already been saved */ +static int xtensa_window_state_save(struct target *target, uint32_t *woe) +{ + struct xtensa *xtensa = target_to_xtensa(target); + unsigned int woe_sr = (xtensa->core_config->core_type == XT_LX) ? XT_SR_PS : XT_SR_WB; + uint32_t woe_dis; + uint8_t woe_buf[4]; + + if (xtensa->core_config->windowed) { + /* Save PS (LX) or WB (NX) and disable window overflow exceptions prior to AR save */ + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, woe_sr, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, woe_buf); + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read %s (%d)!", + (woe_sr == XT_SR_PS) ? "PS" : "WB", res); + return res; + } + xtensa_core_status_check(target); + *woe = buf_get_u32(woe_buf, 0, 32); + woe_dis = *woe & ~((woe_sr == XT_SR_PS) ? XT_PS_WOE_MSK : XT_WB_S_MSK); + LOG_TARGET_DEBUG(target, "Clearing %s (0x%08" PRIx32 " -> 0x%08" PRIx32 ")", + (woe_sr == XT_SR_PS) ? "PS.WOE" : "WB.S", *woe, woe_dis); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, woe_dis); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, woe_sr, XT_REG_A3)); + } + return ERROR_OK; +} + +/* NOTE: Assumes A3 has already been saved */ +static void xtensa_window_state_restore(struct target *target, uint32_t woe) +{ + struct xtensa *xtensa = target_to_xtensa(target); + unsigned int woe_sr = (xtensa->core_config->core_type == XT_LX) ? XT_SR_PS : XT_SR_WB; + if (xtensa->core_config->windowed) { + /* Restore window overflow exception state */ + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, woe); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, woe_sr, XT_REG_A3)); + LOG_TARGET_DEBUG(target, "Restored %s (0x%08" PRIx32 ")", + (woe_sr == XT_SR_PS) ? "PS.WOE" : "WB", woe); + } +} + +static bool xtensa_reg_is_readable(int flags, int cpenable) +{ + if (flags & XT_REGF_NOREAD) + return false; + if ((flags & XT_REGF_COPROC0) && (cpenable & BIT(0)) == 0) + return false; + return true; +} + +static bool xtensa_scratch_regs_fixup(struct xtensa *xtensa, struct reg *reg_list, int i, int j, int a_idx, int ar_idx) +{ + int a_name = (a_idx == XT_AR_SCRATCH_A3) ? 3 : 4; + if (xtensa->scratch_ars[a_idx].intval && !xtensa->scratch_ars[ar_idx].intval) { + LOG_DEBUG("AR conflict: a%d -> ar%d", a_name, j - XT_REG_IDX_AR0); + memcpy(reg_list[j].value, reg_list[i].value, sizeof(xtensa_reg_val_t)); + } else { + LOG_DEBUG("AR conflict: ar%d -> a%d", j - XT_REG_IDX_AR0, a_name); + memcpy(reg_list[i].value, reg_list[j].value, sizeof(xtensa_reg_val_t)); + } + return xtensa->scratch_ars[a_idx].intval && xtensa->scratch_ars[ar_idx].intval; +} + +static int xtensa_write_dirty_registers(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + int res; + xtensa_reg_val_t regval, windowbase = 0; + bool scratch_reg_dirty = false, delay_cpenable = false; + struct reg *reg_list = xtensa->core_cache->reg_list; + unsigned int reg_list_size = xtensa->core_cache->num_regs; + bool preserve_a3 = false; + uint8_t a3_buf[4]; + xtensa_reg_val_t a3 = 0, woe; + unsigned int ms_idx = (xtensa->core_config->core_type == XT_NX) ? + xtensa->nx_reg_idx[XT_NX_REG_IDX_MS] : reg_list_size; + xtensa_reg_val_t ms = 0; + bool restore_ms = false; + + LOG_TARGET_DEBUG(target, "start"); + + /* We need to write the dirty registers in the cache list back to the processor. + * Start by writing the SFR/user registers. */ + for (unsigned int i = 0; i < reg_list_size; i++) { + struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs; + unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS; + if (reg_list[i].dirty) { + if (rlist[ridx].type == XT_REG_SPECIAL || + rlist[ridx].type == XT_REG_USER || + rlist[ridx].type == XT_REG_FR) { + scratch_reg_dirty = true; + if (i == XT_REG_IDX_CPENABLE) { + delay_cpenable = true; + continue; + } + regval = xtensa_reg_get(target, i); + LOG_TARGET_DEBUG(target, "Writing back reg %s (%d) val %08" PRIX32, + reg_list[i].name, + rlist[ridx].reg_num, + regval); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, regval); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + if (reg_list[i].exist) { + unsigned int reg_num = rlist[ridx].reg_num; + if (rlist[ridx].type == XT_REG_USER) { + xtensa_queue_exec_ins(xtensa, XT_INS_WUR(xtensa, reg_num, XT_REG_A3)); + } else if (rlist[ridx].type == XT_REG_FR) { + xtensa_queue_exec_ins(xtensa, XT_INS_WFR(xtensa, reg_num, XT_REG_A3)); + } else {/*SFR */ + if (reg_num == XT_PC_REG_NUM_VIRTUAL) { + if (xtensa->core_config->core_type == XT_LX) { + /* reg number of PC for debug interrupt depends on NDEBUGLEVEL */ + reg_num = (XT_EPC_REG_NUM_BASE + xtensa->core_config->debug.irq_level); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, reg_num, XT_REG_A3)); + } else { + /* NX PC set through issuing a jump instruction */ + xtensa_queue_exec_ins(xtensa, XT_INS_JX(xtensa, XT_REG_A3)); + } + } else if (i == ms_idx) { + /* MS must be restored after ARs. This ensures ARs remain in correct + * order even for reversed register groups (overflow/underflow). + */ + ms = regval; + restore_ms = true; + LOG_TARGET_DEBUG(target, "Delaying MS write: 0x%x", ms); + } else { + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, reg_num, XT_REG_A3)); + } + } + } + reg_list[i].dirty = false; + } + } + } + if (scratch_reg_dirty) + xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3); + if (delay_cpenable) { + regval = xtensa_reg_get(target, XT_REG_IDX_CPENABLE); + LOG_TARGET_DEBUG(target, "Writing back reg cpenable (224) val %08" PRIX32, regval); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, regval); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, + xtensa_regs[XT_REG_IDX_CPENABLE].reg_num, + XT_REG_A3)); + reg_list[XT_REG_IDX_CPENABLE].dirty = false; + } + + preserve_a3 = (xtensa->core_config->windowed) || (xtensa->core_config->core_type == XT_NX); + if (preserve_a3) { + /* Save (windowed) A3 for scratch use */ + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, a3_buf); + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) + return res; + xtensa_core_status_check(target); + a3 = buf_get_u32(a3_buf, 0, 32); + } + + if (xtensa->core_config->windowed) { + res = xtensa_window_state_save(target, &woe); + if (res != ERROR_OK) + return res; + /* Grab the windowbase, we need it. */ + uint32_t wb_idx = (xtensa->core_config->core_type == XT_LX) ? + XT_REG_IDX_WINDOWBASE : xtensa->nx_reg_idx[XT_NX_REG_IDX_WB]; + windowbase = xtensa_reg_get(target, wb_idx); + if (xtensa->core_config->core_type == XT_NX) + windowbase = (windowbase & XT_WB_P_MSK) >> XT_WB_P_SHIFT; + + /* Check if there are mismatches between the ARx and corresponding Ax registers. + * When the user sets a register on a windowed config, xt-gdb may set the ARx + * register directly. Thus we take ARx as priority over Ax if both are dirty + * and it's unclear if the user set one over the other explicitly. + */ + for (unsigned int i = XT_REG_IDX_A0; i <= XT_REG_IDX_A15; i++) { + unsigned int j = xtensa_windowbase_offset_to_canonical(xtensa, i, windowbase); + if (reg_list[i].dirty && reg_list[j].dirty) { + if (memcmp(reg_list[i].value, reg_list[j].value, sizeof(xtensa_reg_val_t)) != 0) { + bool show_warning = true; + if (i == XT_REG_IDX_A3) + show_warning = xtensa_scratch_regs_fixup(xtensa, + reg_list, i, j, XT_AR_SCRATCH_A3, XT_AR_SCRATCH_AR3); + else if (i == XT_REG_IDX_A4) + show_warning = xtensa_scratch_regs_fixup(xtensa, + reg_list, i, j, XT_AR_SCRATCH_A4, XT_AR_SCRATCH_AR4); + if (show_warning) + LOG_WARNING( + "Warning: Both A%d [0x%08" PRIx32 + "] as well as its underlying physical register " + "(AR%d) [0x%08" PRIx32 "] are dirty and differ in value", + i - XT_REG_IDX_A0, + buf_get_u32(reg_list[i].value, 0, 32), + j - XT_REG_IDX_AR0, + buf_get_u32(reg_list[j].value, 0, 32)); + } + } + } + } + + /* Write A0-A16. */ + for (unsigned int i = 0; i < 16; i++) { + if (reg_list[XT_REG_IDX_A0 + i].dirty) { + regval = xtensa_reg_get(target, XT_REG_IDX_A0 + i); + LOG_TARGET_DEBUG(target, "Writing back reg %s value %08" PRIX32 ", num =%i", + xtensa_regs[XT_REG_IDX_A0 + i].name, + regval, + xtensa_regs[XT_REG_IDX_A0 + i].reg_num); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, regval); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, i)); + reg_list[XT_REG_IDX_A0 + i].dirty = false; + if (i == 3) { + /* Avoid stomping A3 during restore at end of function */ + a3 = regval; + } + } + } + + if (xtensa->core_config->windowed) { + /* Now write AR registers */ + for (unsigned int j = 0; j < XT_REG_IDX_ARLAST; j += 16) { + /* Write the 16 registers we can see */ + for (unsigned int i = 0; i < 16; i++) { + if (i + j < xtensa->core_config->aregs_num) { + enum xtensa_reg_id realadr = + xtensa_windowbase_offset_to_canonical(xtensa, XT_REG_IDX_AR0 + i + j, + windowbase); + /* Write back any dirty un-windowed registers */ + if (reg_list[realadr].dirty) { + regval = xtensa_reg_get(target, realadr); + LOG_TARGET_DEBUG( + target, + "Writing back reg %s value %08" PRIX32 ", num =%i", + xtensa_regs[realadr].name, + regval, + xtensa_regs[realadr].reg_num); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, regval); + xtensa_queue_exec_ins(xtensa, + XT_INS_RSR(xtensa, XT_SR_DDR, + xtensa_regs[XT_REG_IDX_AR0 + i].reg_num)); + reg_list[realadr].dirty = false; + if ((i + j) == 3) + /* Avoid stomping AR during A3 restore at end of function */ + a3 = regval; + } + } + } + + /* Now rotate the window so we'll see the next 16 registers. The final rotate + * will wraparound, leaving us in the state we were. + * Each ROTW rotates 4 registers on LX and 8 on NX */ + int rotw_arg = (xtensa->core_config->core_type == XT_LX) ? 4 : 2; + xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(xtensa, rotw_arg)); + } + + xtensa_window_state_restore(target, woe); + + for (enum xtensa_ar_scratch_set_e s = 0; s < XT_AR_SCRATCH_NUM; s++) + xtensa->scratch_ars[s].intval = false; + } + + if (restore_ms) { + uint32_t ms_regno = xtensa->optregs[ms_idx - XT_NUM_REGS].reg_num; + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, ms); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, ms_regno, XT_REG_A3)); + LOG_TARGET_DEBUG(target, "Delayed MS (0x%x) write complete: 0x%x", ms_regno, ms); + } + + if (preserve_a3) { + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, a3); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + } + + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + xtensa_core_status_check(target); + + return res; +} + +static inline bool xtensa_is_stopped(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + return xtensa->dbg_mod.core_status.dsr & OCDDSR_STOPPED; +} + +int xtensa_examine(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + unsigned int cmd = PWRCTL_DEBUGWAKEUP(xtensa) | PWRCTL_MEMWAKEUP(xtensa) | PWRCTL_COREWAKEUP(xtensa); + + LOG_TARGET_DEBUG(target, ""); + + if (xtensa->core_config->core_type == XT_UNDEF) { + LOG_ERROR("XTensa core not configured; is xtensa-core-openocd.cfg missing?"); + return ERROR_FAIL; + } + + xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd); + xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd | PWRCTL_JTAGDEBUGUSE(xtensa)); + xtensa_dm_queue_enable(&xtensa->dbg_mod); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) + return res; + if (!xtensa_dm_is_online(&xtensa->dbg_mod)) { + LOG_ERROR("Unexpected OCD_ID = %08" PRIx32, xtensa->dbg_mod.device_id); + return ERROR_TARGET_FAILURE; + } + LOG_DEBUG("OCD_ID = %08" PRIx32, xtensa->dbg_mod.device_id); + target_set_examined(target); + xtensa_smpbreak_write(xtensa, xtensa->smp_break); + return ERROR_OK; +} + +int xtensa_wakeup(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + unsigned int cmd = PWRCTL_DEBUGWAKEUP(xtensa) | PWRCTL_MEMWAKEUP(xtensa) | PWRCTL_COREWAKEUP(xtensa); + + if (xtensa->reset_asserted) + cmd |= PWRCTL_CORERESET(xtensa); + xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd); + /* TODO: can we join this with the write above? */ + xtensa_queue_pwr_reg_write(xtensa, XDMREG_PWRCTL, cmd | PWRCTL_JTAGDEBUGUSE(xtensa)); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + return xtensa_dm_queue_execute(&xtensa->dbg_mod); +} + +int xtensa_smpbreak_write(struct xtensa *xtensa, uint32_t set) +{ + uint32_t dsr_data = 0x00110000; + uint32_t clear = (set | OCDDCR_ENABLEOCD) ^ + (OCDDCR_BREAKINEN | OCDDCR_BREAKOUTEN | OCDDCR_RUNSTALLINEN | + OCDDCR_DEBUGMODEOUTEN | OCDDCR_ENABLEOCD); + + LOG_TARGET_DEBUG(xtensa->target, "write smpbreak set=0x%" PRIx32 " clear=0x%" PRIx32, set, clear); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DCRSET, set | OCDDCR_ENABLEOCD); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DCRCLR, clear); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DSR, dsr_data); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + return xtensa_dm_queue_execute(&xtensa->dbg_mod); +} + +int xtensa_smpbreak_set(struct target *target, uint32_t set) +{ + struct xtensa *xtensa = target_to_xtensa(target); + int res = ERROR_OK; + + xtensa->smp_break = set; + if (target_was_examined(target)) + res = xtensa_smpbreak_write(xtensa, xtensa->smp_break); + LOG_TARGET_DEBUG(target, "set smpbreak=%" PRIx32 ", state=%i", set, target->state); + return res; +} + +int xtensa_smpbreak_read(struct xtensa *xtensa, uint32_t *val) +{ + uint8_t dcr_buf[sizeof(uint32_t)]; + + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DCRSET, dcr_buf); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + *val = buf_get_u32(dcr_buf, 0, 32); + + return res; +} + +int xtensa_smpbreak_get(struct target *target, uint32_t *val) +{ + struct xtensa *xtensa = target_to_xtensa(target); + *val = xtensa->smp_break; + return ERROR_OK; +} + +static inline xtensa_reg_val_t xtensa_reg_get_value(struct reg *reg) +{ + return buf_get_u32(reg->value, 0, 32); +} + +static inline void xtensa_reg_set_value(struct reg *reg, xtensa_reg_val_t value) +{ + buf_set_u32(reg->value, 0, 32, value); + reg->dirty = true; +} + +static int xtensa_imprecise_exception_occurred(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + for (enum xtensa_nx_reg_idx idx = XT_NX_REG_IDX_IEVEC; idx <= XT_NX_REG_IDX_MESR; idx++) { + enum xtensa_reg_id ridx = xtensa->nx_reg_idx[idx]; + if (xtensa->nx_reg_idx[idx]) { + xtensa_reg_val_t reg = xtensa_reg_get(target, xtensa->nx_reg_idx[idx]); + if (reg & XT_IMPR_EXC_MSK) { + LOG_TARGET_DEBUG(target, "Imprecise exception: %s: 0x%x", + xtensa->core_cache->reg_list[ridx].name, reg); + return true; + } + } + } + return false; +} + +static void xtensa_imprecise_exception_clear(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + for (enum xtensa_nx_reg_idx idx = XT_NX_REG_IDX_IEVEC; idx <= XT_NX_REG_IDX_MESRCLR; idx++) { + enum xtensa_reg_id ridx = xtensa->nx_reg_idx[idx]; + if (ridx && idx != XT_NX_REG_IDX_MESR) { + xtensa_reg_val_t value = (idx == XT_NX_REG_IDX_MESRCLR) ? XT_MESRCLR_IMPR_EXC_MSK : 0; + xtensa_reg_set(target, ridx, value); + LOG_TARGET_DEBUG(target, "Imprecise exception: clearing %s (0x%x)", + xtensa->core_cache->reg_list[ridx].name, value); + } + } +} + +int xtensa_core_status_check(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + int res, needclear = 0, needimprclear = 0; + + xtensa_dm_core_status_read(&xtensa->dbg_mod); + xtensa_dsr_t dsr = xtensa_dm_core_status_get(&xtensa->dbg_mod); + LOG_TARGET_DEBUG(target, "DSR (%08" PRIX32 ")", dsr); + if (dsr & OCDDSR_EXECBUSY) { + if (!xtensa->suppress_dsr_errors) + LOG_TARGET_ERROR(target, "DSR (%08" PRIX32 ") indicates target still busy!", dsr); + needclear = 1; + } + if (dsr & OCDDSR_EXECEXCEPTION) { + if (!xtensa->suppress_dsr_errors) + LOG_TARGET_ERROR(target, + "DSR (%08" PRIX32 ") indicates DIR instruction generated an exception!", + dsr); + needclear = 1; + } + if (dsr & OCDDSR_EXECOVERRUN) { + if (!xtensa->suppress_dsr_errors) + LOG_TARGET_ERROR(target, + "DSR (%08" PRIX32 ") indicates DIR instruction generated an overrun!", + dsr); + needclear = 1; + } + if (xtensa->core_config->core_type == XT_NX && (xtensa_imprecise_exception_occurred(target))) { + if (!xtensa->suppress_dsr_errors) + LOG_TARGET_ERROR(target, + "%s: Imprecise exception occurred!", target_name(target)); + needclear = 1; + needimprclear = 1; + } + if (needclear) { + res = xtensa_dm_core_status_clear(&xtensa->dbg_mod, + OCDDSR_EXECEXCEPTION | OCDDSR_EXECOVERRUN); + if (res != ERROR_OK && !xtensa->suppress_dsr_errors) + LOG_TARGET_ERROR(target, "clearing DSR failed!"); + if (xtensa->core_config->core_type == XT_NX && needimprclear) + xtensa_imprecise_exception_clear(target); + return ERROR_FAIL; + } + return ERROR_OK; +} + +xtensa_reg_val_t xtensa_reg_get(struct target *target, enum xtensa_reg_id reg_id) +{ + struct xtensa *xtensa = target_to_xtensa(target); + struct reg *reg = &xtensa->core_cache->reg_list[reg_id]; + return xtensa_reg_get_value(reg); +} + +void xtensa_reg_set(struct target *target, enum xtensa_reg_id reg_id, xtensa_reg_val_t value) +{ + struct xtensa *xtensa = target_to_xtensa(target); + struct reg *reg = &xtensa->core_cache->reg_list[reg_id]; + if (xtensa_reg_get_value(reg) == value) + return; + xtensa_reg_set_value(reg, value); +} + +/* Set Ax (XT_REG_RELGEN) register along with its underlying ARx (XT_REG_GENERAL) */ +void xtensa_reg_set_deep_relgen(struct target *target, enum xtensa_reg_id a_idx, xtensa_reg_val_t value) +{ + struct xtensa *xtensa = target_to_xtensa(target); + uint32_t wb_idx = (xtensa->core_config->core_type == XT_LX) ? + XT_REG_IDX_WINDOWBASE : xtensa->nx_reg_idx[XT_NX_REG_IDX_WB]; + uint32_t windowbase = (xtensa->core_config->windowed ? + xtensa_reg_get(target, wb_idx) : 0); + if (xtensa->core_config->core_type == XT_NX) + windowbase = (windowbase & XT_WB_P_MSK) >> XT_WB_P_SHIFT; + int ar_idx = xtensa_windowbase_offset_to_canonical(xtensa, a_idx, windowbase); + xtensa_reg_set(target, a_idx, value); + xtensa_reg_set(target, ar_idx, value); +} + +/* Read cause for entering halted state; return bitmask in DEBUGCAUSE_* format */ +uint32_t xtensa_cause_get(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + if (xtensa->core_config->core_type == XT_LX) { + /* LX cause in DEBUGCAUSE */ + return xtensa_reg_get(target, XT_REG_IDX_DEBUGCAUSE); + } + if (xtensa->nx_stop_cause & DEBUGCAUSE_VALID) + return xtensa->nx_stop_cause; + + /* NX cause determined from DSR.StopCause */ + if (xtensa_dm_core_status_read(&xtensa->dbg_mod) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Read DSR error"); + } else { + uint32_t dsr = xtensa_dm_core_status_get(&xtensa->dbg_mod); + /* NX causes are prioritized; only 1 bit can be set */ + switch ((dsr & OCDDSR_STOPCAUSE) >> OCDDSR_STOPCAUSE_SHIFT) { + case OCDDSR_STOPCAUSE_DI: + xtensa->nx_stop_cause = DEBUGCAUSE_DI; + break; + case OCDDSR_STOPCAUSE_SS: + xtensa->nx_stop_cause = DEBUGCAUSE_IC; + break; + case OCDDSR_STOPCAUSE_IB: + xtensa->nx_stop_cause = DEBUGCAUSE_IB; + break; + case OCDDSR_STOPCAUSE_B: + case OCDDSR_STOPCAUSE_B1: + xtensa->nx_stop_cause = DEBUGCAUSE_BI; + break; + case OCDDSR_STOPCAUSE_BN: + xtensa->nx_stop_cause = DEBUGCAUSE_BN; + break; + case OCDDSR_STOPCAUSE_DB0: + case OCDDSR_STOPCAUSE_DB1: + xtensa->nx_stop_cause = DEBUGCAUSE_DB; + break; + default: + LOG_TARGET_ERROR(target, "Unknown stop cause (DSR: 0x%08x)", dsr); + break; + } + if (xtensa->nx_stop_cause) + xtensa->nx_stop_cause |= DEBUGCAUSE_VALID; + } + return xtensa->nx_stop_cause; +} + +void xtensa_cause_clear(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + if (xtensa->core_config->core_type == XT_LX) { + xtensa_reg_set(target, XT_REG_IDX_DEBUGCAUSE, 0); + xtensa->core_cache->reg_list[XT_REG_IDX_DEBUGCAUSE].dirty = false; + } else { + /* NX DSR.STOPCAUSE is not writeable; clear cached copy but leave it valid */ + xtensa->nx_stop_cause = DEBUGCAUSE_VALID; + } +} + +void xtensa_cause_reset(struct target *target) +{ + /* Clear DEBUGCAUSE_VALID to trigger re-read (on NX) */ + struct xtensa *xtensa = target_to_xtensa(target); + xtensa->nx_stop_cause = 0; +} + +int xtensa_assert_reset(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + + LOG_TARGET_DEBUG(target, " begin"); + xtensa_queue_pwr_reg_write(xtensa, + XDMREG_PWRCTL, + PWRCTL_JTAGDEBUGUSE(xtensa) | PWRCTL_DEBUGWAKEUP(xtensa) | PWRCTL_MEMWAKEUP(xtensa) | + PWRCTL_COREWAKEUP(xtensa) | PWRCTL_CORERESET(xtensa)); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) + return res; + + /* registers are now invalid */ + xtensa->reset_asserted = true; + register_cache_invalidate(xtensa->core_cache); + target->state = TARGET_RESET; + return ERROR_OK; +} + +int xtensa_deassert_reset(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + + LOG_TARGET_DEBUG(target, "halt=%d", target->reset_halt); + if (target->reset_halt) + xtensa_queue_dbg_reg_write(xtensa, + XDMREG_DCRSET, + OCDDCR_ENABLEOCD | OCDDCR_DEBUGINTERRUPT); + xtensa_queue_pwr_reg_write(xtensa, + XDMREG_PWRCTL, + PWRCTL_JTAGDEBUGUSE(xtensa) | PWRCTL_DEBUGWAKEUP(xtensa) | PWRCTL_MEMWAKEUP(xtensa) | + PWRCTL_COREWAKEUP(xtensa)); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) + return res; + target->state = TARGET_RUNNING; + xtensa->reset_asserted = false; + return res; +} + +int xtensa_soft_reset_halt(struct target *target) +{ + LOG_TARGET_DEBUG(target, "begin"); + return xtensa_assert_reset(target); +} + +int xtensa_fetch_all_regs(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + struct reg *reg_list = xtensa->core_cache->reg_list; + unsigned int reg_list_size = xtensa->core_cache->num_regs; + xtensa_reg_val_t cpenable = 0, windowbase = 0, a0 = 0, a3; + unsigned int ms_idx = reg_list_size; + uint32_t ms = 0; + uint32_t woe; + uint8_t a0_buf[4], a3_buf[4], ms_buf[4]; + bool debug_dsrs = !xtensa->regs_fetched || LOG_LEVEL_IS(LOG_LVL_DEBUG); + + union xtensa_reg_val_u *regvals = calloc(reg_list_size, sizeof(*regvals)); + if (!regvals) { + LOG_TARGET_ERROR(target, "unable to allocate memory for regvals!"); + return ERROR_FAIL; + } + union xtensa_reg_val_u *dsrs = calloc(reg_list_size, sizeof(*dsrs)); + if (!dsrs) { + LOG_TARGET_ERROR(target, "unable to allocate memory for dsrs!"); + free(regvals); + return ERROR_FAIL; + } + + LOG_TARGET_DEBUG(target, "start"); + + /* Save (windowed) A3 so cache matches physical AR3; A3 usable as scratch */ + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, a3_buf); + if (xtensa->core_config->core_type == XT_NX) { + /* Save (windowed) A0 as well--it will be required for reading PC */ + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A0)); + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, a0_buf); + + /* Set MS.DispSt, clear MS.DE prior to accessing ARs. This ensures ARs remain + * in correct order even for reversed register groups (overflow/underflow). + */ + ms_idx = xtensa->nx_reg_idx[XT_NX_REG_IDX_MS]; + uint32_t ms_regno = xtensa->optregs[ms_idx - XT_NUM_REGS].reg_num; + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, ms_regno, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, ms_buf); + LOG_TARGET_DEBUG(target, "Overriding MS (0x%x): 0x%x", ms_regno, XT_MS_DISPST_DBG); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, XT_MS_DISPST_DBG); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, ms_regno, XT_REG_A3)); + } + + int res = xtensa_window_state_save(target, &woe); + if (res != ERROR_OK) + goto xtensa_fetch_all_regs_done; + + /* Assume the CPU has just halted. We now want to fill the register cache with all the + * register contents GDB needs. For speed, we pipeline all the read operations, execute them + * in one go, then sort everything out from the regvals variable. */ + + /* Start out with AREGS; we can reach those immediately. Grab them per 16 registers. */ + for (unsigned int j = 0; j < XT_AREGS_NUM_MAX; j += 16) { + /*Grab the 16 registers we can see */ + for (unsigned int i = 0; i < 16; i++) { + if (i + j < xtensa->core_config->aregs_num) { + xtensa_queue_exec_ins(xtensa, + XT_INS_WSR(xtensa, XT_SR_DDR, xtensa_regs[XT_REG_IDX_AR0 + i].reg_num)); + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, + regvals[XT_REG_IDX_AR0 + i + j].buf); + if (debug_dsrs) + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DSR, + dsrs[XT_REG_IDX_AR0 + i + j].buf); + } + } + if (xtensa->core_config->windowed) { + /* Now rotate the window so we'll see the next 16 registers. The final rotate + * will wraparound, leaving us in the state we were. + * Each ROTW rotates 4 registers on LX and 8 on NX */ + int rotw_arg = (xtensa->core_config->core_type == XT_LX) ? 4 : 2; + xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(xtensa, rotw_arg)); + } + } + xtensa_window_state_restore(target, woe); + + if (xtensa->core_config->coproc) { + /* As the very first thing after AREGS, go grab CPENABLE */ + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, xtensa_regs[XT_REG_IDX_CPENABLE].reg_num, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, regvals[XT_REG_IDX_CPENABLE].buf); + } + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read ARs (%d)!", res); + goto xtensa_fetch_all_regs_done; + } + xtensa_core_status_check(target); + + a3 = buf_get_u32(a3_buf, 0, 32); + if (xtensa->core_config->core_type == XT_NX) { + a0 = buf_get_u32(a0_buf, 0, 32); + ms = buf_get_u32(ms_buf, 0, 32); + } + + if (xtensa->core_config->coproc) { + cpenable = buf_get_u32(regvals[XT_REG_IDX_CPENABLE].buf, 0, 32); + + /* Enable all coprocessors (by setting all bits in CPENABLE) so we can read FP and user registers. */ + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, 0xffffffff); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, xtensa_regs[XT_REG_IDX_CPENABLE].reg_num, XT_REG_A3)); + + /* Save CPENABLE; flag dirty later (when regcache updated) so original value is always restored */ + LOG_TARGET_DEBUG(target, "CPENABLE: was 0x%" PRIx32 ", all enabled", cpenable); + xtensa_reg_set(target, XT_REG_IDX_CPENABLE, cpenable); + } + /* We're now free to use any of A0-A15 as scratch registers + * Grab the SFRs and user registers first. We use A3 as a scratch register. */ + for (unsigned int i = 0; i < reg_list_size; i++) { + struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs; + unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS; + if (xtensa_reg_is_readable(rlist[ridx].flags, cpenable) && rlist[ridx].exist) { + bool reg_fetched = true; + unsigned int reg_num = rlist[ridx].reg_num; + switch (rlist[ridx].type) { + case XT_REG_USER: + xtensa_queue_exec_ins(xtensa, XT_INS_RUR(xtensa, reg_num, XT_REG_A3)); + break; + case XT_REG_FR: + xtensa_queue_exec_ins(xtensa, XT_INS_RFR(xtensa, reg_num, XT_REG_A3)); + break; + case XT_REG_SPECIAL: + if (reg_num == XT_PC_REG_NUM_VIRTUAL) { + if (xtensa->core_config->core_type == XT_LX) { + /* reg number of PC for debug interrupt depends on NDEBUGLEVEL */ + reg_num = XT_EPC_REG_NUM_BASE + xtensa->core_config->debug.irq_level; + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, reg_num, XT_REG_A3)); + } else { + /* NX PC read through CALL0(0) and reading A0 */ + xtensa_queue_exec_ins(xtensa, XT_INS_CALL0(xtensa, 0)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A0)); + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, regvals[i].buf); + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DSR, dsrs[i].buf); + reg_fetched = false; + } + } else if ((xtensa->core_config->core_type == XT_LX) + && (reg_num == xtensa_regs[XT_REG_IDX_PS].reg_num)) { + /* reg number of PS for debug interrupt depends on NDEBUGLEVEL */ + reg_num = XT_EPS_REG_NUM_BASE + xtensa->core_config->debug.irq_level; + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, reg_num, XT_REG_A3)); + } else if (reg_num == xtensa_regs[XT_REG_IDX_CPENABLE].reg_num) { + /* CPENABLE already read/updated; don't re-read */ + reg_fetched = false; + break; + } else { + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, reg_num, XT_REG_A3)); + } + break; + default: + reg_fetched = false; + } + if (reg_fetched) { + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, regvals[i].buf); + if (debug_dsrs) + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DSR, dsrs[i].buf); + } + } + } + /* Ok, send the whole mess to the CPU. */ + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_ERROR("Failed to fetch AR regs!"); + goto xtensa_fetch_all_regs_done; + } + xtensa_core_status_check(target); + + if (debug_dsrs) { + /* DSR checking: follows order in which registers are requested. */ + for (unsigned int i = 0; i < reg_list_size; i++) { + struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs; + unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS; + if (xtensa_reg_is_readable(rlist[ridx].flags, cpenable) && rlist[ridx].exist && + (rlist[ridx].type != XT_REG_DEBUG) && + (rlist[ridx].type != XT_REG_RELGEN) && + (rlist[ridx].type != XT_REG_TIE) && + (rlist[ridx].type != XT_REG_OTHER)) { + if (buf_get_u32(dsrs[i].buf, 0, 32) & OCDDSR_EXECEXCEPTION) { + LOG_ERROR("Exception reading %s!", reg_list[i].name); + res = ERROR_FAIL; + goto xtensa_fetch_all_regs_done; + } + } + } + } + + if (xtensa->core_config->windowed) { + /* We need the windowbase to decode the general addresses. */ + uint32_t wb_idx = (xtensa->core_config->core_type == XT_LX) ? + XT_REG_IDX_WINDOWBASE : xtensa->nx_reg_idx[XT_NX_REG_IDX_WB]; + windowbase = buf_get_u32(regvals[wb_idx].buf, 0, 32); + if (xtensa->core_config->core_type == XT_NX) + windowbase = (windowbase & XT_WB_P_MSK) >> XT_WB_P_SHIFT; + } + + /* Decode the result and update the cache. */ + for (unsigned int i = 0; i < reg_list_size; i++) { + struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs; + unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS; + if (xtensa_reg_is_readable(rlist[ridx].flags, cpenable) && rlist[ridx].exist) { + if ((xtensa->core_config->windowed) && (rlist[ridx].type == XT_REG_GENERAL)) { + /* The 64-value general register set is read from (windowbase) on down. + * We need to get the real register address by subtracting windowbase and + * wrapping around. */ + enum xtensa_reg_id realadr = xtensa_canonical_to_windowbase_offset(xtensa, i, + windowbase); + buf_cpy(regvals[realadr].buf, reg_list[i].value, reg_list[i].size); + } else if (rlist[ridx].type == XT_REG_RELGEN) { + buf_cpy(regvals[rlist[ridx].reg_num].buf, reg_list[i].value, reg_list[i].size); + if (xtensa_extra_debug_log) { + xtensa_reg_val_t regval = buf_get_u32(regvals[rlist[ridx].reg_num].buf, 0, 32); + LOG_DEBUG("%s = 0x%x", rlist[ridx].name, regval); + } + } else { + xtensa_reg_val_t regval = buf_get_u32(regvals[i].buf, 0, 32); + bool is_dirty = (i == XT_REG_IDX_CPENABLE); + if (xtensa_extra_debug_log) + LOG_INFO("Register %s: 0x%X", reg_list[i].name, regval); + if (rlist[ridx].reg_num == XT_PC_REG_NUM_VIRTUAL && + xtensa->core_config->core_type == XT_NX) { + /* A0 from prior CALL0 points to next instruction; decrement it */ + regval -= 3; + is_dirty = 1; + } else if (i == ms_idx) { + LOG_TARGET_DEBUG(target, "Caching MS: 0x%x", ms); + regval = ms; + is_dirty = 1; + } + xtensa_reg_set(target, i, regval); + reg_list[i].dirty = is_dirty; /*always do this _after_ xtensa_reg_set! */ + } + reg_list[i].valid = true; + } else { + if ((rlist[ridx].flags & XT_REGF_MASK) == XT_REGF_NOREAD) { + /* Report read-only registers all-zero but valid */ + reg_list[i].valid = true; + xtensa_reg_set(target, i, 0); + } else { + reg_list[i].valid = false; + } + } + } + + if (xtensa->core_config->windowed) { + /* We have used A3 as a scratch register. + * Windowed configs: restore A3's AR (XT_REG_GENERAL) and and flag for write-back. + */ + enum xtensa_reg_id ar3_idx = xtensa_windowbase_offset_to_canonical(xtensa, XT_REG_IDX_A3, windowbase); + xtensa_reg_set(target, ar3_idx, a3); + xtensa_mark_register_dirty(xtensa, ar3_idx); + + /* Reset scratch_ars[] on fetch. .chrval tracks AR mapping and changes w/ window */ + sprintf(xtensa->scratch_ars[XT_AR_SCRATCH_AR3].chrval, "ar%d", ar3_idx - XT_REG_IDX_AR0); + enum xtensa_reg_id ar4_idx = xtensa_windowbase_offset_to_canonical(xtensa, XT_REG_IDX_A4, windowbase); + sprintf(xtensa->scratch_ars[XT_AR_SCRATCH_AR4].chrval, "ar%d", ar4_idx - XT_REG_IDX_AR0); + for (enum xtensa_ar_scratch_set_e s = 0; s < XT_AR_SCRATCH_NUM; s++) + xtensa->scratch_ars[s].intval = false; + } + + /* We have used A3 (XT_REG_RELGEN) as a scratch register. Restore and flag for write-back. */ + xtensa_reg_set(target, XT_REG_IDX_A3, a3); + xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3); + if (xtensa->core_config->core_type == XT_NX) { + xtensa_reg_set(target, XT_REG_IDX_A0, a0); + xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A0); + } + + xtensa->regs_fetched = true; +xtensa_fetch_all_regs_done: + free(regvals); + free(dsrs); + return res; +} + +int xtensa_get_gdb_reg_list(struct target *target, + struct reg **reg_list[], + int *reg_list_size, + enum target_register_class reg_class) +{ + struct xtensa *xtensa = target_to_xtensa(target); + unsigned int num_regs; + + if (reg_class == REG_CLASS_GENERAL) { + if ((xtensa->genpkt_regs_num == 0) || !xtensa->contiguous_regs_list) { + LOG_ERROR("reg_class %d unhandled; 'xtgregs' not found", reg_class); + return ERROR_FAIL; + } + num_regs = xtensa->genpkt_regs_num; + } else { + /* Determine whether to return a contiguous or sparse register map */ + num_regs = xtensa->regmap_contiguous ? xtensa->total_regs_num : xtensa->dbregs_num; + } + + LOG_DEBUG("reg_class=%i, num_regs=%d", (int)reg_class, num_regs); + + *reg_list = calloc(num_regs, sizeof(struct reg *)); + if (!*reg_list) + return ERROR_FAIL; + + *reg_list_size = num_regs; + if (xtensa->regmap_contiguous) { + assert((num_regs <= xtensa->total_regs_num) && "contiguous regmap size internal error!"); + for (unsigned int i = 0; i < num_regs; i++) + (*reg_list)[i] = xtensa->contiguous_regs_list[i]; + return ERROR_OK; + } + + for (unsigned int i = 0; i < num_regs; i++) + (*reg_list)[i] = (struct reg *)&xtensa->empty_regs[i]; + unsigned int k = 0; + for (unsigned int i = 0; i < xtensa->core_cache->num_regs && k < num_regs; i++) { + if (xtensa->core_cache->reg_list[i].exist) { + struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs; + unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS; + int sparse_idx = rlist[ridx].dbreg_num; + if (i == XT_REG_IDX_PS && xtensa->core_config->core_type == XT_LX) { + if (xtensa->eps_dbglevel_idx == 0) { + LOG_ERROR("eps_dbglevel_idx not set\n"); + return ERROR_FAIL; + } + (*reg_list)[sparse_idx] = &xtensa->core_cache->reg_list[xtensa->eps_dbglevel_idx]; + if (xtensa_extra_debug_log) + LOG_DEBUG("SPARSE GDB reg 0x%x getting EPS%d 0x%x", + sparse_idx, xtensa->core_config->debug.irq_level, + xtensa_reg_get_value((*reg_list)[sparse_idx])); + } else if (rlist[ridx].type == XT_REG_RELGEN) { + (*reg_list)[sparse_idx - XT_REG_IDX_ARFIRST] = &xtensa->core_cache->reg_list[i]; + } else { + (*reg_list)[sparse_idx] = &xtensa->core_cache->reg_list[i]; + } + if (i == XT_REG_IDX_PC) + /* Make a duplicate copy of PC for external access */ + (*reg_list)[XT_PC_DBREG_NUM_BASE] = &xtensa->core_cache->reg_list[i]; + k++; + } + } + + if (k == num_regs) + LOG_ERROR("SPARSE GDB reg list full (size %d)", k); + + return ERROR_OK; +} + +int xtensa_mmu_is_enabled(struct target *target, int *enabled) +{ + struct xtensa *xtensa = target_to_xtensa(target); + *enabled = xtensa->core_config->mmu.itlb_entries_count > 0 || + xtensa->core_config->mmu.dtlb_entries_count > 0; + return ERROR_OK; +} + +int xtensa_halt(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + + LOG_TARGET_DEBUG(target, "start"); + if (target->state == TARGET_HALTED) { + LOG_TARGET_DEBUG(target, "target was already halted"); + return ERROR_OK; + } + /* First we have to read dsr and check if the target stopped */ + int res = xtensa_dm_core_status_read(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read core status!"); + return res; + } + LOG_TARGET_DEBUG(target, "Core status 0x%" PRIx32, xtensa_dm_core_status_get(&xtensa->dbg_mod)); + if (!xtensa_is_stopped(target)) { + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DCRSET, OCDDCR_ENABLEOCD | OCDDCR_DEBUGINTERRUPT); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) + LOG_TARGET_ERROR(target, "Failed to set OCDDCR_DEBUGINTERRUPT. Can't halt."); + } + + return res; +} + +int xtensa_prepare_resume(struct target *target, + int current, + target_addr_t address, + int handle_breakpoints, + int debug_execution) +{ + struct xtensa *xtensa = target_to_xtensa(target); + uint32_t bpena = 0; + + LOG_TARGET_DEBUG(target, + "current=%d address=" TARGET_ADDR_FMT ", handle_breakpoints=%i, debug_execution=%i)", + current, + address, + handle_breakpoints, + debug_execution); + + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; + } + xtensa->halt_request = false; + + if (address && !current) { + xtensa_reg_set(target, XT_REG_IDX_PC, address); + } else { + uint32_t cause = xtensa_cause_get(target); + LOG_TARGET_DEBUG(target, "DEBUGCAUSE 0x%x (watchpoint %lu) (break %lu)", + cause, (cause & DEBUGCAUSE_DB), (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN))); + if (cause & DEBUGCAUSE_DB) + /* We stopped due to a watchpoint. We can't just resume executing the + * instruction again because */ + /* that would trigger the watchpoint again. To fix this, we single-step, + * which ignores watchpoints. */ + xtensa_do_step(target, current, address, handle_breakpoints); + if (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN)) + /* We stopped due to a break instruction. We can't just resume executing the + * instruction again because */ + /* that would trigger the break again. To fix this, we single-step, which + * ignores break. */ + xtensa_do_step(target, current, address, handle_breakpoints); + } + + /* Write back hw breakpoints. Current FreeRTOS SMP code can set a hw breakpoint on an + * exception; we need to clear that and return to the breakpoints gdb has set on resume. */ + for (unsigned int slot = 0; slot < xtensa->core_config->debug.ibreaks_num; slot++) { + if (xtensa->hw_brps[slot]) { + /* Write IBREAKA[slot] and set bit #slot in IBREAKENABLE */ + xtensa_reg_set(target, XT_REG_IDX_IBREAKA0 + slot, xtensa->hw_brps[slot]->address); + if (xtensa->core_config->core_type == XT_NX) + xtensa_reg_set(target, xtensa->nx_reg_idx[XT_NX_REG_IDX_IBREAKC0] + slot, XT_IBREAKC_FB); + bpena |= BIT(slot); + } + } + if (xtensa->core_config->core_type == XT_LX) + xtensa_reg_set(target, XT_REG_IDX_IBREAKENABLE, bpena); + + /* Here we write all registers to the targets */ + int res = xtensa_write_dirty_registers(target); + if (res != ERROR_OK) + LOG_TARGET_ERROR(target, "Failed to write back register cache."); + return res; +} + +int xtensa_do_resume(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + + LOG_TARGET_DEBUG(target, "start"); + + xtensa_cause_reset(target); + xtensa_queue_exec_ins(xtensa, XT_INS_RFDO(xtensa)); + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to exec RFDO %d!", res); + return res; + } + xtensa_core_status_check(target); + return ERROR_OK; +} + +int xtensa_resume(struct target *target, + int current, + target_addr_t address, + int handle_breakpoints, + int debug_execution) +{ + LOG_TARGET_DEBUG(target, "start"); + int res = xtensa_prepare_resume(target, current, address, handle_breakpoints, debug_execution); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to prepare for resume!"); + return res; + } + res = xtensa_do_resume(target); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to resume!"); + return res; + } + + target->debug_reason = DBG_REASON_NOTHALTED; + if (!debug_execution) + target->state = TARGET_RUNNING; + else + target->state = TARGET_DEBUG_RUNNING; + + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + + return ERROR_OK; +} + +static bool xtensa_pc_in_winexc(struct target *target, target_addr_t pc) +{ + struct xtensa *xtensa = target_to_xtensa(target); + uint8_t insn_buf[XT_ISNS_SZ_MAX]; + int err = xtensa_read_buffer(target, pc, sizeof(insn_buf), insn_buf); + if (err != ERROR_OK) + return false; + + xtensa_insn_t insn = buf_get_u32(insn_buf, 0, 24); + xtensa_insn_t masked = insn & XT_INS_L32E_S32E_MASK(xtensa); + if (masked == XT_INS_L32E(xtensa, 0, 0, 0) || masked == XT_INS_S32E(xtensa, 0, 0, 0)) + return true; + + masked = insn & XT_INS_RFWO_RFWU_MASK(xtensa); + if (masked == XT_INS_RFWO(xtensa) || masked == XT_INS_RFWU(xtensa)) + return true; + + return false; +} + +int xtensa_do_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) +{ + struct xtensa *xtensa = target_to_xtensa(target); + int res; + const uint32_t icount_val = -2; /* ICOUNT value to load for 1 step */ + xtensa_reg_val_t dbreakc[XT_WATCHPOINTS_NUM_MAX]; + xtensa_reg_val_t icountlvl, cause; + xtensa_reg_val_t oldps, oldpc, cur_pc; + bool ps_lowered = false; + + LOG_TARGET_DEBUG(target, "current=%d, address=" TARGET_ADDR_FMT ", handle_breakpoints=%i", + current, address, handle_breakpoints); + + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (xtensa->eps_dbglevel_idx == 0 && xtensa->core_config->core_type == XT_LX) { + LOG_TARGET_ERROR(target, "eps_dbglevel_idx not set\n"); + return ERROR_FAIL; + } + + /* Save old ps (EPS[dbglvl] on LX), pc */ + oldps = xtensa_reg_get(target, (xtensa->core_config->core_type == XT_LX) ? + xtensa->eps_dbglevel_idx : XT_REG_IDX_PS); + oldpc = xtensa_reg_get(target, XT_REG_IDX_PC); + + cause = xtensa_cause_get(target); + LOG_TARGET_DEBUG(target, "oldps=%" PRIx32 ", oldpc=%" PRIx32 " dbg_cause=%" PRIx32 " exc_cause=%" PRIx32, + oldps, + oldpc, + cause, + xtensa_reg_get(target, XT_REG_IDX_EXCCAUSE)); + if (handle_breakpoints && (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN))) { + /* handle hard-coded SW breakpoints (e.g. syscalls) */ + LOG_TARGET_DEBUG(target, "Increment PC to pass break instruction..."); + xtensa_cause_clear(target); /* so we don't recurse into the same routine */ + /* pretend that we have stepped */ + if (cause & DEBUGCAUSE_BI) + xtensa_reg_set(target, XT_REG_IDX_PC, oldpc + 3); /* PC = PC+3 */ + else + xtensa_reg_set(target, XT_REG_IDX_PC, oldpc + 2); /* PC = PC+2 */ + return ERROR_OK; + } + + /* Xtensa LX has an ICOUNTLEVEL register which sets the maximum interrupt level + * at which the instructions are to be counted while stepping. + * + * For example, if we need to step by 2 instructions, and an interrupt occurs + * in between, the processor will trigger the interrupt and halt after the 2nd + * instruction within the interrupt vector and/or handler. + * + * However, sometimes we don't want the interrupt handlers to be executed at all + * while stepping through the code. In this case (XT_STEPPING_ISR_OFF), + * ICOUNTLEVEL can be lowered to the executing code's (level + 1) to prevent ISR + * code from being counted during stepping. Note that C exception handlers must + * run at level 0 and hence will be counted and stepped into, should one occur. + * + * TODO: Certain instructions should never be single-stepped and should instead + * be emulated (per DUG): RSIL >= DBGLEVEL, RSR/WSR [ICOUNT|ICOUNTLEVEL], and + * RFI >= DBGLEVEL. + */ + if (xtensa->stepping_isr_mode == XT_STEPPING_ISR_OFF) { + if (!xtensa->core_config->high_irq.enabled) { + LOG_TARGET_WARNING( + target, + "disabling IRQs while stepping is not implemented w/o high prio IRQs option!"); + return ERROR_FAIL; + } + /* Update ICOUNTLEVEL accordingly */ + icountlvl = MIN((oldps & 0xF) + 1, xtensa->core_config->debug.irq_level); + } else { + icountlvl = xtensa->core_config->debug.irq_level; + } + + if (cause & DEBUGCAUSE_DB) { + /* We stopped due to a watchpoint. We can't just resume executing the instruction again because + * that would trigger the watchpoint again. To fix this, we remove watchpoints,single-step and + * re-enable the watchpoint. */ + LOG_TARGET_DEBUG( + target, + "Single-stepping to get past instruction that triggered the watchpoint..."); + xtensa_cause_clear(target); /* so we don't recurse into the same routine */ + /* Save all DBREAKCx registers and set to 0 to disable watchpoints */ + for (unsigned int slot = 0; slot < xtensa->core_config->debug.dbreaks_num; slot++) { + dbreakc[slot] = xtensa_reg_get(target, XT_REG_IDX_DBREAKC0 + slot); + xtensa_reg_set(target, XT_REG_IDX_DBREAKC0 + slot, 0); + } + } + + if (!handle_breakpoints && (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN))) + /* handle normal SW breakpoint */ + xtensa_cause_clear(target); /* so we don't recurse into the same routine */ + if (xtensa->core_config->core_type == XT_LX && ((oldps & 0xf) >= icountlvl)) { + /* Lower interrupt level to allow stepping, but flag eps[dbglvl] to be restored */ + ps_lowered = true; + uint32_t newps = (oldps & ~0xf) | (icountlvl - 1); + xtensa_reg_set(target, xtensa->eps_dbglevel_idx, newps); + LOG_TARGET_DEBUG(target, + "Lowering PS.INTLEVEL to allow stepping: %s <- 0x%08" PRIx32 " (was 0x%08" PRIx32 ")", + xtensa->core_cache->reg_list[xtensa->eps_dbglevel_idx].name, + newps, + oldps); + } + do { + if (xtensa->core_config->core_type == XT_LX) { + xtensa_reg_set(target, XT_REG_IDX_ICOUNTLEVEL, icountlvl); + xtensa_reg_set(target, XT_REG_IDX_ICOUNT, icount_val); + } else { + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DCRSET, OCDDCR_STEPREQUEST); + } + + /* Now that ICOUNT (LX) or DCR.StepRequest (NX) is set, + * we can resume as if we were going to run + */ + res = xtensa_prepare_resume(target, current, address, 0, 0); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to prepare resume for single step"); + return res; + } + res = xtensa_do_resume(target); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to resume after setting up single step"); + return res; + } + + /* Wait for stepping to complete */ + long long start = timeval_ms(); + while (timeval_ms() < start + 500) { + /* Do not use target_poll here, it also triggers other things... just manually read the DSR + *until stepping is complete. */ + usleep(1000); + res = xtensa_dm_core_status_read(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read core status!"); + return res; + } + if (xtensa_is_stopped(target)) + break; + usleep(1000); + } + LOG_TARGET_DEBUG(target, "Finish stepping. dsr=0x%08" PRIx32, + xtensa_dm_core_status_get(&xtensa->dbg_mod)); + if (!xtensa_is_stopped(target)) { + LOG_TARGET_WARNING( + target, + "Timed out waiting for target to finish stepping. dsr=0x%08" PRIx32, + xtensa_dm_core_status_get(&xtensa->dbg_mod)); + target->debug_reason = DBG_REASON_NOTHALTED; + target->state = TARGET_RUNNING; + return ERROR_FAIL; + } + + xtensa_fetch_all_regs(target); + cur_pc = xtensa_reg_get(target, XT_REG_IDX_PC); + + LOG_TARGET_DEBUG(target, + "cur_ps=%" PRIx32 ", cur_pc=%" PRIx32 " dbg_cause=%" PRIx32 " exc_cause=%" PRIx32, + xtensa_reg_get(target, XT_REG_IDX_PS), + cur_pc, + xtensa_cause_get(target), + xtensa_reg_get(target, XT_REG_IDX_EXCCAUSE)); + + /* Do not step into WindowOverflow if ISRs are masked. + If we stop in WindowOverflow at breakpoint with masked ISRs and + try to do a step it will get us out of that handler */ + if (xtensa->core_config->windowed && + xtensa->stepping_isr_mode == XT_STEPPING_ISR_OFF && + xtensa_pc_in_winexc(target, cur_pc)) { + /* isrmask = on, need to step out of the window exception handler */ + LOG_DEBUG("Stepping out of window exception, PC=%" PRIX32, cur_pc); + oldpc = cur_pc; + address = oldpc + 3; + continue; + } + + if (oldpc == cur_pc) + LOG_TARGET_WARNING(target, "Stepping doesn't seem to change PC! dsr=0x%08" PRIx32, + xtensa_dm_core_status_get(&xtensa->dbg_mod)); + else + LOG_DEBUG("Stepped from %" PRIX32 " to %" PRIX32, oldpc, cur_pc); + break; + } while (true); + + target->debug_reason = DBG_REASON_SINGLESTEP; + target->state = TARGET_HALTED; + LOG_DEBUG("Done stepping, PC=%" PRIX32, cur_pc); + + if (cause & DEBUGCAUSE_DB) { + LOG_TARGET_DEBUG(target, "...Done, re-installing watchpoints."); + /* Restore the DBREAKCx registers */ + for (unsigned int slot = 0; slot < xtensa->core_config->debug.dbreaks_num; slot++) + xtensa_reg_set(target, XT_REG_IDX_DBREAKC0 + slot, dbreakc[slot]); + } + + /* Restore int level */ + if (ps_lowered) { + LOG_DEBUG("Restoring %s after stepping: 0x%08" PRIx32, + xtensa->core_cache->reg_list[xtensa->eps_dbglevel_idx].name, + oldps); + xtensa_reg_set(target, xtensa->eps_dbglevel_idx, oldps); + } + + /* write ICOUNTLEVEL back to zero */ + xtensa_reg_set(target, XT_REG_IDX_ICOUNTLEVEL, 0); + /* TODO: can we skip writing dirty registers and re-fetching them? */ + res = xtensa_write_dirty_registers(target); + xtensa_fetch_all_regs(target); + return res; +} + +int xtensa_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) +{ + int retval = xtensa_do_step(target, current, address, handle_breakpoints); + if (retval != ERROR_OK) + return retval; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + return ERROR_OK; +} + +/** + * Returns true if two ranges are overlapping + */ +static inline bool xtensa_memory_regions_overlap(target_addr_t r1_start, + target_addr_t r1_end, + target_addr_t r2_start, + target_addr_t r2_end) +{ + if ((r2_start >= r1_start) && (r2_start < r1_end)) + return true; /* r2_start is in r1 region */ + if ((r2_end > r1_start) && (r2_end <= r1_end)) + return true; /* r2_end is in r1 region */ + return false; +} + +/** + * Returns a size of overlapped region of two ranges. + */ +static inline target_addr_t xtensa_get_overlap_size(target_addr_t r1_start, + target_addr_t r1_end, + target_addr_t r2_start, + target_addr_t r2_end) +{ + if (xtensa_memory_regions_overlap(r1_start, r1_end, r2_start, r2_end)) { + target_addr_t ov_start = r1_start < r2_start ? r2_start : r1_start; + target_addr_t ov_end = r1_end > r2_end ? r2_end : r1_end; + return ov_end - ov_start; + } + return 0; +} + +/** + * Check if the address gets to memory regions, and its access mode + */ +static bool xtensa_memory_op_validate_range(struct xtensa *xtensa, target_addr_t address, size_t size, int access) +{ + target_addr_t adr_pos = address; /* address cursor set to the beginning start */ + target_addr_t adr_end = address + size; /* region end */ + target_addr_t overlap_size; + const struct xtensa_local_mem_region_config *cm; /* current mem region */ + + while (adr_pos < adr_end) { + cm = xtensa_target_memory_region_find(xtensa, adr_pos); + if (!cm) /* address is not belong to anything */ + return false; + if ((cm->access & access) != access) /* access check */ + return false; + overlap_size = xtensa_get_overlap_size(cm->base, (cm->base + cm->size), adr_pos, adr_end); + assert(overlap_size != 0); + adr_pos += overlap_size; + } + return true; +} + +int xtensa_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) +{ + struct xtensa *xtensa = target_to_xtensa(target); + /* We are going to read memory in 32-bit increments. This may not be what the calling + * function expects, so we may need to allocate a temp buffer and read into that first. */ + target_addr_t addrstart_al = ALIGN_DOWN(address, 4); + target_addr_t addrend_al = ALIGN_UP(address + size * count, 4); + target_addr_t adr = addrstart_al; + uint8_t *albuff; + bool bswap = xtensa->target->endianness == TARGET_BIG_ENDIAN; + + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!xtensa->permissive_mode) { + if (!xtensa_memory_op_validate_range(xtensa, address, (size * count), + XT_MEM_ACCESS_READ)) { + LOG_DEBUG("address " TARGET_ADDR_FMT " not readable", address); + return ERROR_FAIL; + } + } + + unsigned int alloc_bytes = ALIGN_UP(addrend_al - addrstart_al, sizeof(uint32_t)); + albuff = calloc(alloc_bytes, 1); + if (!albuff) { + LOG_TARGET_ERROR(target, "Out of memory allocating %" PRId64 " bytes!", + addrend_al - addrstart_al); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* We're going to use A3 here */ + xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3); + /* Write start address to A3 */ + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, addrstart_al); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + /* Now we can safely read data from addrstart_al up to addrend_al into albuff */ + if (xtensa->probe_lsddr32p != 0) { + xtensa_queue_exec_ins(xtensa, XT_INS_LDDR32P(xtensa, XT_REG_A3)); + for (unsigned int i = 0; adr != addrend_al; i += sizeof(uint32_t), adr += sizeof(uint32_t)) + xtensa_queue_dbg_reg_read(xtensa, + (adr + sizeof(uint32_t) == addrend_al) ? XDMREG_DDR : XDMREG_DDREXEC, + &albuff[i]); + } else { + xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A4); + for (unsigned int i = 0; adr != addrend_al; i += sizeof(uint32_t), adr += sizeof(uint32_t)) { + xtensa_queue_exec_ins(xtensa, XT_INS_L32I(xtensa, XT_REG_A3, XT_REG_A4, 0)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A4)); + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, &albuff[i]); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, adr + sizeof(uint32_t)); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + } + } + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res == ERROR_OK) { + bool prev_suppress = xtensa->suppress_dsr_errors; + xtensa->suppress_dsr_errors = true; + res = xtensa_core_status_check(target); + if (xtensa->probe_lsddr32p == -1) + xtensa->probe_lsddr32p = 1; + xtensa->suppress_dsr_errors = prev_suppress; + } + if (res != ERROR_OK) { + if (xtensa->probe_lsddr32p != 0) { + /* Disable fast memory access instructions and retry before reporting an error */ + LOG_TARGET_DEBUG(target, "Disabling LDDR32.P/SDDR32.P"); + xtensa->probe_lsddr32p = 0; + res = xtensa_read_memory(target, address, size, count, albuff); + bswap = false; + } else { + LOG_TARGET_WARNING(target, "Failed reading %d bytes at address "TARGET_ADDR_FMT, + count * size, address); + } + } + + if (bswap) + buf_bswap32(albuff, albuff, addrend_al - addrstart_al); + memcpy(buffer, albuff + (address & 3), (size * count)); + free(albuff); + return res; +} + +int xtensa_read_buffer(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer) +{ + /* xtensa_read_memory can also read unaligned stuff. Just pass through to that routine. */ + return xtensa_read_memory(target, address, 1, count, buffer); +} + +int xtensa_write_memory(struct target *target, + target_addr_t address, + uint32_t size, + uint32_t count, + const uint8_t *buffer) +{ + /* This memory write function can get thrown nigh everything into it, from + * aligned uint32 writes to unaligned uint8ths. The Xtensa memory doesn't always + * accept anything but aligned uint32 writes, though. That is why we convert + * everything into that. */ + struct xtensa *xtensa = target_to_xtensa(target); + target_addr_t addrstart_al = ALIGN_DOWN(address, 4); + target_addr_t addrend_al = ALIGN_UP(address + size * count, 4); + target_addr_t adr = addrstart_al; + int res; + uint8_t *albuff; + bool fill_head_tail = false; + + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!xtensa->permissive_mode) { + if (!xtensa_memory_op_validate_range(xtensa, address, (size * count), XT_MEM_ACCESS_WRITE)) { + LOG_WARNING("address " TARGET_ADDR_FMT " not writable", address); + return ERROR_FAIL; + } + } + + if (size == 0 || count == 0 || !buffer) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* Allocate a temporary buffer to put the aligned bytes in, if needed. */ + if (addrstart_al == address && addrend_al == address + (size * count)) { + if (xtensa->target->endianness == TARGET_BIG_ENDIAN) + /* Need a buffer for byte-swapping */ + albuff = malloc(addrend_al - addrstart_al); + else + /* We discard the const here because albuff can also be non-const */ + albuff = (uint8_t *)buffer; + } else { + fill_head_tail = true; + albuff = malloc(addrend_al - addrstart_al); + } + if (!albuff) { + LOG_TARGET_ERROR(target, "Out of memory allocating %" PRId64 " bytes!", + addrend_al - addrstart_al); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* We're going to use A3 here */ + xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3); + + /* If we're using a temp aligned buffer, we need to fill the head and/or tail bit of it. */ + if (fill_head_tail) { + /* See if we need to read the first and/or last word. */ + if (address & 3) { + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, addrstart_al); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + if (xtensa->probe_lsddr32p == 1) { + xtensa_queue_exec_ins(xtensa, XT_INS_LDDR32P(xtensa, XT_REG_A3)); + } else { + xtensa_queue_exec_ins(xtensa, XT_INS_L32I(xtensa, XT_REG_A3, XT_REG_A3, 0)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); + } + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, &albuff[0]); + } + if ((address + (size * count)) & 3) { + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, addrend_al - 4); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + if (xtensa->probe_lsddr32p == 1) { + xtensa_queue_exec_ins(xtensa, XT_INS_LDDR32P(xtensa, XT_REG_A3)); + } else { + xtensa_queue_exec_ins(xtensa, XT_INS_L32I(xtensa, XT_REG_A3, XT_REG_A3, 0)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3)); + } + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, + &albuff[addrend_al - addrstart_al - 4]); + } + /* Grab bytes */ + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_ERROR("Error issuing unaligned memory write context instruction(s): %d", res); + if (albuff != buffer) + free(albuff); + return res; + } + xtensa_core_status_check(target); + if (xtensa->target->endianness == TARGET_BIG_ENDIAN) { + bool swapped_w0 = false; + if (address & 3) { + buf_bswap32(&albuff[0], &albuff[0], 4); + swapped_w0 = true; + } + if ((address + (size * count)) & 3) { + if ((addrend_al - addrstart_al - 4 == 0) && swapped_w0) { + /* Don't double-swap if buffer start/end are within the same word */ + } else { + buf_bswap32(&albuff[addrend_al - addrstart_al - 4], + &albuff[addrend_al - addrstart_al - 4], 4); + } + } + } + /* Copy data to be written into the aligned buffer (in host-endianness) */ + memcpy(&albuff[address & 3], buffer, size * count); + /* Now we can write albuff in aligned uint32s. */ + } + + if (xtensa->target->endianness == TARGET_BIG_ENDIAN) + buf_bswap32(albuff, fill_head_tail ? albuff : buffer, addrend_al - addrstart_al); + + /* Write start address to A3 */ + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, addrstart_al); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + /* Write the aligned buffer */ + if (xtensa->probe_lsddr32p != 0) { + for (unsigned int i = 0; adr != addrend_al; i += sizeof(uint32_t), adr += sizeof(uint32_t)) { + if (i == 0) { + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, buf_get_u32(&albuff[i], 0, 32)); + xtensa_queue_exec_ins(xtensa, XT_INS_SDDR32P(xtensa, XT_REG_A3)); + } else { + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDREXEC, buf_get_u32(&albuff[i], 0, 32)); + } + } + } else { + xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A4); + for (unsigned int i = 0; adr != addrend_al; i += sizeof(uint32_t), adr += sizeof(uint32_t)) { + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, buf_get_u32(&albuff[i], 0, 32)); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A4)); + xtensa_queue_exec_ins(xtensa, XT_INS_S32I(xtensa, XT_REG_A3, XT_REG_A4, 0)); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, adr + sizeof(uint32_t)); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + } + } + + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res == ERROR_OK) { + bool prev_suppress = xtensa->suppress_dsr_errors; + xtensa->suppress_dsr_errors = true; + res = xtensa_core_status_check(target); + if (xtensa->probe_lsddr32p == -1) + xtensa->probe_lsddr32p = 1; + xtensa->suppress_dsr_errors = prev_suppress; + } + if (res != ERROR_OK) { + if (xtensa->probe_lsddr32p != 0) { + /* Disable fast memory access instructions and retry before reporting an error */ + LOG_TARGET_INFO(target, "Disabling LDDR32.P/SDDR32.P"); + xtensa->probe_lsddr32p = 0; + res = xtensa_write_memory(target, address, size, count, buffer); + } else { + LOG_TARGET_WARNING(target, "Failed writing %d bytes at address "TARGET_ADDR_FMT, + count * size, address); + } + } else { + /* Invalidate ICACHE, writeback DCACHE if present */ + uint32_t issue_ihi = xtensa_is_icacheable(xtensa, address); + uint32_t issue_dhwb = xtensa_is_dcacheable(xtensa, address); + if (issue_ihi || issue_dhwb) { + uint32_t ilinesize = issue_ihi ? xtensa->core_config->icache.line_size : UINT32_MAX; + uint32_t dlinesize = issue_dhwb ? xtensa->core_config->dcache.line_size : UINT32_MAX; + uint32_t linesize = MIN(ilinesize, dlinesize); + uint32_t off = 0; + adr = addrstart_al; + + while ((adr + off) < addrend_al) { + if (off == 0) { + /* Write start address to A3 */ + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, adr); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + } + if (issue_ihi) + xtensa_queue_exec_ins(xtensa, XT_INS_IHI(xtensa, XT_REG_A3, off)); + if (issue_dhwb) + xtensa_queue_exec_ins(xtensa, XT_INS_DHWBI(xtensa, XT_REG_A3, off)); + off += linesize; + if (off > 1020) { + /* IHI, DHWB have 8-bit immediate operands (0..1020) */ + adr += off; + off = 0; + } + } + + /* Execute cache WB/INV instructions */ + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + xtensa_core_status_check(target); + if (res != ERROR_OK) + LOG_TARGET_ERROR(target, + "Error issuing cache writeback/invaldate instruction(s): %d", + res); + } + } + if (albuff != buffer) + free(albuff); + + return res; +} + +int xtensa_write_buffer(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer) +{ + /* xtensa_write_memory can handle everything. Just pass on to that. */ + return xtensa_write_memory(target, address, 1, count, buffer); +} + +int xtensa_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) +{ + LOG_WARNING("not implemented yet"); + return ERROR_FAIL; +} + +int xtensa_poll(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + if (xtensa_dm_poll(&xtensa->dbg_mod) != ERROR_OK) { + target->state = TARGET_UNKNOWN; + return ERROR_TARGET_NOT_EXAMINED; + } + + int res = xtensa_dm_power_status_read(&xtensa->dbg_mod, PWRSTAT_DEBUGWASRESET(xtensa) | + PWRSTAT_COREWASRESET(xtensa)); + if (xtensa->dbg_mod.power_status.stat != xtensa->dbg_mod.power_status.stath) + LOG_TARGET_DEBUG(target, "PWRSTAT: read 0x%08" PRIx32 ", clear 0x%08lx, reread 0x%08" PRIx32, + xtensa->dbg_mod.power_status.stat, + PWRSTAT_DEBUGWASRESET(xtensa) | PWRSTAT_COREWASRESET(xtensa), + xtensa->dbg_mod.power_status.stath); + if (res != ERROR_OK) + return res; + + if (xtensa_dm_tap_was_reset(&xtensa->dbg_mod)) { + LOG_TARGET_INFO(target, "Debug controller was reset."); + res = xtensa_smpbreak_write(xtensa, xtensa->smp_break); + if (res != ERROR_OK) + return res; + } + if (xtensa_dm_core_was_reset(&xtensa->dbg_mod)) + LOG_TARGET_INFO(target, "Core was reset."); + xtensa_dm_power_status_cache(&xtensa->dbg_mod); + /* Enable JTAG, set reset if needed */ + res = xtensa_wakeup(target); + if (res != ERROR_OK) + return res; + + uint32_t prev_dsr = xtensa->dbg_mod.core_status.dsr; + res = xtensa_dm_core_status_read(&xtensa->dbg_mod); + if (res != ERROR_OK) + return res; + if (prev_dsr != xtensa->dbg_mod.core_status.dsr) + LOG_TARGET_DEBUG(target, + "DSR has changed: was 0x%08" PRIx32 " now 0x%08" PRIx32, + prev_dsr, + xtensa->dbg_mod.core_status.dsr); + if (xtensa->dbg_mod.power_status.stath & PWRSTAT_COREWASRESET(xtensa)) { + /* if RESET state is persitent */ + target->state = TARGET_RESET; + } else if (!xtensa_dm_is_powered(&xtensa->dbg_mod)) { + LOG_TARGET_DEBUG(target, "not powered 0x%" PRIX32 "%ld", + xtensa->dbg_mod.core_status.dsr, + xtensa->dbg_mod.core_status.dsr & OCDDSR_STOPPED); + target->state = TARGET_UNKNOWN; + if (xtensa->come_online_probes_num == 0) + target->examined = false; + else + xtensa->come_online_probes_num--; + } else if (xtensa_is_stopped(target)) { + if (target->state != TARGET_HALTED) { + enum target_state oldstate = target->state; + target->state = TARGET_HALTED; + /* Examine why the target has been halted */ + target->debug_reason = DBG_REASON_DBGRQ; + xtensa_fetch_all_regs(target); + /* When setting debug reason DEBUGCAUSE events have the following + * priorities: watchpoint == breakpoint > single step > debug interrupt. */ + /* Watchpoint and breakpoint events at the same time results in special + * debug reason: DBG_REASON_WPTANDBKPT. */ + uint32_t halt_cause = xtensa_cause_get(target); + /* TODO: Add handling of DBG_REASON_EXC_CATCH */ + if (halt_cause & DEBUGCAUSE_IC) + target->debug_reason = DBG_REASON_SINGLESTEP; + if (halt_cause & (DEBUGCAUSE_IB | DEBUGCAUSE_BN | DEBUGCAUSE_BI)) { + if (halt_cause & DEBUGCAUSE_DB) + target->debug_reason = DBG_REASON_WPTANDBKPT; + else + target->debug_reason = DBG_REASON_BREAKPOINT; + } else if (halt_cause & DEBUGCAUSE_DB) { + target->debug_reason = DBG_REASON_WATCHPOINT; + } + LOG_TARGET_DEBUG(target, "Target halted, pc=0x%08" PRIx32 + ", debug_reason=%08" PRIx32 ", oldstate=%08" PRIx32, + xtensa_reg_get(target, XT_REG_IDX_PC), + target->debug_reason, + oldstate); + LOG_TARGET_DEBUG(target, "Halt reason=0x%08" PRIX32 ", exc_cause=%" PRId32 ", dsr=0x%08" PRIx32, + halt_cause, + xtensa_reg_get(target, XT_REG_IDX_EXCCAUSE), + xtensa->dbg_mod.core_status.dsr); + xtensa_dm_core_status_clear( + &xtensa->dbg_mod, + OCDDSR_DEBUGPENDBREAK | OCDDSR_DEBUGINTBREAK | OCDDSR_DEBUGPENDTRAX | + OCDDSR_DEBUGINTTRAX | + OCDDSR_DEBUGPENDHOST | OCDDSR_DEBUGINTHOST); + if (xtensa->core_config->core_type == XT_NX) { + /* Enable imprecise exceptions while in halted state */ + xtensa_reg_val_t ps = xtensa_reg_get(target, XT_REG_IDX_PS); + xtensa_reg_val_t newps = ps & ~(XT_PS_DIEXC_MSK); + xtensa_mark_register_dirty(xtensa, XT_REG_IDX_PS); + LOG_TARGET_DEBUG(target, "Enabling PS.DIEXC: 0x%08x -> 0x%08x", ps, newps); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, newps); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_PS, XT_REG_A3)); + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to write PS.DIEXC (%d)!", res); + return res; + } + xtensa_core_status_check(target); + } + } + } else { + target->debug_reason = DBG_REASON_NOTHALTED; + if (target->state != TARGET_RUNNING && target->state != TARGET_DEBUG_RUNNING) { + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + } + } + if (xtensa->trace_active) { + /* Detect if tracing was active but has stopped. */ + struct xtensa_trace_status trace_status; + res = xtensa_dm_trace_status_read(&xtensa->dbg_mod, &trace_status); + if (res == ERROR_OK) { + if (!(trace_status.stat & TRAXSTAT_TRACT)) { + LOG_INFO("Detected end of trace."); + if (trace_status.stat & TRAXSTAT_PCMTG) + LOG_TARGET_INFO(target, "Trace stop triggered by PC match"); + if (trace_status.stat & TRAXSTAT_PTITG) + LOG_TARGET_INFO(target, "Trace stop triggered by Processor Trigger Input"); + if (trace_status.stat & TRAXSTAT_CTITG) + LOG_TARGET_INFO(target, "Trace stop triggered by Cross-trigger Input"); + xtensa->trace_active = false; + } + } + } + return ERROR_OK; +} + +static int xtensa_update_instruction(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer) +{ + struct xtensa *xtensa = target_to_xtensa(target); + unsigned int issue_ihi = xtensa_is_icacheable(xtensa, address); + unsigned int issue_dhwbi = xtensa_is_dcacheable(xtensa, address); + uint32_t icache_line_size = issue_ihi ? xtensa->core_config->icache.line_size : UINT32_MAX; + uint32_t dcache_line_size = issue_dhwbi ? xtensa->core_config->dcache.line_size : UINT32_MAX; + unsigned int same_ic_line = ((address & (icache_line_size - 1)) + size) <= icache_line_size; + unsigned int same_dc_line = ((address & (dcache_line_size - 1)) + size) <= dcache_line_size; + int ret; + + if (size > icache_line_size) + return ERROR_FAIL; + + if (issue_ihi || issue_dhwbi) { + /* We're going to use A3 here */ + xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3); + + /* Write start address to A3 and invalidate */ + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, address); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + LOG_TARGET_DEBUG(target, "DHWBI, IHI for address "TARGET_ADDR_FMT, address); + if (issue_dhwbi) { + xtensa_queue_exec_ins(xtensa, XT_INS_DHWBI(xtensa, XT_REG_A3, 0)); + if (!same_dc_line) { + LOG_TARGET_DEBUG(target, + "DHWBI second dcache line for address "TARGET_ADDR_FMT, + address + 4); + xtensa_queue_exec_ins(xtensa, XT_INS_DHWBI(xtensa, XT_REG_A3, 4)); + } + } + if (issue_ihi) { + xtensa_queue_exec_ins(xtensa, XT_INS_IHI(xtensa, XT_REG_A3, 0)); + if (!same_ic_line) { + LOG_TARGET_DEBUG(target, + "IHI second icache line for address "TARGET_ADDR_FMT, + address + 4); + xtensa_queue_exec_ins(xtensa, XT_INS_IHI(xtensa, XT_REG_A3, 4)); + } + } + + /* Execute invalidate instructions */ + ret = xtensa_dm_queue_execute(&xtensa->dbg_mod); + xtensa_core_status_check(target); + if (ret != ERROR_OK) { + LOG_ERROR("Error issuing cache invaldate instruction(s): %d", ret); + return ret; + } + } + + /* Write new instructions to memory */ + ret = target_write_buffer(target, address, size, buffer); + if (ret != ERROR_OK) { + LOG_TARGET_ERROR(target, "Error writing instruction to memory: %d", ret); + return ret; + } + + if (issue_dhwbi) { + /* Flush dcache so instruction propagates. A3 may be corrupted during memory write */ + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, address); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_DHWB(xtensa, XT_REG_A3, 0)); + LOG_DEBUG("DHWB dcache line for address "TARGET_ADDR_FMT, address); + if (!same_dc_line) { + LOG_TARGET_DEBUG(target, "DHWB second dcache line for address "TARGET_ADDR_FMT, address + 4); + xtensa_queue_exec_ins(xtensa, XT_INS_DHWB(xtensa, XT_REG_A3, 4)); + } + + /* Execute invalidate instructions */ + ret = xtensa_dm_queue_execute(&xtensa->dbg_mod); + xtensa_core_status_check(target); + } + + /* TODO: Handle L2 cache if present */ + return ret; +} + +static int xtensa_sw_breakpoint_add(struct target *target, + struct breakpoint *breakpoint, + struct xtensa_sw_breakpoint *sw_bp) +{ + struct xtensa *xtensa = target_to_xtensa(target); + int ret = target_read_buffer(target, breakpoint->address, XT_ISNS_SZ_MAX, sw_bp->insn); + if (ret != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read original instruction (%d)!", ret); + return ret; + } + + sw_bp->insn_sz = MIN(XT_ISNS_SZ_MAX, breakpoint->length); + sw_bp->oocd_bp = breakpoint; + + uint32_t break_insn = sw_bp->insn_sz == XT_ISNS_SZ_MAX ? XT_INS_BREAK(xtensa, 0, 0) : XT_INS_BREAKN(xtensa, 0); + + /* Underlying memory write will convert instruction endianness, don't do that here */ + ret = xtensa_update_instruction(target, breakpoint->address, sw_bp->insn_sz, (uint8_t *)&break_insn); + if (ret != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to write breakpoint instruction (%d)!", ret); + return ret; + } + + return ERROR_OK; +} + +static int xtensa_sw_breakpoint_remove(struct target *target, struct xtensa_sw_breakpoint *sw_bp) +{ + int ret = xtensa_update_instruction(target, sw_bp->oocd_bp->address, sw_bp->insn_sz, sw_bp->insn); + if (ret != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to write insn (%d)!", ret); + return ret; + } + sw_bp->oocd_bp = NULL; + return ERROR_OK; +} + +int xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint) +{ + struct xtensa *xtensa = target_to_xtensa(target); + unsigned int slot; + + if (breakpoint->type == BKPT_SOFT) { + for (slot = 0; slot < XT_SW_BREAKPOINTS_MAX_NUM; slot++) { + if (!xtensa->sw_brps[slot].oocd_bp || + xtensa->sw_brps[slot].oocd_bp == breakpoint) + break; + } + if (slot == XT_SW_BREAKPOINTS_MAX_NUM) { + LOG_TARGET_WARNING(target, "No free slots to add SW breakpoint!"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + int ret = xtensa_sw_breakpoint_add(target, breakpoint, &xtensa->sw_brps[slot]); + if (ret != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to add SW breakpoint!"); + return ret; + } + LOG_TARGET_DEBUG(target, "placed SW breakpoint %u @ " TARGET_ADDR_FMT, + slot, + breakpoint->address); + return ERROR_OK; + } + + for (slot = 0; slot < xtensa->core_config->debug.ibreaks_num; slot++) { + if (!xtensa->hw_brps[slot] || xtensa->hw_brps[slot] == breakpoint) + break; + } + if (slot == xtensa->core_config->debug.ibreaks_num) { + LOG_TARGET_ERROR(target, "No free slots to add HW breakpoint!"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + xtensa->hw_brps[slot] = breakpoint; + /* We will actually write the breakpoints when we resume the target. */ + LOG_TARGET_DEBUG(target, "placed HW breakpoint %u @ " TARGET_ADDR_FMT, + slot, + breakpoint->address); + + return ERROR_OK; +} + +int xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint) +{ + struct xtensa *xtensa = target_to_xtensa(target); + unsigned int slot; + + if (breakpoint->type == BKPT_SOFT) { + for (slot = 0; slot < XT_SW_BREAKPOINTS_MAX_NUM; slot++) { + if (xtensa->sw_brps[slot].oocd_bp && xtensa->sw_brps[slot].oocd_bp == breakpoint) + break; + } + if (slot == XT_SW_BREAKPOINTS_MAX_NUM) { + LOG_TARGET_WARNING(target, "Max SW breakpoints slot reached, slot=%u!", slot); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + int ret = xtensa_sw_breakpoint_remove(target, &xtensa->sw_brps[slot]); + if (ret != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to remove SW breakpoint (%d)!", ret); + return ret; + } + LOG_TARGET_DEBUG(target, "cleared SW breakpoint %u @ " TARGET_ADDR_FMT, slot, breakpoint->address); + return ERROR_OK; + } + + for (slot = 0; slot < xtensa->core_config->debug.ibreaks_num; slot++) { + if (xtensa->hw_brps[slot] == breakpoint) + break; + } + if (slot == xtensa->core_config->debug.ibreaks_num) { + LOG_TARGET_ERROR(target, "HW breakpoint not found!"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + xtensa->hw_brps[slot] = NULL; + if (xtensa->core_config->core_type == XT_NX) + xtensa_reg_set(target, xtensa->nx_reg_idx[XT_NX_REG_IDX_IBREAKC0] + slot, 0); + LOG_TARGET_DEBUG(target, "cleared HW breakpoint %u @ " TARGET_ADDR_FMT, slot, breakpoint->address); + return ERROR_OK; +} + +int xtensa_watchpoint_add(struct target *target, struct watchpoint *watchpoint) +{ + struct xtensa *xtensa = target_to_xtensa(target); + unsigned int slot; + xtensa_reg_val_t dbreakcval; + + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (watchpoint->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) { + LOG_TARGET_ERROR(target, "watchpoint value masks not supported"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + for (slot = 0; slot < xtensa->core_config->debug.dbreaks_num; slot++) { + if (!xtensa->hw_wps[slot] || xtensa->hw_wps[slot] == watchpoint) + break; + } + if (slot == xtensa->core_config->debug.dbreaks_num) { + LOG_TARGET_WARNING(target, "No free slots to add HW watchpoint!"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* Figure out value for dbreakc5..0 + * It's basically 0x3F with an incremental bit removed from the LSB for each extra length power of 2. */ + if (watchpoint->length < 1 || watchpoint->length > 64 || + !IS_PWR_OF_2(watchpoint->length) || + !IS_ALIGNED(watchpoint->address, watchpoint->length)) { + LOG_TARGET_WARNING( + target, + "Watchpoint with length %d on address " TARGET_ADDR_FMT + " not supported by hardware.", + watchpoint->length, + watchpoint->address); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + dbreakcval = ALIGN_DOWN(0x3F, watchpoint->length); + + if (watchpoint->rw == WPT_READ) + dbreakcval |= BIT(30); + if (watchpoint->rw == WPT_WRITE) + dbreakcval |= BIT(31); + if (watchpoint->rw == WPT_ACCESS) + dbreakcval |= BIT(30) | BIT(31); + + /* Write DBREAKA[slot] and DBCREAKC[slot] */ + xtensa_reg_set(target, XT_REG_IDX_DBREAKA0 + slot, watchpoint->address); + xtensa_reg_set(target, XT_REG_IDX_DBREAKC0 + slot, dbreakcval); + xtensa->hw_wps[slot] = watchpoint; + LOG_TARGET_DEBUG(target, "placed HW watchpoint @ " TARGET_ADDR_FMT, + watchpoint->address); + return ERROR_OK; +} + +int xtensa_watchpoint_remove(struct target *target, struct watchpoint *watchpoint) +{ + struct xtensa *xtensa = target_to_xtensa(target); + unsigned int slot; + + for (slot = 0; slot < xtensa->core_config->debug.dbreaks_num; slot++) { + if (xtensa->hw_wps[slot] == watchpoint) + break; + } + if (slot == xtensa->core_config->debug.dbreaks_num) { + LOG_TARGET_WARNING(target, "HW watchpoint " TARGET_ADDR_FMT " not found!", watchpoint->address); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + xtensa_reg_set(target, XT_REG_IDX_DBREAKC0 + slot, 0); + xtensa->hw_wps[slot] = NULL; + LOG_TARGET_DEBUG(target, "cleared HW watchpoint @ " TARGET_ADDR_FMT, + watchpoint->address); + return ERROR_OK; +} + +int xtensa_start_algorithm(struct target *target, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + target_addr_t entry_point, target_addr_t exit_point, + void *arch_info) +{ + struct xtensa *xtensa = target_to_xtensa(target); + struct xtensa_algorithm *algorithm_info = arch_info; + int retval = ERROR_OK; + bool usr_ps = false; + uint32_t newps; + + /* NOTE: xtensa_run_algorithm requires that each algorithm uses a software breakpoint + * at the exit point */ + + if (target->state != TARGET_HALTED) { + LOG_WARNING("Target not halted!"); + return ERROR_TARGET_NOT_HALTED; + } + + for (unsigned int i = 0; i < xtensa->core_cache->num_regs; i++) { + struct reg *reg = &xtensa->core_cache->reg_list[i]; + buf_cpy(reg->value, xtensa->algo_context_backup[i], reg->size); + } + /* save debug reason, it will be changed */ + if (!algorithm_info) { + LOG_ERROR("BUG: arch_info not specified"); + return ERROR_FAIL; + } + algorithm_info->ctx_debug_reason = target->debug_reason; + if (xtensa->core_config->core_type == XT_LX) { + /* save PS and set to debug_level - 1 */ + algorithm_info->ctx_ps = xtensa_reg_get(target, xtensa->eps_dbglevel_idx); + newps = (algorithm_info->ctx_ps & ~0xf) | (xtensa->core_config->debug.irq_level - 1); + xtensa_reg_set(target, xtensa->eps_dbglevel_idx, newps); + } + /* write mem params */ + for (int i = 0; i < num_mem_params; i++) { + if (mem_params[i].direction != PARAM_IN) { + retval = target_write_buffer(target, mem_params[i].address, + mem_params[i].size, + mem_params[i].value); + if (retval != ERROR_OK) + return retval; + } + } + /* write reg params */ + for (int i = 0; i < num_reg_params; i++) { + if (reg_params[i].size > 32) { + LOG_ERROR("BUG: not supported register size (%d)", reg_params[i].size); + return ERROR_FAIL; + } + struct reg *reg = register_get_by_name(xtensa->core_cache, reg_params[i].reg_name, 0); + if (!reg) { + LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); + return ERROR_FAIL; + } + if (reg->size != reg_params[i].size) { + LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); + return ERROR_FAIL; + } + if (memcmp(reg_params[i].reg_name, "ps", 3)) { + usr_ps = true; + } else if (xtensa->core_config->core_type == XT_LX) { + unsigned int reg_id = xtensa->eps_dbglevel_idx; + assert(reg_id < xtensa->core_cache->num_regs && "Attempt to access non-existing reg!"); + reg = &xtensa->core_cache->reg_list[reg_id]; + } + xtensa_reg_set_value(reg, buf_get_u32(reg_params[i].value, 0, reg->size)); + reg->valid = 1; + } + /* ignore custom core mode if custom PS value is specified */ + if (!usr_ps && xtensa->core_config->core_type == XT_LX) { + unsigned int eps_reg_idx = xtensa->eps_dbglevel_idx; + xtensa_reg_val_t ps = xtensa_reg_get(target, eps_reg_idx); + enum xtensa_mode core_mode = XT_PS_RING_GET(ps); + if (algorithm_info->core_mode != XT_MODE_ANY && algorithm_info->core_mode != core_mode) { + LOG_DEBUG("setting core_mode: 0x%x", algorithm_info->core_mode); + xtensa_reg_val_t new_ps = (ps & ~XT_PS_RING_MSK) | XT_PS_RING(algorithm_info->core_mode); + /* save previous core mode */ + /* TODO: core_mode is not restored for now. Can be added to the end of wait_algorithm */ + algorithm_info->core_mode = core_mode; + xtensa_reg_set(target, eps_reg_idx, new_ps); + xtensa->core_cache->reg_list[eps_reg_idx].valid = 1; + } + } + + return xtensa_resume(target, 0, entry_point, 1, 1); +} + +/** Waits for an algorithm in the target. */ +int xtensa_wait_algorithm(struct target *target, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + target_addr_t exit_point, unsigned int timeout_ms, + void *arch_info) +{ + struct xtensa *xtensa = target_to_xtensa(target); + struct xtensa_algorithm *algorithm_info = arch_info; + int retval = ERROR_OK; + xtensa_reg_val_t pc; + + /* NOTE: xtensa_run_algorithm requires that each algorithm uses a software breakpoint + * at the exit point */ + + retval = target_wait_state(target, TARGET_HALTED, timeout_ms); + /* If the target fails to halt due to the breakpoint, force a halt */ + if (retval != ERROR_OK || target->state != TARGET_HALTED) { + retval = target_halt(target); + if (retval != ERROR_OK) + return retval; + retval = target_wait_state(target, TARGET_HALTED, 500); + if (retval != ERROR_OK) + return retval; + LOG_TARGET_ERROR(target, "not halted %d, pc 0x%" PRIx32 ", ps 0x%" PRIx32, retval, + xtensa_reg_get(target, XT_REG_IDX_PC), + xtensa_reg_get(target, (xtensa->core_config->core_type == XT_LX) ? + xtensa->eps_dbglevel_idx : XT_REG_IDX_PS)); + return ERROR_TARGET_TIMEOUT; + } + pc = xtensa_reg_get(target, XT_REG_IDX_PC); + if (exit_point && pc != exit_point) { + LOG_ERROR("failed algorithm halted at 0x%" PRIx32 ", expected " TARGET_ADDR_FMT, pc, exit_point); + return ERROR_TARGET_TIMEOUT; + } + /* Copy core register values to reg_params[] */ + for (int i = 0; i < num_reg_params; i++) { + if (reg_params[i].direction != PARAM_OUT) { + struct reg *reg = register_get_by_name(xtensa->core_cache, reg_params[i].reg_name, 0); + if (!reg) { + LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); + return ERROR_FAIL; + } + if (reg->size != reg_params[i].size) { + LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); + return ERROR_FAIL; + } + buf_set_u32(reg_params[i].value, 0, 32, xtensa_reg_get_value(reg)); + } + } + /* Read memory values to mem_params */ + LOG_DEBUG("Read mem params"); + for (int i = 0; i < num_mem_params; i++) { + LOG_DEBUG("Check mem param @ " TARGET_ADDR_FMT, mem_params[i].address); + if (mem_params[i].direction != PARAM_OUT) { + LOG_DEBUG("Read mem param @ " TARGET_ADDR_FMT, mem_params[i].address); + retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); + if (retval != ERROR_OK) + return retval; + } + } + + /* avoid gdb keep_alive warning */ + keep_alive(); + + for (int i = xtensa->core_cache->num_regs - 1; i >= 0; i--) { + struct reg *reg = &xtensa->core_cache->reg_list[i]; + if (i == XT_REG_IDX_PS) { + continue; /* restore mapped reg number of PS depends on NDEBUGLEVEL */ + } else if (i == XT_REG_IDX_DEBUGCAUSE) { + /*FIXME: restoring DEBUGCAUSE causes exception when executing corresponding + * instruction in DIR */ + LOG_DEBUG("Skip restoring register %s: 0x%8.8" PRIx32 " -> 0x%8.8" PRIx32, + xtensa->core_cache->reg_list[i].name, + buf_get_u32(reg->value, 0, 32), + buf_get_u32(xtensa->algo_context_backup[i], 0, 32)); + buf_cpy(xtensa->algo_context_backup[i], reg->value, reg->size); + xtensa->core_cache->reg_list[i].dirty = 0; + xtensa->core_cache->reg_list[i].valid = 0; + } else if (memcmp(xtensa->algo_context_backup[i], reg->value, reg->size / 8)) { + if (reg->size <= 32) { + LOG_DEBUG("restoring register %s: 0x%8.8" PRIx32 " -> 0x%8.8" PRIx32, + xtensa->core_cache->reg_list[i].name, + buf_get_u32(reg->value, 0, reg->size), + buf_get_u32(xtensa->algo_context_backup[i], 0, reg->size)); + } else if (reg->size <= 64) { + LOG_DEBUG("restoring register %s: 0x%8.8" PRIx64 " -> 0x%8.8" PRIx64, + xtensa->core_cache->reg_list[i].name, + buf_get_u64(reg->value, 0, reg->size), + buf_get_u64(xtensa->algo_context_backup[i], 0, reg->size)); + } else { + LOG_DEBUG("restoring register %s %u-bits", xtensa->core_cache->reg_list[i].name, reg->size); + } + buf_cpy(xtensa->algo_context_backup[i], reg->value, reg->size); + xtensa->core_cache->reg_list[i].dirty = 1; + xtensa->core_cache->reg_list[i].valid = 1; + } + } + target->debug_reason = algorithm_info->ctx_debug_reason; + if (xtensa->core_config->core_type == XT_LX) + xtensa_reg_set(target, xtensa->eps_dbglevel_idx, algorithm_info->ctx_ps); + + retval = xtensa_write_dirty_registers(target); + if (retval != ERROR_OK) + LOG_ERROR("Failed to write dirty regs (%d)!", retval); + + return retval; +} + +int xtensa_run_algorithm(struct target *target, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + target_addr_t entry_point, target_addr_t exit_point, + unsigned int timeout_ms, void *arch_info) +{ + int retval = xtensa_start_algorithm(target, + num_mem_params, mem_params, + num_reg_params, reg_params, + entry_point, exit_point, + arch_info); + + if (retval == ERROR_OK) { + retval = xtensa_wait_algorithm(target, + num_mem_params, mem_params, + num_reg_params, reg_params, + exit_point, timeout_ms, + arch_info); + } + + return retval; +} + +static int xtensa_build_reg_cache(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); + unsigned int last_dbreg_num = 0; + + if (xtensa->core_regs_num + xtensa->num_optregs != xtensa->total_regs_num) + LOG_TARGET_WARNING(target, "Register count MISMATCH: %d core regs, %d extended regs; %d expected", + xtensa->core_regs_num, xtensa->num_optregs, xtensa->total_regs_num); + + struct reg_cache *reg_cache = calloc(1, sizeof(struct reg_cache)); + + if (!reg_cache) { + LOG_ERROR("Failed to alloc reg cache!"); + return ERROR_FAIL; + } + reg_cache->name = "Xtensa registers"; + reg_cache->next = NULL; + /* Init reglist */ + unsigned int reg_list_size = XT_NUM_REGS + xtensa->num_optregs; + struct reg *reg_list = calloc(reg_list_size, sizeof(struct reg)); + if (!reg_list) { + LOG_ERROR("Failed to alloc reg list!"); + goto fail; + } + xtensa->dbregs_num = 0; + unsigned int didx = 0; + for (unsigned int whichlist = 0; whichlist < 2; whichlist++) { + struct xtensa_reg_desc *rlist = (whichlist == 0) ? xtensa_regs : xtensa->optregs; + unsigned int listsize = (whichlist == 0) ? XT_NUM_REGS : xtensa->num_optregs; + for (unsigned int i = 0; i < listsize; i++, didx++) { + reg_list[didx].exist = rlist[i].exist; + reg_list[didx].name = rlist[i].name; + reg_list[didx].size = 32; + reg_list[didx].value = calloc(1, 4 /*XT_REG_LEN*/); /* make Clang Static Analyzer happy */ + if (!reg_list[didx].value) { + LOG_ERROR("Failed to alloc reg list value!"); + goto fail; + } + reg_list[didx].dirty = false; + reg_list[didx].valid = false; + reg_list[didx].type = &xtensa_reg_type; + reg_list[didx].arch_info = xtensa; + if (rlist[i].exist && (rlist[i].dbreg_num > last_dbreg_num)) + last_dbreg_num = rlist[i].dbreg_num; + + if (xtensa_extra_debug_log) { + LOG_TARGET_DEBUG(target, + "POPULATE %-16s list %d exist %d, idx %d, type %d, dbreg_num 0x%04x", + reg_list[didx].name, + whichlist, + reg_list[didx].exist, + didx, + rlist[i].type, + rlist[i].dbreg_num); + } + } + } + + xtensa->dbregs_num = last_dbreg_num + 1; + reg_cache->reg_list = reg_list; + reg_cache->num_regs = reg_list_size; + + LOG_TARGET_DEBUG(target, "xtensa->total_regs_num %d reg_list_size %d xtensa->dbregs_num %d", + xtensa->total_regs_num, reg_list_size, xtensa->dbregs_num); + + /* Construct empty-register list for handling unknown register requests */ + xtensa->empty_regs = calloc(xtensa->dbregs_num, sizeof(struct reg)); + if (!xtensa->empty_regs) { + LOG_TARGET_ERROR(target, "ERROR: Out of memory"); + goto fail; + } + for (unsigned int i = 0; i < xtensa->dbregs_num; i++) { + xtensa->empty_regs[i].name = calloc(8, sizeof(char)); + if (!xtensa->empty_regs[i].name) { + LOG_TARGET_ERROR(target, "ERROR: Out of memory"); + goto fail; + } + sprintf((char *)xtensa->empty_regs[i].name, "?0x%04x", i & 0x0000FFFF); + xtensa->empty_regs[i].size = 32; + xtensa->empty_regs[i].type = &xtensa_reg_type; + xtensa->empty_regs[i].value = calloc(1, 4 /*XT_REG_LEN*/); /* make Clang Static Analyzer happy */ + if (!xtensa->empty_regs[i].value) { + LOG_ERROR("Failed to alloc empty reg list value!"); + goto fail; + } + xtensa->empty_regs[i].arch_info = xtensa; + } + + /* Construct contiguous register list from contiguous descriptor list */ + if (xtensa->regmap_contiguous && xtensa->contiguous_regs_desc) { + xtensa->contiguous_regs_list = calloc(xtensa->total_regs_num, sizeof(struct reg *)); + if (!xtensa->contiguous_regs_list) { + LOG_TARGET_ERROR(target, "ERROR: Out of memory"); + goto fail; + } + for (unsigned int i = 0; i < xtensa->total_regs_num; i++) { + unsigned int j; + for (j = 0; j < reg_cache->num_regs; j++) { + if (!strcmp(reg_cache->reg_list[j].name, xtensa->contiguous_regs_desc[i]->name)) { + /* Register number field is not filled above. + Here we are assigning the corresponding index from the contiguous reg list. + These indexes are in the same order with gdb g-packet request/response. + Some more changes may be required for sparse reg lists. + */ + reg_cache->reg_list[j].number = i; + xtensa->contiguous_regs_list[i] = &(reg_cache->reg_list[j]); + LOG_TARGET_DEBUG(target, + "POPULATE contiguous regs list: %-16s, dbreg_num 0x%04x", + xtensa->contiguous_regs_list[i]->name, + xtensa->contiguous_regs_desc[i]->dbreg_num); + break; + } + } + if (j == reg_cache->num_regs) + LOG_TARGET_WARNING(target, "contiguous register %s not found", + xtensa->contiguous_regs_desc[i]->name); + } + } + + xtensa->algo_context_backup = calloc(reg_cache->num_regs, sizeof(void *)); + if (!xtensa->algo_context_backup) { + LOG_ERROR("Failed to alloc mem for algorithm context backup!"); + goto fail; + } + for (unsigned int i = 0; i < reg_cache->num_regs; i++) { + struct reg *reg = ®_cache->reg_list[i]; + xtensa->algo_context_backup[i] = calloc(1, reg->size / 8); + if (!xtensa->algo_context_backup[i]) { + LOG_ERROR("Failed to alloc mem for algorithm context!"); + goto fail; + } + } + xtensa->core_cache = reg_cache; + if (cache_p) + *cache_p = reg_cache; + return ERROR_OK; + +fail: + if (reg_list) { + for (unsigned int i = 0; i < reg_list_size; i++) + free(reg_list[i].value); + free(reg_list); + } + if (xtensa->empty_regs) { + for (unsigned int i = 0; i < xtensa->dbregs_num; i++) { + free((void *)xtensa->empty_regs[i].name); + free(xtensa->empty_regs[i].value); + } + free(xtensa->empty_regs); + } + if (xtensa->algo_context_backup) { + for (unsigned int i = 0; i < reg_cache->num_regs; i++) + free(xtensa->algo_context_backup[i]); + free(xtensa->algo_context_backup); + } + free(reg_cache); + + return ERROR_FAIL; +} + +static int32_t xtensa_gdbqc_parse_exec_tie_ops(struct target *target, char *opstr) +{ + struct xtensa *xtensa = target_to_xtensa(target); + int32_t status = ERROR_COMMAND_ARGUMENT_INVALID; + /* Process op[] list */ + while (opstr && (*opstr == ':')) { + uint8_t ops[32]; + unsigned int oplen = strtoul(opstr + 1, &opstr, 16); + if (oplen > 32) { + LOG_TARGET_ERROR(target, "TIE access instruction too long (%d)\n", oplen); + break; + } + unsigned int i = 0; + while ((i < oplen) && opstr && (*opstr == ':')) + ops[i++] = strtoul(opstr + 1, &opstr, 16); + if (i != oplen) { + LOG_TARGET_ERROR(target, "TIE access instruction malformed (%d)\n", i); + break; + } + + char insn_buf[128]; + sprintf(insn_buf, "Exec %d-byte TIE sequence: ", oplen); + for (i = 0; i < oplen; i++) + sprintf(insn_buf + strlen(insn_buf), "%02x:", ops[i]); + LOG_TARGET_DEBUG(target, "%s", insn_buf); + xtensa_queue_exec_ins_wide(xtensa, ops, oplen); /* Handles endian-swap */ + status = ERROR_OK; + } + return status; +} + +static int xtensa_gdbqc_qxtreg(struct target *target, const char *packet, char **response_p) +{ + struct xtensa *xtensa = target_to_xtensa(target); + bool iswrite = (packet[0] == 'Q'); + enum xtensa_qerr_e error; + + /* Read/write TIE register. Requires spill location. + * qxtreg<num>:<len>:<oplen>:<op[0]>:<...>[:<oplen>:<op[0]>:<...>] + * Qxtreg<num>:<len>:<oplen>:<op[0]>:<...>[:<oplen>:<op[0]>:<...>]=<value> + */ + if (!(xtensa->spill_buf)) { + LOG_ERROR("Spill location not specified. Try 'target remote <host>:3333 &spill_location0'"); + error = XT_QERR_FAIL; + goto xtensa_gdbqc_qxtreg_fail; + } + + char *delim; + uint32_t regnum = strtoul(packet + 6, &delim, 16); + if (*delim != ':') { + LOG_ERROR("Malformed qxtreg packet"); + error = XT_QERR_INVAL; + goto xtensa_gdbqc_qxtreg_fail; + } + uint32_t reglen = strtoul(delim + 1, &delim, 16); + if (*delim != ':') { + LOG_ERROR("Malformed qxtreg packet"); + error = XT_QERR_INVAL; + goto xtensa_gdbqc_qxtreg_fail; + } + uint8_t regbuf[XT_QUERYPKT_RESP_MAX]; + memset(regbuf, 0, XT_QUERYPKT_RESP_MAX); + LOG_DEBUG("TIE reg 0x%08" PRIx32 " %s (%d bytes)", regnum, iswrite ? "write" : "read", reglen); + if (reglen * 2 + 1 > XT_QUERYPKT_RESP_MAX) { + LOG_ERROR("TIE register too large"); + error = XT_QERR_MEM; + goto xtensa_gdbqc_qxtreg_fail; + } + + /* (1) Save spill memory, (1.5) [if write then store value to spill location], + * (2) read old a4, (3) write spill address to a4. + * NOTE: ensure a4 is restored properly by all error handling logic + */ + unsigned int memop_size = (xtensa->spill_loc & 3) ? 1 : 4; + int status = xtensa_read_memory(target, xtensa->spill_loc, memop_size, + xtensa->spill_bytes / memop_size, xtensa->spill_buf); + if (status != ERROR_OK) { + LOG_ERROR("Spill memory save"); + error = XT_QERR_MEM; + goto xtensa_gdbqc_qxtreg_fail; + } + if (iswrite) { + /* Extract value and store in spill memory */ + unsigned int b = 0; + char *valbuf = strchr(delim, '='); + if (!(valbuf && (*valbuf == '='))) { + LOG_ERROR("Malformed Qxtreg packet"); + error = XT_QERR_INVAL; + goto xtensa_gdbqc_qxtreg_fail; + } + valbuf++; + while (*valbuf && *(valbuf + 1)) { + char bytestr[3] = { 0, 0, 0 }; + strncpy(bytestr, valbuf, 2); + regbuf[b++] = strtoul(bytestr, NULL, 16); + valbuf += 2; + } + if (b != reglen) { + LOG_ERROR("Malformed Qxtreg packet"); + error = XT_QERR_INVAL; + goto xtensa_gdbqc_qxtreg_fail; + } + status = xtensa_write_memory(target, xtensa->spill_loc, memop_size, + reglen / memop_size, regbuf); + if (status != ERROR_OK) { + LOG_ERROR("TIE value store"); + error = XT_QERR_MEM; + goto xtensa_gdbqc_qxtreg_fail; + } + } + xtensa_reg_val_t orig_a4 = xtensa_reg_get(target, XT_REG_IDX_A4); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, xtensa->spill_loc); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A4)); + + int32_t tieop_status = xtensa_gdbqc_parse_exec_tie_ops(target, delim); + + /* Restore a4 but not yet spill memory. Execute it all... */ + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, orig_a4); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A4)); + status = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (status != ERROR_OK) { + LOG_TARGET_ERROR(target, "TIE queue execute: %d\n", status); + tieop_status = status; + } + status = xtensa_core_status_check(target); + if (status != ERROR_OK) { + LOG_TARGET_ERROR(target, "TIE instr execute: %d\n", status); + tieop_status = status; + } + + if (tieop_status == ERROR_OK) { + if (iswrite) { + /* TIE write succeeded; send OK */ + strcpy(*response_p, "OK"); + } else { + /* TIE read succeeded; copy result from spill memory */ + status = xtensa_read_memory(target, xtensa->spill_loc, memop_size, reglen, regbuf); + if (status != ERROR_OK) { + LOG_TARGET_ERROR(target, "TIE result read"); + tieop_status = status; + } + unsigned int i; + for (i = 0; i < reglen; i++) + sprintf(*response_p + 2 * i, "%02x", regbuf[i]); + *(*response_p + 2 * i) = '\0'; + LOG_TARGET_DEBUG(target, "TIE response: %s", *response_p); + } + } + + /* Restore spill memory first, then report any previous errors */ + status = xtensa_write_memory(target, xtensa->spill_loc, memop_size, + xtensa->spill_bytes / memop_size, xtensa->spill_buf); + if (status != ERROR_OK) { + LOG_ERROR("Spill memory restore"); + error = XT_QERR_MEM; + goto xtensa_gdbqc_qxtreg_fail; + } + if (tieop_status != ERROR_OK) { + LOG_ERROR("TIE execution"); + error = XT_QERR_FAIL; + goto xtensa_gdbqc_qxtreg_fail; + } + return ERROR_OK; + +xtensa_gdbqc_qxtreg_fail: + strcpy(*response_p, xt_qerr[error].chrval); + return xt_qerr[error].intval; +} + +int xtensa_gdb_query_custom(struct target *target, const char *packet, char **response_p) +{ + struct xtensa *xtensa = target_to_xtensa(target); + enum xtensa_qerr_e error; + if (!packet || !response_p) { + LOG_TARGET_ERROR(target, "invalid parameter: packet %p response_p %p", packet, response_p); + return ERROR_FAIL; + } + + *response_p = xtensa->qpkt_resp; + if (strncmp(packet, "qxtn", 4) == 0) { + strcpy(*response_p, "OpenOCD"); + return ERROR_OK; + } else if (strncasecmp(packet, "qxtgdbversion=", 14) == 0) { + return ERROR_OK; + } else if ((strncmp(packet, "Qxtsis=", 7) == 0) || (strncmp(packet, "Qxtsds=", 7) == 0)) { + /* Confirm host cache params match core .cfg file */ + struct xtensa_cache_config *cachep = (packet[4] == 'i') ? + &xtensa->core_config->icache : &xtensa->core_config->dcache; + unsigned int line_size = 0, size = 0, way_count = 0; + sscanf(&packet[7], "%x,%x,%x", &line_size, &size, &way_count); + if ((cachep->line_size != line_size) || + (cachep->size != size) || + (cachep->way_count != way_count)) { + LOG_TARGET_WARNING(target, "%cCache mismatch; check xtensa-core-XXX.cfg file", + cachep == &xtensa->core_config->icache ? 'I' : 'D'); + } + strcpy(*response_p, "OK"); + return ERROR_OK; + } else if ((strncmp(packet, "Qxtiram=", 8) == 0) || (strncmp(packet, "Qxtirom=", 8) == 0)) { + /* Confirm host IRAM/IROM params match core .cfg file */ + struct xtensa_local_mem_config *memp = (packet[5] == 'a') ? + &xtensa->core_config->iram : &xtensa->core_config->irom; + unsigned int base = 0, size = 0, i; + char *pkt = (char *)&packet[7]; + do { + pkt++; + size = strtoul(pkt, &pkt, 16); + pkt++; + base = strtoul(pkt, &pkt, 16); + LOG_TARGET_DEBUG(target, "memcheck: %dB @ 0x%08x", size, base); + for (i = 0; i < memp->count; i++) { + if ((memp->regions[i].base == base) && (memp->regions[i].size == size)) + break; + } + if (i == memp->count) { + LOG_TARGET_WARNING(target, "%s mismatch; check xtensa-core-XXX.cfg file", + memp == &xtensa->core_config->iram ? "IRAM" : "IROM"); + break; + } + for (i = 0; i < 11; i++) { + pkt++; + strtoul(pkt, &pkt, 16); + } + } while (pkt && (pkt[0] == ',')); + strcpy(*response_p, "OK"); + return ERROR_OK; + } else if (strncmp(packet, "Qxtexcmlvl=", 11) == 0) { + /* Confirm host EXCM_LEVEL matches core .cfg file */ + unsigned int excm_level = strtoul(&packet[11], NULL, 0); + if (!xtensa->core_config->high_irq.enabled || + (excm_level != xtensa->core_config->high_irq.excm_level)) + LOG_TARGET_WARNING(target, "EXCM_LEVEL mismatch; check xtensa-core-XXX.cfg file"); + strcpy(*response_p, "OK"); + return ERROR_OK; + } else if ((strncmp(packet, "Qxtl2cs=", 8) == 0) || + (strncmp(packet, "Qxtl2ca=", 8) == 0) || + (strncmp(packet, "Qxtdensity=", 11) == 0)) { + strcpy(*response_p, "OK"); + return ERROR_OK; + } else if (strncmp(packet, "Qxtspill=", 9) == 0) { + char *delim; + uint32_t spill_loc = strtoul(packet + 9, &delim, 16); + if (*delim != ':') { + LOG_ERROR("Malformed Qxtspill packet"); + error = XT_QERR_INVAL; + goto xtensa_gdb_query_custom_fail; + } + xtensa->spill_loc = spill_loc; + xtensa->spill_bytes = strtoul(delim + 1, NULL, 16); + if (xtensa->spill_buf) + free(xtensa->spill_buf); + xtensa->spill_buf = calloc(1, xtensa->spill_bytes); + if (!xtensa->spill_buf) { + LOG_ERROR("Spill buf alloc"); + error = XT_QERR_MEM; + goto xtensa_gdb_query_custom_fail; + } + LOG_TARGET_DEBUG(target, "Set spill 0x%08" PRIx32 " (%d)", xtensa->spill_loc, xtensa->spill_bytes); + strcpy(*response_p, "OK"); + return ERROR_OK; + } else if (strncasecmp(packet, "qxtreg", 6) == 0) { + return xtensa_gdbqc_qxtreg(target, packet, response_p); + } else if ((strncmp(packet, "qTStatus", 8) == 0) || + (strncmp(packet, "qxtftie", 7) == 0) || + (strncmp(packet, "qxtstie", 7) == 0)) { + /* Return empty string to indicate trace, TIE wire debug are unsupported */ + strcpy(*response_p, ""); + return ERROR_OK; + } + + /* Warn for all other queries, but do not return errors */ + LOG_TARGET_WARNING(target, "Unknown target-specific query packet: %s", packet); + strcpy(*response_p, ""); + return ERROR_OK; + +xtensa_gdb_query_custom_fail: + strcpy(*response_p, xt_qerr[error].chrval); + return xt_qerr[error].intval; +} + +int xtensa_init_arch_info(struct target *target, struct xtensa *xtensa, + const struct xtensa_debug_module_config *dm_cfg) +{ + target->arch_info = xtensa; + xtensa->common_magic = XTENSA_COMMON_MAGIC; + xtensa->target = target; + xtensa->stepping_isr_mode = XT_STEPPING_ISR_ON; + + xtensa->core_config = calloc(1, sizeof(struct xtensa_config)); + if (!xtensa->core_config) { + LOG_ERROR("Xtensa configuration alloc failed\n"); + return ERROR_FAIL; + } + + /* Default cache settings are disabled with 1 way */ + xtensa->core_config->icache.way_count = 1; + xtensa->core_config->dcache.way_count = 1; + + /* chrval: AR3/AR4 register names will change with window mapping. + * intval: tracks whether scratch register was set through gdb P packet. + */ + for (enum xtensa_ar_scratch_set_e s = 0; s < XT_AR_SCRATCH_NUM; s++) { + xtensa->scratch_ars[s].chrval = calloc(8, sizeof(char)); + if (!xtensa->scratch_ars[s].chrval) { + for (enum xtensa_ar_scratch_set_e f = 0; f < s; f++) + free(xtensa->scratch_ars[f].chrval); + free(xtensa->core_config); + LOG_ERROR("Xtensa scratch AR alloc failed\n"); + return ERROR_FAIL; + } + xtensa->scratch_ars[s].intval = false; + sprintf(xtensa->scratch_ars[s].chrval, "%s%d", + ((s == XT_AR_SCRATCH_A3) || (s == XT_AR_SCRATCH_A4)) ? "a" : "ar", + ((s == XT_AR_SCRATCH_A3) || (s == XT_AR_SCRATCH_AR3)) ? 3 : 4); + } + + return xtensa_dm_init(&xtensa->dbg_mod, dm_cfg); +} + +void xtensa_set_permissive_mode(struct target *target, bool state) +{ + target_to_xtensa(target)->permissive_mode = state; +} + +int xtensa_target_init(struct command_context *cmd_ctx, struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + + xtensa->come_online_probes_num = 3; + xtensa->hw_brps = calloc(XT_HW_IBREAK_MAX_NUM, sizeof(struct breakpoint *)); + if (!xtensa->hw_brps) { + LOG_ERROR("Failed to alloc memory for HW breakpoints!"); + return ERROR_FAIL; + } + xtensa->hw_wps = calloc(XT_HW_DBREAK_MAX_NUM, sizeof(struct watchpoint *)); + if (!xtensa->hw_wps) { + free(xtensa->hw_brps); + LOG_ERROR("Failed to alloc memory for HW watchpoints!"); + return ERROR_FAIL; + } + xtensa->sw_brps = calloc(XT_SW_BREAKPOINTS_MAX_NUM, sizeof(struct xtensa_sw_breakpoint)); + if (!xtensa->sw_brps) { + free(xtensa->hw_brps); + free(xtensa->hw_wps); + LOG_ERROR("Failed to alloc memory for SW breakpoints!"); + return ERROR_FAIL; + } + + xtensa->spill_loc = 0xffffffff; + xtensa->spill_bytes = 0; + xtensa->spill_buf = NULL; + xtensa->probe_lsddr32p = -1; /* Probe for fast load/store operations */ + + return xtensa_build_reg_cache(target); +} + +static void xtensa_free_reg_cache(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + struct reg_cache *cache = xtensa->core_cache; + + if (cache) { + register_unlink_cache(&target->reg_cache, cache); + for (unsigned int i = 0; i < cache->num_regs; i++) { + free(xtensa->algo_context_backup[i]); + free(cache->reg_list[i].value); + } + free(xtensa->algo_context_backup); + free(cache->reg_list); + free(cache); + } + xtensa->core_cache = NULL; + xtensa->algo_context_backup = NULL; + + if (xtensa->empty_regs) { + for (unsigned int i = 0; i < xtensa->dbregs_num; i++) { + free((void *)xtensa->empty_regs[i].name); + free(xtensa->empty_regs[i].value); + } + free(xtensa->empty_regs); + } + xtensa->empty_regs = NULL; + if (xtensa->optregs) { + for (unsigned int i = 0; i < xtensa->num_optregs; i++) + free((void *)xtensa->optregs[i].name); + free(xtensa->optregs); + } + xtensa->optregs = NULL; +} + +void xtensa_target_deinit(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + + LOG_DEBUG("start"); + + if (target_was_examined(target)) { + int ret = xtensa_queue_dbg_reg_write(xtensa, XDMREG_DCRCLR, OCDDCR_ENABLEOCD); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to queue OCDDCR_ENABLEOCD clear operation!"); + return; + } + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + ret = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to clear OCDDCR_ENABLEOCD!"); + return; + } + xtensa_dm_deinit(&xtensa->dbg_mod); + } + xtensa_free_reg_cache(target); + free(xtensa->hw_brps); + free(xtensa->hw_wps); + free(xtensa->sw_brps); + if (xtensa->spill_buf) { + free(xtensa->spill_buf); + xtensa->spill_buf = NULL; + } + for (enum xtensa_ar_scratch_set_e s = 0; s < XT_AR_SCRATCH_NUM; s++) + free(xtensa->scratch_ars[s].chrval); + free(xtensa->core_config); +} + +const char *xtensa_get_gdb_arch(const struct target *target) +{ + return "xtensa"; +} + +/* exe <ascii-encoded hexadecimal instruction bytes> */ +static COMMAND_HELPER(xtensa_cmd_exe_do, struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* Process ascii-encoded hex byte string */ + const char *parm = CMD_ARGV[0]; + unsigned int parm_len = strlen(parm); + if ((parm_len >= 64) || (parm_len & 1)) { + command_print(CMD, "Invalid parameter length (%d): must be even, < 64 characters", parm_len); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + uint8_t ops[32]; + memset(ops, 0, 32); + unsigned int oplen = parm_len / 2; + char encoded_byte[3] = { 0, 0, 0 }; + for (unsigned int i = 0; i < oplen; i++) { + encoded_byte[0] = *parm++; + encoded_byte[1] = *parm++; + ops[i] = strtoul(encoded_byte, NULL, 16); + } + + /* GDB must handle state save/restore. + * Flush reg cache in case spill location is in an AR + * Update CPENABLE only for this execution; later restore cached copy + * Keep a copy of exccause in case executed code triggers an exception + */ + int status = xtensa_write_dirty_registers(target); + if (status != ERROR_OK) { + command_print(CMD, "%s: Failed to write back register cache.", target_name(target)); + return ERROR_FAIL; + } + xtensa_reg_val_t exccause = xtensa_reg_get(target, XT_REG_IDX_EXCCAUSE); + xtensa_reg_val_t cpenable = xtensa_reg_get(target, XT_REG_IDX_CPENABLE); + xtensa_reg_val_t a3 = xtensa_reg_get(target, XT_REG_IDX_A3); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, 0xffffffff); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, + xtensa_regs[XT_REG_IDX_CPENABLE].reg_num, XT_REG_A3)); + xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, a3); + xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3)); + + /* Queue instruction list and execute everything */ + LOG_TARGET_DEBUG(target, "execute stub: %s", CMD_ARGV[0]); + xtensa_queue_exec_ins_wide(xtensa, ops, oplen); /* Handles endian-swap */ + status = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (status != ERROR_OK) { + command_print(CMD, "exec: queue error %d", status); + } else { + status = xtensa_core_status_check(target); + if (status != ERROR_OK) + command_print(CMD, "exec: status error %d", status); + } + + /* Reread register cache and restore saved regs after instruction execution */ + if (xtensa_fetch_all_regs(target) != ERROR_OK) + command_print(CMD, "post-exec: register fetch error"); + if (status != ERROR_OK) { + command_print(CMD, "post-exec: EXCCAUSE 0x%02" PRIx32, + xtensa_reg_get(target, XT_REG_IDX_EXCCAUSE)); + } + xtensa_reg_set(target, XT_REG_IDX_EXCCAUSE, exccause); + xtensa_reg_set(target, XT_REG_IDX_CPENABLE, cpenable); + return status; +} + +COMMAND_HANDLER(xtensa_cmd_exe) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_exe_do, get_current_target(CMD_CTX)); +} + +/* xtdef <name> */ +COMMAND_HELPER(xtensa_cmd_xtdef_do, struct xtensa *xtensa) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + const char *core_name = CMD_ARGV[0]; + if (strcasecmp(core_name, "LX") == 0) { + xtensa->core_config->core_type = XT_LX; + } else if (strcasecmp(core_name, "NX") == 0) { + xtensa->core_config->core_type = XT_NX; + } else { + command_print(CMD, "xtdef [LX|NX]\n"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_xtdef) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +static inline bool xtensa_cmd_xtopt_legal_val(char *opt, int val, int min, int max) +{ + if ((val < min) || (val > max)) { + LOG_ERROR("xtopt %s (%d) out of range [%d..%d]\n", opt, val, min, max); + return false; + } + return true; +} + +/* xtopt <name> <value> */ +COMMAND_HELPER(xtensa_cmd_xtopt_do, struct xtensa *xtensa) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + const char *opt_name = CMD_ARGV[0]; + int opt_val = strtol(CMD_ARGV[1], NULL, 0); + if (strcasecmp(opt_name, "arnum") == 0) { + if (!xtensa_cmd_xtopt_legal_val("arnum", opt_val, 0, 64)) + return ERROR_COMMAND_ARGUMENT_INVALID; + xtensa->core_config->aregs_num = opt_val; + } else if (strcasecmp(opt_name, "windowed") == 0) { + if (!xtensa_cmd_xtopt_legal_val("windowed", opt_val, 0, 1)) + return ERROR_COMMAND_ARGUMENT_INVALID; + xtensa->core_config->windowed = opt_val; + } else if (strcasecmp(opt_name, "cpenable") == 0) { + if (!xtensa_cmd_xtopt_legal_val("cpenable", opt_val, 0, 1)) + return ERROR_COMMAND_ARGUMENT_INVALID; + xtensa->core_config->coproc = opt_val; + } else if (strcasecmp(opt_name, "exceptions") == 0) { + if (!xtensa_cmd_xtopt_legal_val("exceptions", opt_val, 0, 1)) + return ERROR_COMMAND_ARGUMENT_INVALID; + xtensa->core_config->exceptions = opt_val; + } else if (strcasecmp(opt_name, "intnum") == 0) { + if (!xtensa_cmd_xtopt_legal_val("intnum", opt_val, 0, 32)) + return ERROR_COMMAND_ARGUMENT_INVALID; + xtensa->core_config->irq.enabled = (opt_val > 0); + xtensa->core_config->irq.irq_num = opt_val; + } else if (strcasecmp(opt_name, "hipriints") == 0) { + if (!xtensa_cmd_xtopt_legal_val("hipriints", opt_val, 0, 1)) + return ERROR_COMMAND_ARGUMENT_INVALID; + xtensa->core_config->high_irq.enabled = opt_val; + } else if (strcasecmp(opt_name, "excmlevel") == 0) { + if (!xtensa_cmd_xtopt_legal_val("excmlevel", opt_val, 1, 6)) + return ERROR_COMMAND_ARGUMENT_INVALID; + if (!xtensa->core_config->high_irq.enabled) { + command_print(CMD, "xtopt excmlevel requires hipriints\n"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + xtensa->core_config->high_irq.excm_level = opt_val; + } else if (strcasecmp(opt_name, "intlevels") == 0) { + if (xtensa->core_config->core_type == XT_LX) { + if (!xtensa_cmd_xtopt_legal_val("intlevels", opt_val, 2, 6)) + return ERROR_COMMAND_ARGUMENT_INVALID; + } else { + if (!xtensa_cmd_xtopt_legal_val("intlevels", opt_val, 1, 255)) + return ERROR_COMMAND_ARGUMENT_INVALID; + } + if (!xtensa->core_config->high_irq.enabled) { + command_print(CMD, "xtopt intlevels requires hipriints\n"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + xtensa->core_config->high_irq.level_num = opt_val; + } else if (strcasecmp(opt_name, "debuglevel") == 0) { + if (xtensa->core_config->core_type == XT_LX) { + if (!xtensa_cmd_xtopt_legal_val("debuglevel", opt_val, 2, 6)) + return ERROR_COMMAND_ARGUMENT_INVALID; + } else { + if (!xtensa_cmd_xtopt_legal_val("debuglevel", opt_val, 0, 0)) + return ERROR_COMMAND_ARGUMENT_INVALID; + } + xtensa->core_config->debug.enabled = 1; + xtensa->core_config->debug.irq_level = opt_val; + } else if (strcasecmp(opt_name, "ibreaknum") == 0) { + if (!xtensa_cmd_xtopt_legal_val("ibreaknum", opt_val, 0, 2)) + return ERROR_COMMAND_ARGUMENT_INVALID; + xtensa->core_config->debug.ibreaks_num = opt_val; + } else if (strcasecmp(opt_name, "dbreaknum") == 0) { + if (!xtensa_cmd_xtopt_legal_val("dbreaknum", opt_val, 0, 2)) + return ERROR_COMMAND_ARGUMENT_INVALID; + xtensa->core_config->debug.dbreaks_num = opt_val; + } else if (strcasecmp(opt_name, "tracemem") == 0) { + if (!xtensa_cmd_xtopt_legal_val("tracemem", opt_val, 0, 256 * 1024)) + return ERROR_COMMAND_ARGUMENT_INVALID; + xtensa->core_config->trace.mem_sz = opt_val; + xtensa->core_config->trace.enabled = (opt_val > 0); + } else if (strcasecmp(opt_name, "tracememrev") == 0) { + if (!xtensa_cmd_xtopt_legal_val("tracememrev", opt_val, 0, 1)) + return ERROR_COMMAND_ARGUMENT_INVALID; + xtensa->core_config->trace.reversed_mem_access = opt_val; + } else if (strcasecmp(opt_name, "perfcount") == 0) { + if (!xtensa_cmd_xtopt_legal_val("perfcount", opt_val, 0, 8)) + return ERROR_COMMAND_ARGUMENT_INVALID; + xtensa->core_config->debug.perfcount_num = opt_val; + } else { + LOG_WARNING("Unknown xtensa command ignored: \"xtopt %s %s\"", CMD_ARGV[0], CMD_ARGV[1]); + return ERROR_OK; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_xtopt) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +/* xtmem <type> [parameters] */ +COMMAND_HELPER(xtensa_cmd_xtmem_do, struct xtensa *xtensa) +{ + struct xtensa_cache_config *cachep = NULL; + struct xtensa_local_mem_config *memp = NULL; + int mem_access = 0; + bool is_dcache = false; + + if (CMD_ARGC == 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + const char *mem_name = CMD_ARGV[0]; + if (strcasecmp(mem_name, "icache") == 0) { + cachep = &xtensa->core_config->icache; + } else if (strcasecmp(mem_name, "dcache") == 0) { + cachep = &xtensa->core_config->dcache; + is_dcache = true; + } else if (strcasecmp(mem_name, "l2cache") == 0) { + /* TODO: support L2 cache */ + } else if (strcasecmp(mem_name, "l2addr") == 0) { + /* TODO: support L2 cache */ + } else if (strcasecmp(mem_name, "iram") == 0) { + memp = &xtensa->core_config->iram; + mem_access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE; + } else if (strcasecmp(mem_name, "dram") == 0) { + memp = &xtensa->core_config->dram; + mem_access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE; + } else if (strcasecmp(mem_name, "sram") == 0) { + memp = &xtensa->core_config->sram; + mem_access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE; + } else if (strcasecmp(mem_name, "irom") == 0) { + memp = &xtensa->core_config->irom; + mem_access = XT_MEM_ACCESS_READ; + } else if (strcasecmp(mem_name, "drom") == 0) { + memp = &xtensa->core_config->drom; + mem_access = XT_MEM_ACCESS_READ; + } else if (strcasecmp(mem_name, "srom") == 0) { + memp = &xtensa->core_config->srom; + mem_access = XT_MEM_ACCESS_READ; + } else { + command_print(CMD, "xtmem types: <icache|dcache|l2cache|l2addr|iram|irom|dram|drom|sram|srom>\n"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if (cachep) { + if (CMD_ARGC != 4 && CMD_ARGC != 5) + return ERROR_COMMAND_SYNTAX_ERROR; + cachep->line_size = strtoul(CMD_ARGV[1], NULL, 0); + cachep->size = strtoul(CMD_ARGV[2], NULL, 0); + cachep->way_count = strtoul(CMD_ARGV[3], NULL, 0); + cachep->writeback = ((CMD_ARGC == 5) && is_dcache) ? + strtoul(CMD_ARGV[4], NULL, 0) : 0; + } else if (memp) { + if (CMD_ARGC != 3) + return ERROR_COMMAND_SYNTAX_ERROR; + struct xtensa_local_mem_region_config *memcfgp = &memp->regions[memp->count]; + memcfgp->base = strtoul(CMD_ARGV[1], NULL, 0); + memcfgp->size = strtoul(CMD_ARGV[2], NULL, 0); + memcfgp->access = mem_access; + memp->count++; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_xtmem) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +/* xtmpu <num FG seg> <min seg size> <lockable> <executeonly> */ +COMMAND_HELPER(xtensa_cmd_xtmpu_do, struct xtensa *xtensa) +{ + if (CMD_ARGC != 4) + return ERROR_COMMAND_SYNTAX_ERROR; + + unsigned int nfgseg = strtoul(CMD_ARGV[0], NULL, 0); + unsigned int minsegsize = strtoul(CMD_ARGV[1], NULL, 0); + unsigned int lockable = strtoul(CMD_ARGV[2], NULL, 0); + unsigned int execonly = strtoul(CMD_ARGV[3], NULL, 0); + + if ((nfgseg > 32)) { + command_print(CMD, "<nfgseg> must be within [0..32]\n"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } else if (minsegsize & (minsegsize - 1)) { + command_print(CMD, "<minsegsize> must be a power of 2 >= 32\n"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } else if (lockable > 1) { + command_print(CMD, "<lockable> must be 0 or 1\n"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } else if (execonly > 1) { + command_print(CMD, "<execonly> must be 0 or 1\n"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + xtensa->core_config->mpu.enabled = true; + xtensa->core_config->mpu.nfgseg = nfgseg; + xtensa->core_config->mpu.minsegsize = minsegsize; + xtensa->core_config->mpu.lockable = lockable; + xtensa->core_config->mpu.execonly = execonly; + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_xtmpu) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +/* xtmmu <NIREFILLENTRIES> <NDREFILLENTRIES> <IVARWAY56> <DVARWAY56> */ +COMMAND_HELPER(xtensa_cmd_xtmmu_do, struct xtensa *xtensa) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + unsigned int nirefillentries = strtoul(CMD_ARGV[0], NULL, 0); + unsigned int ndrefillentries = strtoul(CMD_ARGV[1], NULL, 0); + if ((nirefillentries != 16) && (nirefillentries != 32)) { + command_print(CMD, "<nirefillentries> must be 16 or 32\n"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } else if ((ndrefillentries != 16) && (ndrefillentries != 32)) { + command_print(CMD, "<ndrefillentries> must be 16 or 32\n"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + xtensa->core_config->mmu.enabled = true; + xtensa->core_config->mmu.itlb_entries_count = nirefillentries; + xtensa->core_config->mmu.dtlb_entries_count = ndrefillentries; + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_xtmmu) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +/* xtregs <numregs> + * xtreg <regname> <regnum> */ +COMMAND_HELPER(xtensa_cmd_xtreg_do, struct xtensa *xtensa) +{ + if (CMD_ARGC == 1) { + int32_t numregs = strtoul(CMD_ARGV[0], NULL, 0); + if ((numregs <= 0) || (numregs > UINT16_MAX)) { + command_print(CMD, "xtreg <numregs>: Invalid 'numregs' (%d)", numregs); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + if ((xtensa->genpkt_regs_num > 0) && (numregs < (int32_t)xtensa->genpkt_regs_num)) { + command_print(CMD, "xtregs (%d) must be larger than numgenregs (%d) (if xtregfmt specified)", + numregs, xtensa->genpkt_regs_num); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + xtensa->total_regs_num = numregs; + xtensa->core_regs_num = 0; + xtensa->num_optregs = 0; + /* A little more memory than required, but saves a second initialization pass */ + xtensa->optregs = calloc(xtensa->total_regs_num, sizeof(struct xtensa_reg_desc)); + if (!xtensa->optregs) { + LOG_ERROR("Failed to allocate xtensa->optregs!"); + return ERROR_FAIL; + } + return ERROR_OK; + } else if (CMD_ARGC != 2) { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + /* "xtregfmt contiguous" must be specified prior to the first "xtreg" definition + * if general register (g-packet) requests or contiguous register maps are supported */ + if (xtensa->regmap_contiguous && !xtensa->contiguous_regs_desc) { + xtensa->contiguous_regs_desc = calloc(xtensa->total_regs_num, sizeof(struct xtensa_reg_desc *)); + if (!xtensa->contiguous_regs_desc) { + LOG_ERROR("Failed to allocate xtensa->contiguous_regs_desc!"); + return ERROR_FAIL; + } + } + + const char *regname = CMD_ARGV[0]; + unsigned int regnum = strtoul(CMD_ARGV[1], NULL, 0); + if (regnum > UINT16_MAX) { + command_print(CMD, "<regnum> must be a 16-bit number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if ((xtensa->num_optregs + xtensa->core_regs_num) >= xtensa->total_regs_num) { + if (xtensa->total_regs_num) + command_print(CMD, "'xtreg %s 0x%04x': Too many registers (%d expected, %d core %d extended)", + regname, regnum, + xtensa->total_regs_num, xtensa->core_regs_num, xtensa->num_optregs); + else + command_print(CMD, "'xtreg %s 0x%04x': Number of registers unspecified", + regname, regnum); + return ERROR_FAIL; + } + + /* Determine whether register belongs in xtensa_regs[] or xtensa->xtensa_spec_regs[] */ + struct xtensa_reg_desc *rptr = &xtensa->optregs[xtensa->num_optregs]; + bool is_extended_reg = true; + unsigned int ridx; + for (ridx = 0; ridx < XT_NUM_REGS; ridx++) { + if (strcmp(CMD_ARGV[0], xtensa_regs[ridx].name) == 0) { + /* Flag core register as defined */ + rptr = &xtensa_regs[ridx]; + xtensa->core_regs_num++; + is_extended_reg = false; + break; + } + } + + rptr->exist = true; + if (is_extended_reg) { + /* Register ID, debugger-visible register ID */ + rptr->name = strdup(CMD_ARGV[0]); + rptr->dbreg_num = regnum; + rptr->reg_num = (regnum & XT_REG_INDEX_MASK); + xtensa->num_optregs++; + + /* Register type */ + if ((regnum & XT_REG_GENERAL_MASK) == XT_REG_GENERAL_VAL) { + rptr->type = XT_REG_GENERAL; + } else if ((regnum & XT_REG_USER_MASK) == XT_REG_USER_VAL) { + rptr->type = XT_REG_USER; + } else if ((regnum & XT_REG_FR_MASK) == XT_REG_FR_VAL) { + rptr->type = XT_REG_FR; + } else if ((regnum & XT_REG_SPECIAL_MASK) == XT_REG_SPECIAL_VAL) { + rptr->type = XT_REG_SPECIAL; + } else if ((regnum & XT_REG_RELGEN_MASK) == XT_REG_RELGEN_VAL) { + /* WARNING: For these registers, regnum points to the + * index of the corresponding ARx registers, NOT to + * the processor register number! */ + rptr->type = XT_REG_RELGEN; + rptr->reg_num += XT_REG_IDX_ARFIRST; + rptr->dbreg_num += XT_REG_IDX_ARFIRST; + } else if ((regnum & XT_REG_TIE_MASK) != 0) { + rptr->type = XT_REG_TIE; + } else { + rptr->type = XT_REG_OTHER; + } + + /* Register flags */ + if ((strcmp(rptr->name, "mmid") == 0) || (strcmp(rptr->name, "eraccess") == 0) || + (strcmp(rptr->name, "ddr") == 0) || (strcmp(rptr->name, "intset") == 0) || + (strcmp(rptr->name, "intclear") == 0)) + rptr->flags = XT_REGF_NOREAD; + else + rptr->flags = 0; + + if (rptr->reg_num == (XT_EPS_REG_NUM_BASE + xtensa->core_config->debug.irq_level) && + xtensa->core_config->core_type == XT_LX && rptr->type == XT_REG_SPECIAL) { + xtensa->eps_dbglevel_idx = XT_NUM_REGS + xtensa->num_optregs - 1; + LOG_DEBUG("Setting PS (%s) index to %d", rptr->name, xtensa->eps_dbglevel_idx); + } + if (xtensa->core_config->core_type == XT_NX) { + enum xtensa_nx_reg_idx idx = XT_NX_REG_IDX_NUM; + if (strcmp(rptr->name, "ibreakc0") == 0) + idx = XT_NX_REG_IDX_IBREAKC0; + else if (strcmp(rptr->name, "wb") == 0) + idx = XT_NX_REG_IDX_WB; + else if (strcmp(rptr->name, "ms") == 0) + idx = XT_NX_REG_IDX_MS; + else if (strcmp(rptr->name, "ievec") == 0) + idx = XT_NX_REG_IDX_IEVEC; + else if (strcmp(rptr->name, "ieextern") == 0) + idx = XT_NX_REG_IDX_IEEXTERN; + else if (strcmp(rptr->name, "mesr") == 0) + idx = XT_NX_REG_IDX_MESR; + else if (strcmp(rptr->name, "mesrclr") == 0) + idx = XT_NX_REG_IDX_MESRCLR; + if (idx < XT_NX_REG_IDX_NUM) { + if (xtensa->nx_reg_idx[idx] != 0) { + command_print(CMD, "nx_reg_idx[%d] previously set to %d", + idx, xtensa->nx_reg_idx[idx]); + return ERROR_FAIL; + } + xtensa->nx_reg_idx[idx] = XT_NUM_REGS + xtensa->num_optregs - 1; + LOG_DEBUG("NX reg %s: index %d (%d)", + rptr->name, xtensa->nx_reg_idx[idx], idx); + } + } + } else if (strcmp(rptr->name, "cpenable") == 0) { + xtensa->core_config->coproc = true; + } + + /* Build out list of contiguous registers in specified order */ + unsigned int running_reg_count = xtensa->num_optregs + xtensa->core_regs_num; + if (xtensa->contiguous_regs_desc) { + assert((running_reg_count <= xtensa->total_regs_num) && "contiguous register address internal error!"); + xtensa->contiguous_regs_desc[running_reg_count - 1] = rptr; + } + if (xtensa_extra_debug_log) + LOG_DEBUG("Added %s register %-16s: 0x%04x/0x%02x t%d (%d of %d)", + is_extended_reg ? "config-specific" : "core", + rptr->name, rptr->dbreg_num, rptr->reg_num, rptr->type, + is_extended_reg ? xtensa->num_optregs : ridx, + is_extended_reg ? xtensa->total_regs_num : XT_NUM_REGS); + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_xtreg) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +/* xtregfmt <contiguous|sparse> [numgregs] */ +COMMAND_HELPER(xtensa_cmd_xtregfmt_do, struct xtensa *xtensa) +{ + if ((CMD_ARGC == 1) || (CMD_ARGC == 2)) { + if (!strcasecmp(CMD_ARGV[0], "sparse")) { + return ERROR_OK; + } else if (!strcasecmp(CMD_ARGV[0], "contiguous")) { + xtensa->regmap_contiguous = true; + if (CMD_ARGC == 2) { + unsigned int numgregs = strtoul(CMD_ARGV[1], NULL, 0); + if ((numgregs <= 0) || + ((numgregs > xtensa->total_regs_num) && + (xtensa->total_regs_num > 0))) { + command_print(CMD, "xtregfmt: if specified, numgregs (%d) must be <= numregs (%d)", + numgregs, xtensa->total_regs_num); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + xtensa->genpkt_regs_num = numgregs; + } + return ERROR_OK; + } + } + return ERROR_COMMAND_SYNTAX_ERROR; +} + +COMMAND_HANDLER(xtensa_cmd_xtregfmt) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +COMMAND_HELPER(xtensa_cmd_permissive_mode_do, struct xtensa *xtensa) +{ + return CALL_COMMAND_HANDLER(handle_command_parse_bool, + &xtensa->permissive_mode, "xtensa permissive mode"); +} + +COMMAND_HANDLER(xtensa_cmd_permissive_mode) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +/* perfmon_enable <counter_id> <select> [mask] [kernelcnt] [tracelevel] */ +COMMAND_HELPER(xtensa_cmd_perfmon_enable_do, struct xtensa *xtensa) +{ + struct xtensa_perfmon_config config = { + .mask = 0xffff, + .kernelcnt = 0, + .tracelevel = -1 /* use DEBUGLEVEL by default */ + }; + + if (CMD_ARGC < 2 || CMD_ARGC > 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + unsigned int counter_id = strtoul(CMD_ARGV[0], NULL, 0); + if (counter_id >= XTENSA_MAX_PERF_COUNTERS) { + command_print(CMD, "counter_id should be < %d", XTENSA_MAX_PERF_COUNTERS); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + config.select = strtoul(CMD_ARGV[1], NULL, 0); + if (config.select > XTENSA_MAX_PERF_SELECT) { + command_print(CMD, "select should be < %d", XTENSA_MAX_PERF_SELECT); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if (CMD_ARGC >= 3) { + config.mask = strtoul(CMD_ARGV[2], NULL, 0); + if (config.mask > XTENSA_MAX_PERF_MASK) { + command_print(CMD, "mask should be < %d", XTENSA_MAX_PERF_MASK); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } + + if (CMD_ARGC >= 4) { + config.kernelcnt = strtoul(CMD_ARGV[3], NULL, 0); + if (config.kernelcnt > 1) { + command_print(CMD, "kernelcnt should be 0 or 1"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } + + if (CMD_ARGC >= 5) { + config.tracelevel = strtoul(CMD_ARGV[4], NULL, 0); + if (config.tracelevel > 7) { + command_print(CMD, "tracelevel should be <=7"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } + + if (config.tracelevel == -1) + config.tracelevel = xtensa->core_config->debug.irq_level; + + return xtensa_dm_perfmon_enable(&xtensa->dbg_mod, counter_id, &config); +} + +COMMAND_HANDLER(xtensa_cmd_perfmon_enable) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +/* perfmon_dump [counter_id] */ +COMMAND_HELPER(xtensa_cmd_perfmon_dump_do, struct xtensa *xtensa) +{ + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + int counter_id = -1; + if (CMD_ARGC == 1) { + counter_id = strtol(CMD_ARGV[0], NULL, 0); + if (counter_id > XTENSA_MAX_PERF_COUNTERS) { + command_print(CMD, "counter_id should be < %d", XTENSA_MAX_PERF_COUNTERS); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } + + unsigned int counter_start = (counter_id < 0) ? 0 : counter_id; + unsigned int counter_end = (counter_id < 0) ? XTENSA_MAX_PERF_COUNTERS : counter_id + 1; + for (unsigned int counter = counter_start; counter < counter_end; ++counter) { + char result_buf[128] = { 0 }; + size_t result_pos = snprintf(result_buf, sizeof(result_buf), "Counter %d: ", counter); + struct xtensa_perfmon_result result; + int res = xtensa_dm_perfmon_dump(&xtensa->dbg_mod, counter, &result); + if (res != ERROR_OK) + return res; + snprintf(result_buf + result_pos, sizeof(result_buf) - result_pos, + "%-12" PRIu64 "%s", + result.value, + result.overflow ? " (overflow)" : ""); + command_print(CMD, "%s", result_buf); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_perfmon_dump) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +COMMAND_HELPER(xtensa_cmd_mask_interrupts_do, struct xtensa *xtensa) +{ + int state = -1; + + if (CMD_ARGC < 1) { + const char *st; + state = xtensa->stepping_isr_mode; + if (state == XT_STEPPING_ISR_ON) + st = "OFF"; + else if (state == XT_STEPPING_ISR_OFF) + st = "ON"; + else + st = "UNKNOWN"; + command_print(CMD, "Current ISR step mode: %s", st); + return ERROR_OK; + } + + if (xtensa->core_config->core_type == XT_NX) { + command_print(CMD, "ERROR: ISR step mode only supported on Xtensa LX"); + return ERROR_FAIL; + } + + /* Masking is ON -> interrupts during stepping are OFF, and vice versa */ + if (!strcasecmp(CMD_ARGV[0], "off")) + state = XT_STEPPING_ISR_ON; + else if (!strcasecmp(CMD_ARGV[0], "on")) + state = XT_STEPPING_ISR_OFF; + + if (state == -1) { + command_print(CMD, "Argument unknown. Please pick one of ON, OFF"); + return ERROR_FAIL; + } + xtensa->stepping_isr_mode = state; + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_mask_interrupts) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +COMMAND_HELPER(xtensa_cmd_smpbreak_do, struct target *target) +{ + int res; + uint32_t val = 0; + + if (CMD_ARGC >= 1) { + for (unsigned int i = 0; i < CMD_ARGC; i++) { + if (!strcasecmp(CMD_ARGV[0], "none")) { + val = 0; + } else if (!strcasecmp(CMD_ARGV[i], "BreakIn")) { + val |= OCDDCR_BREAKINEN; + } else if (!strcasecmp(CMD_ARGV[i], "BreakOut")) { + val |= OCDDCR_BREAKOUTEN; + } else if (!strcasecmp(CMD_ARGV[i], "RunStallIn")) { + val |= OCDDCR_RUNSTALLINEN; + } else if (!strcasecmp(CMD_ARGV[i], "DebugModeOut")) { + val |= OCDDCR_DEBUGMODEOUTEN; + } else if (!strcasecmp(CMD_ARGV[i], "BreakInOut")) { + val |= OCDDCR_BREAKINEN | OCDDCR_BREAKOUTEN; + } else if (!strcasecmp(CMD_ARGV[i], "RunStall")) { + val |= OCDDCR_RUNSTALLINEN | OCDDCR_DEBUGMODEOUTEN; + } else { + command_print(CMD, "Unknown arg %s", CMD_ARGV[i]); + command_print( + CMD, + "use either BreakInOut, None or RunStall as arguments, or any combination of BreakIn, BreakOut, RunStallIn and DebugModeOut."); + return ERROR_OK; + } + } + res = xtensa_smpbreak_set(target, val); + if (res != ERROR_OK) + command_print(CMD, "Failed to set smpbreak config %d", res); + } else { + struct xtensa *xtensa = target_to_xtensa(target); + res = xtensa_smpbreak_read(xtensa, &val); + if (res == ERROR_OK) + command_print(CMD, "Current bits set:%s%s%s%s", + (val & OCDDCR_BREAKINEN) ? " BreakIn" : "", + (val & OCDDCR_BREAKOUTEN) ? " BreakOut" : "", + (val & OCDDCR_RUNSTALLINEN) ? " RunStallIn" : "", + (val & OCDDCR_DEBUGMODEOUTEN) ? " DebugModeOut" : "" + ); + else + command_print(CMD, "Failed to get smpbreak config %d", res); + } + return res; +} + +COMMAND_HANDLER(xtensa_cmd_smpbreak) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, + get_current_target(CMD_CTX)); +} + +COMMAND_HELPER(xtensa_cmd_dm_rw_do, struct xtensa *xtensa) +{ + if (CMD_ARGC == 1) { + // read: xtensa dm addr + uint32_t addr = strtoul(CMD_ARGV[0], NULL, 0); + uint32_t val; + int res = xtensa_dm_read(&xtensa->dbg_mod, addr, &val); + if (res == ERROR_OK) + command_print(CMD, "xtensa DM(0x%08" PRIx32 ") -> 0x%08" PRIx32, addr, val); + else + command_print(CMD, "xtensa DM(0x%08" PRIx32 ") : read ERROR %" PRId32, addr, res); + return res; + } else if (CMD_ARGC == 2) { + // write: xtensa dm addr value + uint32_t addr = strtoul(CMD_ARGV[0], NULL, 0); + uint32_t val = strtoul(CMD_ARGV[1], NULL, 0); + int res = xtensa_dm_write(&xtensa->dbg_mod, addr, val); + if (res == ERROR_OK) + command_print(CMD, "xtensa DM(0x%08" PRIx32 ") <- 0x%08" PRIx32, addr, val); + else + command_print(CMD, "xtensa DM(0x%08" PRIx32 ") : write ERROR %" PRId32, addr, res); + return res; + } + return ERROR_COMMAND_SYNTAX_ERROR; +} + +COMMAND_HANDLER(xtensa_cmd_dm_rw) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_dm_rw_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +COMMAND_HELPER(xtensa_cmd_tracestart_do, struct xtensa *xtensa) +{ + struct xtensa_trace_status trace_status; + struct xtensa_trace_start_config cfg = { + .stoppc = 0, + .stopmask = XTENSA_STOPMASK_DISABLED, + .after = 0, + .after_is_words = false + }; + + /* Parse arguments */ + for (unsigned int i = 0; i < CMD_ARGC; i++) { + if ((!strcasecmp(CMD_ARGV[i], "pc")) && CMD_ARGC > i) { + char *e; + i++; + cfg.stoppc = strtol(CMD_ARGV[i], &e, 0); + cfg.stopmask = 0; + if (*e == '/') + cfg.stopmask = strtol(e, NULL, 0); + } else if ((!strcasecmp(CMD_ARGV[i], "after")) && CMD_ARGC > i) { + i++; + cfg.after = strtol(CMD_ARGV[i], NULL, 0); + } else if (!strcasecmp(CMD_ARGV[i], "ins")) { + cfg.after_is_words = 0; + } else if (!strcasecmp(CMD_ARGV[i], "words")) { + cfg.after_is_words = 1; + } else { + command_print(CMD, "Did not understand %s", CMD_ARGV[i]); + return ERROR_FAIL; + } + } + + int res = xtensa_dm_trace_status_read(&xtensa->dbg_mod, &trace_status); + if (res != ERROR_OK) + return res; + if (trace_status.stat & TRAXSTAT_TRACT) { + LOG_WARNING("Silently stop active tracing!"); + res = xtensa_dm_trace_stop(&xtensa->dbg_mod, false); + if (res != ERROR_OK) + return res; + } + + res = xtensa_dm_trace_start(&xtensa->dbg_mod, &cfg); + if (res != ERROR_OK) + return res; + + xtensa->trace_active = true; + command_print(CMD, "Trace started."); + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_tracestart) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +COMMAND_HELPER(xtensa_cmd_tracestop_do, struct xtensa *xtensa) +{ + struct xtensa_trace_status trace_status; + + int res = xtensa_dm_trace_status_read(&xtensa->dbg_mod, &trace_status); + if (res != ERROR_OK) + return res; + + if (!(trace_status.stat & TRAXSTAT_TRACT)) { + command_print(CMD, "No trace is currently active."); + return ERROR_FAIL; + } + + res = xtensa_dm_trace_stop(&xtensa->dbg_mod, true); + if (res != ERROR_OK) + return res; + + xtensa->trace_active = false; + command_print(CMD, "Trace stop triggered."); + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_tracestop) +{ + return CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do, + target_to_xtensa(get_current_target(CMD_CTX))); +} + +COMMAND_HELPER(xtensa_cmd_tracedump_do, struct xtensa *xtensa, const char *fname) +{ + struct xtensa_trace_config trace_config; + struct xtensa_trace_status trace_status; + uint32_t memsz, wmem; + + int res = xtensa_dm_trace_status_read(&xtensa->dbg_mod, &trace_status); + if (res != ERROR_OK) + return res; + + if (trace_status.stat & TRAXSTAT_TRACT) { + command_print(CMD, "Tracing is still active. Please stop it first."); + return ERROR_FAIL; + } + + res = xtensa_dm_trace_config_read(&xtensa->dbg_mod, &trace_config); + if (res != ERROR_OK) + return res; + + if (!(trace_config.ctrl & TRAXCTRL_TREN)) { + command_print(CMD, "No active trace found; nothing to dump."); + return ERROR_FAIL; + } + + memsz = trace_config.memaddr_end - trace_config.memaddr_start + 1; + command_print(CMD, "Total trace memory: %d words", memsz); + if ((trace_config.addr & + ((TRAXADDR_TWRAP_MASK << TRAXADDR_TWRAP_SHIFT) | TRAXADDR_TWSAT)) == 0) { + /*Memory hasn't overwritten itself yet. */ + wmem = trace_config.addr & TRAXADDR_TADDR_MASK; + command_print(CMD, "...but trace is only %d words", wmem); + if (wmem < memsz) + memsz = wmem; + } else { + if (trace_config.addr & TRAXADDR_TWSAT) { + command_print(CMD, "Real trace is many times longer than that (overflow)"); + } else { + uint32_t trc_sz = (trace_config.addr >> TRAXADDR_TWRAP_SHIFT) & TRAXADDR_TWRAP_MASK; + trc_sz = (trc_sz * memsz) + (trace_config.addr & TRAXADDR_TADDR_MASK); + command_print(CMD, "Real trace is %d words, but the start has been truncated.", trc_sz); + } + } + + uint8_t *tracemem = malloc(memsz * 4); + if (!tracemem) { + command_print(CMD, "Failed to alloc memory for trace data!"); + return ERROR_FAIL; + } + res = xtensa_dm_trace_data_read(&xtensa->dbg_mod, tracemem, memsz * 4); + if (res != ERROR_OK) { + free(tracemem); + return res; + } + + int f = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (f <= 0) { + free(tracemem); + command_print(CMD, "Unable to open file %s", fname); + return ERROR_FAIL; + } + if (write(f, tracemem, memsz * 4) != (int)memsz * 4) + command_print(CMD, "Unable to write to file %s", fname); + else + command_print(CMD, "Written %d bytes of trace data to %s", memsz * 4, fname); + close(f); + + bool is_all_zeroes = true; + for (unsigned int i = 0; i < memsz * 4; i++) { + if (tracemem[i] != 0) { + is_all_zeroes = false; + break; + } + } + free(tracemem); + if (is_all_zeroes) + command_print( + CMD, + "WARNING: File written is all zeroes. Are you sure you enabled trace memory?"); + + return ERROR_OK; +} + +COMMAND_HANDLER(xtensa_cmd_tracedump) +{ + if (CMD_ARGC != 1) { + command_print(CMD, "Command takes exactly 1 parameter.Need filename to dump to as output!"); + return ERROR_FAIL; + } + + return CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do, + target_to_xtensa(get_current_target(CMD_CTX)), CMD_ARGV[0]); +} + +static const struct command_registration xtensa_any_command_handlers[] = { + { + .name = "xtdef", + .handler = xtensa_cmd_xtdef, + .mode = COMMAND_CONFIG, + .help = "Configure Xtensa core type", + .usage = "<type>", + }, + { + .name = "xtopt", + .handler = xtensa_cmd_xtopt, + .mode = COMMAND_CONFIG, + .help = "Configure Xtensa core option", + .usage = "<name> <value>", + }, + { + .name = "xtmem", + .handler = xtensa_cmd_xtmem, + .mode = COMMAND_CONFIG, + .help = "Configure Xtensa memory/cache option", + .usage = "<type> [parameters]", + }, + { + .name = "xtmmu", + .handler = xtensa_cmd_xtmmu, + .mode = COMMAND_CONFIG, + .help = "Configure Xtensa MMU option", + .usage = "<NIREFILLENTRIES> <NDREFILLENTRIES> <IVARWAY56> <DVARWAY56>", + }, + { + .name = "xtmpu", + .handler = xtensa_cmd_xtmpu, + .mode = COMMAND_CONFIG, + .help = "Configure Xtensa MPU option", + .usage = "<num FG seg> <min seg size> <lockable> <executeonly>", + }, + { + .name = "xtreg", + .handler = xtensa_cmd_xtreg, + .mode = COMMAND_CONFIG, + .help = "Configure Xtensa register", + .usage = "<regname> <regnum>", + }, + { + .name = "xtregs", + .handler = xtensa_cmd_xtreg, + .mode = COMMAND_CONFIG, + .help = "Configure number of Xtensa registers", + .usage = "<numregs>", + }, + { + .name = "xtregfmt", + .handler = xtensa_cmd_xtregfmt, + .mode = COMMAND_CONFIG, + .help = "Configure format of Xtensa register map", + .usage = "<contiguous|sparse> [numgregs]", + }, + { + .name = "set_permissive", + .handler = xtensa_cmd_permissive_mode, + .mode = COMMAND_ANY, + .help = "When set to 1, enable Xtensa permissive mode (fewer client-side checks)", + .usage = "[0|1]", + }, + { + .name = "maskisr", + .handler = xtensa_cmd_mask_interrupts, + .mode = COMMAND_ANY, + .help = "mask Xtensa interrupts at step", + .usage = "['on'|'off']", + }, + { + .name = "smpbreak", + .handler = xtensa_cmd_smpbreak, + .mode = COMMAND_ANY, + .help = "Set the way the CPU chains OCD breaks", + .usage = "[none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]", + }, + { + .name = "dm", + .handler = xtensa_cmd_dm_rw, + .mode = COMMAND_ANY, + .help = "Xtensa DM read/write", + .usage = "addr [value]" + }, + { + .name = "perfmon_enable", + .handler = xtensa_cmd_perfmon_enable, + .mode = COMMAND_EXEC, + .help = "Enable and start performance counter", + .usage = "<counter_id> <select> [mask] [kernelcnt] [tracelevel]", + }, + { + .name = "perfmon_dump", + .handler = xtensa_cmd_perfmon_dump, + .mode = COMMAND_EXEC, + .help = "Dump performance counter value. If no argument specified, dumps all counters.", + .usage = "[counter_id]", + }, + { + .name = "tracestart", + .handler = xtensa_cmd_tracestart, + .mode = COMMAND_EXEC, + .help = + "Tracing: Set up and start a trace. Optionally set stop trigger address and amount of data captured after.", + .usage = "[pc <pcval>/[maskbitcount]] [after <n> [ins|words]]", + }, + { + .name = "tracestop", + .handler = xtensa_cmd_tracestop, + .mode = COMMAND_EXEC, + .help = "Tracing: Stop current trace as started by the tracestart command", + .usage = "", + }, + { + .name = "tracedump", + .handler = xtensa_cmd_tracedump, + .mode = COMMAND_EXEC, + .help = "Tracing: Dump trace memory to a files. One file per core.", + .usage = "<outfile>", + }, + { + .name = "exe", + .handler = xtensa_cmd_exe, + .mode = COMMAND_ANY, + .help = "Xtensa stub execution", + .usage = "<ascii-encoded hexadecimal instruction bytes>", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration xtensa_command_handlers[] = { + { + .name = "xtensa", + .mode = COMMAND_ANY, + .help = "Xtensa command group", + .usage = "", + .chain = xtensa_any_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; diff --git a/src/target/xtensa/xtensa.h b/src/target/xtensa/xtensa.h new file mode 100644 index 0000000000..a220021a68 --- /dev/null +++ b/src/target/xtensa/xtensa.h @@ -0,0 +1,446 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Generic Xtensa target * + * Copyright (C) 2020-2022 Cadence Design Systems, Inc. * + * Copyright (C) 2019 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_XTENSA_H +#define OPENOCD_TARGET_XTENSA_H + +#include "assert.h" +#include <target/target.h> +#include <target/breakpoints.h> +#include "xtensa_regs.h" +#include "xtensa_debug_module.h" + +/** + * @file + * Holds the interface to Xtensa cores. + */ + +/* Big-endian vs. little-endian detection */ +#define XT_ISBE(X) ((X)->target->endianness == TARGET_BIG_ENDIAN) + +/* 24-bit break; BE version field-swapped then byte-swapped for use in memory R/W fns */ +#define XT_INS_BREAK_LE(S, T) (0x004000 | (((S) & 0xF) << 8) | (((T) & 0xF) << 4)) +#define XT_INS_BREAK_BE(S, T) (0x000400 | (((S) & 0xF) << 12) | ((T) & 0xF)) +#define XT_INS_BREAK(X, S, T) (XT_ISBE(X) ? XT_INS_BREAK_BE(S, T) : XT_INS_BREAK_LE(S, T)) + +/* 16-bit break; BE version field-swapped then byte-swapped for use in memory R/W fns */ +#define XT_INS_BREAKN_LE(IMM4) (0xF02D | (((IMM4) & 0xF) << 8)) +#define XT_INS_BREAKN_BE(IMM4) (0x0FD2 | (((IMM4) & 0xF) << 12)) +#define XT_INS_BREAKN(X, IMM4) (XT_ISBE(X) ? XT_INS_BREAKN_BE(IMM4) : XT_INS_BREAKN_LE(IMM4)) + +#define XT_ISNS_SZ_MAX 3 + +/* PS register bits (LX) */ +#define XT_PS_RING(_v_) ((uint32_t)((_v_) & 0x3) << 6) +#define XT_PS_RING_MSK (0x3 << 6) +#define XT_PS_RING_GET(_v_) (((_v_) >> 6) & 0x3) +#define XT_PS_CALLINC_MSK (0x3 << 16) +#define XT_PS_OWB_MSK (0xF << 8) +#define XT_PS_WOE_MSK BIT(18) + +/* PS register bits (NX) */ +#define XT_PS_DIEXC_MSK BIT(2) + +/* MS register bits (NX) */ +#define XT_MS_DE_MSK BIT(5) +#define XT_MS_DISPST_MSK (0x1f) +#define XT_MS_DISPST_DBG (0x10) + +/* WB register bits (NX) */ +#define XT_WB_P_SHIFT (0) +#define XT_WB_P_MSK (0x7U << XT_WB_P_SHIFT) +#define XT_WB_C_SHIFT (4) +#define XT_WB_C_MSK (0x7U << XT_WB_C_SHIFT) +#define XT_WB_N_SHIFT (8) +#define XT_WB_N_MSK (0x7U << XT_WB_N_SHIFT) +#define XT_WB_S_SHIFT (30) +#define XT_WB_S_MSK (0x3U << XT_WB_S_SHIFT) + +/* IBREAKC register bits (NX) */ +#define XT_IBREAKC_FB (0x80000000) + +/* Definitions for imprecise exception registers (NX) */ +#define XT_IMPR_EXC_MSK (0x00000013) +#define XT_MESRCLR_IMPR_EXC_MSK (0x00000090) + +#define XT_LOCAL_MEM_REGIONS_NUM_MAX 8 + +#define XT_AREGS_NUM_MAX 64 +#define XT_USER_REGS_NUM_MAX 256 + +#define XT_MEM_ACCESS_NONE 0x0 +#define XT_MEM_ACCESS_READ 0x1 +#define XT_MEM_ACCESS_WRITE 0x2 + +#define XT_MAX_TIE_REG_WIDTH (512) /* TIE register file max 4096 bits */ +#define XT_QUERYPKT_RESP_MAX (XT_MAX_TIE_REG_WIDTH * 2 + 1) + +enum xtensa_qerr_e { + XT_QERR_INTERNAL = 0, + XT_QERR_FAIL, + XT_QERR_INVAL, + XT_QERR_MEM, + XT_QERR_NUM, +}; + +/* An and ARn registers potentially used as scratch regs */ +enum xtensa_ar_scratch_set_e { + XT_AR_SCRATCH_A3 = 0, + XT_AR_SCRATCH_AR3, + XT_AR_SCRATCH_A4, + XT_AR_SCRATCH_AR4, + XT_AR_SCRATCH_NUM +}; + +struct xtensa_keyval_info_s { + char *chrval; + int intval; +}; + +enum xtensa_type { + XT_UNDEF = 0, + XT_LX, + XT_NX, +}; + +struct xtensa_cache_config { + uint8_t way_count; + uint32_t line_size; + uint32_t size; + int writeback; +}; + +struct xtensa_local_mem_region_config { + target_addr_t base; + uint32_t size; + int access; +}; + +struct xtensa_local_mem_config { + uint16_t count; + struct xtensa_local_mem_region_config regions[XT_LOCAL_MEM_REGIONS_NUM_MAX]; +}; + +struct xtensa_mmu_config { + bool enabled; + uint8_t itlb_entries_count; + uint8_t dtlb_entries_count; +}; + +struct xtensa_mpu_config { + bool enabled; + uint8_t nfgseg; + uint32_t minsegsize; + bool lockable; + bool execonly; +}; + +struct xtensa_irq_config { + bool enabled; + uint8_t irq_num; +}; + +struct xtensa_high_prio_irq_config { + bool enabled; + uint8_t level_num; + uint8_t excm_level; +}; + +struct xtensa_debug_config { + bool enabled; + uint8_t irq_level; + uint8_t ibreaks_num; + uint8_t dbreaks_num; + uint8_t perfcount_num; +}; + +struct xtensa_tracing_config { + bool enabled; + uint32_t mem_sz; + bool reversed_mem_access; +}; + +struct xtensa_config { + enum xtensa_type core_type; + uint8_t aregs_num; + bool windowed; + bool coproc; + bool exceptions; + struct xtensa_irq_config irq; + struct xtensa_high_prio_irq_config high_irq; + struct xtensa_mmu_config mmu; + struct xtensa_mpu_config mpu; + struct xtensa_debug_config debug; + struct xtensa_tracing_config trace; + struct xtensa_cache_config icache; + struct xtensa_cache_config dcache; + struct xtensa_local_mem_config irom; + struct xtensa_local_mem_config iram; + struct xtensa_local_mem_config drom; + struct xtensa_local_mem_config dram; + struct xtensa_local_mem_config sram; + struct xtensa_local_mem_config srom; +}; + +typedef uint32_t xtensa_insn_t; + +enum xtensa_stepping_isr_mode { + XT_STEPPING_ISR_OFF, /* interrupts are disabled during stepping */ + XT_STEPPING_ISR_ON, /* interrupts are enabled during stepping */ +}; + +enum xtensa_nx_reg_idx { + XT_NX_REG_IDX_IBREAKC0 = 0, + XT_NX_REG_IDX_WB, + XT_NX_REG_IDX_MS, + XT_NX_REG_IDX_IEVEC, /* IEVEC, IEEXTERN, and MESR must be contiguous */ + XT_NX_REG_IDX_IEEXTERN, + XT_NX_REG_IDX_MESR, + XT_NX_REG_IDX_MESRCLR, + XT_NX_REG_IDX_NUM +}; + +/* Only supported in cores with in-CPU MMU. None of Espressif chips as of now. */ +enum xtensa_mode { + XT_MODE_RING0, + XT_MODE_RING1, + XT_MODE_RING2, + XT_MODE_RING3, + XT_MODE_ANY /* special value to run algorithm in current core mode */ +}; + +struct xtensa_sw_breakpoint { + struct breakpoint *oocd_bp; + /* original insn */ + uint8_t insn[XT_ISNS_SZ_MAX]; + /* original insn size */ + uint8_t insn_sz; /* 2 or 3 bytes */ +}; + +/** + * Xtensa algorithm data. + */ +struct xtensa_algorithm { + /** User can set this to specify which core mode algorithm should be run in. */ + enum xtensa_mode core_mode; + /** Used internally to backup and restore core state. */ + enum target_debug_reason ctx_debug_reason; + xtensa_reg_val_t ctx_ps; +}; + +#define XTENSA_COMMON_MAGIC 0x54E4E555U + +/** + * Represents a generic Xtensa core. + */ +struct xtensa { + unsigned int common_magic; + struct xtensa_chip_common *xtensa_chip; + struct xtensa_config *core_config; + struct xtensa_debug_module dbg_mod; + struct reg_cache *core_cache; + unsigned int total_regs_num; + unsigned int core_regs_num; + bool regmap_contiguous; + unsigned int genpkt_regs_num; + struct xtensa_reg_desc **contiguous_regs_desc; + struct reg **contiguous_regs_list; + /* Per-config Xtensa registers as specified via "xtreg" in xtensa-core*.cfg */ + struct xtensa_reg_desc *optregs; + unsigned int num_optregs; + struct reg *empty_regs; + char qpkt_resp[XT_QUERYPKT_RESP_MAX]; + /* An array of pointers to buffers to backup registers' values while algo is run on target. + * Size is 'regs_num'. */ + void **algo_context_backup; + unsigned int eps_dbglevel_idx; + unsigned int dbregs_num; + struct target *target; + bool reset_asserted; + enum xtensa_stepping_isr_mode stepping_isr_mode; + struct breakpoint **hw_brps; + struct watchpoint **hw_wps; + struct xtensa_sw_breakpoint *sw_brps; + bool trace_active; + bool permissive_mode; /* bypass memory checks */ + bool suppress_dsr_errors; + uint32_t smp_break; + uint32_t spill_loc; + unsigned int spill_bytes; + uint8_t *spill_buf; + int8_t probe_lsddr32p; + /* Sometimes debug module's 'powered' bit is cleared after reset, but get set after some + * time.This is the number of polling periods after which core is considered to be powered + * off (marked as unexamined) if the bit retains to be cleared (e.g. if core is disabled by + * SW running on target).*/ + uint8_t come_online_probes_num; + bool proc_syscall; + bool halt_request; + uint32_t nx_stop_cause; + uint32_t nx_reg_idx[XT_NX_REG_IDX_NUM]; + struct xtensa_keyval_info_s scratch_ars[XT_AR_SCRATCH_NUM]; + bool regs_fetched; /* true after first register fetch completed successfully */ +}; + +static inline struct xtensa *target_to_xtensa(struct target *target) +{ + assert(target); + struct xtensa *xtensa = target->arch_info; + assert(xtensa->common_magic == XTENSA_COMMON_MAGIC); + return xtensa; +} + +int xtensa_init_arch_info(struct target *target, + struct xtensa *xtensa, + const struct xtensa_debug_module_config *dm_cfg); +int xtensa_target_init(struct command_context *cmd_ctx, struct target *target); +void xtensa_target_deinit(struct target *target); + +static inline bool xtensa_addr_in_mem(const struct xtensa_local_mem_config *mem, uint32_t addr) +{ + for (unsigned int i = 0; i < mem->count; i++) { + if (addr >= mem->regions[i].base && + addr < mem->regions[i].base + mem->regions[i].size) + return true; + } + return false; +} + +static inline bool xtensa_data_addr_valid(struct target *target, uint32_t addr) +{ + struct xtensa *xtensa = target_to_xtensa(target); + + if (xtensa_addr_in_mem(&xtensa->core_config->drom, addr)) + return true; + if (xtensa_addr_in_mem(&xtensa->core_config->dram, addr)) + return true; + if (xtensa_addr_in_mem(&xtensa->core_config->sram, addr)) + return true; + return false; +} + +static inline int xtensa_queue_dbg_reg_read(struct xtensa *xtensa, enum xtensa_dm_reg reg, uint8_t *data) +{ + struct xtensa_debug_module *dm = &xtensa->dbg_mod; + + if (!xtensa->core_config->trace.enabled && + (reg <= XDMREG_MEMADDREND || (reg >= XDMREG_PMG && reg <= XDMREG_PMSTAT7))) { + LOG_ERROR("Can not access %u reg when Trace Port option disabled!", reg); + return ERROR_FAIL; + } + return dm->dbg_ops->queue_reg_read(dm, reg, data); +} + +static inline int xtensa_queue_dbg_reg_write(struct xtensa *xtensa, enum xtensa_dm_reg reg, uint32_t data) +{ + struct xtensa_debug_module *dm = &xtensa->dbg_mod; + + if (!xtensa->core_config->trace.enabled && + (reg <= XDMREG_MEMADDREND || (reg >= XDMREG_PMG && reg <= XDMREG_PMSTAT7))) { + LOG_ERROR("Can not access %u reg when Trace Port option disabled!", reg); + return ERROR_FAIL; + } + return dm->dbg_ops->queue_reg_write(dm, reg, data); +} + +static inline int xtensa_core_status_clear(struct target *target, uint32_t bits) +{ + struct xtensa *xtensa = target_to_xtensa(target); + return xtensa_dm_core_status_clear(&xtensa->dbg_mod, bits); +} + +int xtensa_core_status_check(struct target *target); + +int xtensa_examine(struct target *target); +int xtensa_wakeup(struct target *target); +int xtensa_smpbreak_set(struct target *target, uint32_t set); +int xtensa_smpbreak_get(struct target *target, uint32_t *val); +int xtensa_smpbreak_write(struct xtensa *xtensa, uint32_t set); +int xtensa_smpbreak_read(struct xtensa *xtensa, uint32_t *val); +xtensa_reg_val_t xtensa_reg_get(struct target *target, enum xtensa_reg_id reg_id); +void xtensa_reg_set(struct target *target, enum xtensa_reg_id reg_id, xtensa_reg_val_t value); +void xtensa_reg_set_deep_relgen(struct target *target, enum xtensa_reg_id a_idx, xtensa_reg_val_t value); +int xtensa_fetch_all_regs(struct target *target); +int xtensa_get_gdb_reg_list(struct target *target, + struct reg **reg_list[], + int *reg_list_size, + enum target_register_class reg_class); +uint32_t xtensa_cause_get(struct target *target); +void xtensa_cause_clear(struct target *target); +void xtensa_cause_reset(struct target *target); +int xtensa_poll(struct target *target); +void xtensa_on_poll(struct target *target); +int xtensa_halt(struct target *target); +int xtensa_resume(struct target *target, + int current, + target_addr_t address, + int handle_breakpoints, + int debug_execution); +int xtensa_prepare_resume(struct target *target, + int current, + target_addr_t address, + int handle_breakpoints, + int debug_execution); +int xtensa_do_resume(struct target *target); +int xtensa_step(struct target *target, int current, target_addr_t address, int handle_breakpoints); +int xtensa_do_step(struct target *target, int current, target_addr_t address, int handle_breakpoints); +int xtensa_mmu_is_enabled(struct target *target, int *enabled); +int xtensa_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); +int xtensa_read_buffer(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer); +int xtensa_write_memory(struct target *target, + target_addr_t address, + uint32_t size, + uint32_t count, + const uint8_t *buffer); +int xtensa_write_buffer(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer); +int xtensa_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum); +int xtensa_assert_reset(struct target *target); +int xtensa_deassert_reset(struct target *target); +int xtensa_soft_reset_halt(struct target *target); +int xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint); +int xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint); +int xtensa_watchpoint_add(struct target *target, struct watchpoint *watchpoint); +int xtensa_watchpoint_remove(struct target *target, struct watchpoint *watchpoint); +int xtensa_start_algorithm(struct target *target, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + target_addr_t entry_point, target_addr_t exit_point, + void *arch_info); +int xtensa_wait_algorithm(struct target *target, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + target_addr_t exit_point, unsigned int timeout_ms, + void *arch_info); +int xtensa_run_algorithm(struct target *target, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + target_addr_t entry_point, target_addr_t exit_point, + unsigned int timeout_ms, void *arch_info); +void xtensa_set_permissive_mode(struct target *target, bool state); +const char *xtensa_get_gdb_arch(const struct target *target); +int xtensa_gdb_query_custom(struct target *target, const char *packet, char **response_p); + +COMMAND_HELPER(xtensa_cmd_xtdef_do, struct xtensa *xtensa); +COMMAND_HELPER(xtensa_cmd_xtopt_do, struct xtensa *xtensa); +COMMAND_HELPER(xtensa_cmd_xtmem_do, struct xtensa *xtensa); +COMMAND_HELPER(xtensa_cmd_xtmpu_do, struct xtensa *xtensa); +COMMAND_HELPER(xtensa_cmd_xtmmu_do, struct xtensa *xtensa); +COMMAND_HELPER(xtensa_cmd_xtreg_do, struct xtensa *xtensa); +COMMAND_HELPER(xtensa_cmd_xtregfmt_do, struct xtensa *xtensa); +COMMAND_HELPER(xtensa_cmd_permissive_mode_do, struct xtensa *xtensa); +COMMAND_HELPER(xtensa_cmd_mask_interrupts_do, struct xtensa *xtensa); +COMMAND_HELPER(xtensa_cmd_smpbreak_do, struct target *target); +COMMAND_HELPER(xtensa_cmd_perfmon_dump_do, struct xtensa *xtensa); +COMMAND_HELPER(xtensa_cmd_perfmon_enable_do, struct xtensa *xtensa); +COMMAND_HELPER(xtensa_cmd_tracestart_do, struct xtensa *xtensa); +COMMAND_HELPER(xtensa_cmd_tracestop_do, struct xtensa *xtensa); +COMMAND_HELPER(xtensa_cmd_tracedump_do, struct xtensa *xtensa, const char *fname); + +extern const struct command_registration xtensa_command_handlers[]; + +#endif /* OPENOCD_TARGET_XTENSA_H */ diff --git a/src/target/xtensa/xtensa_chip.c b/src/target/xtensa/xtensa_chip.c new file mode 100644 index 0000000000..ac758ed830 --- /dev/null +++ b/src/target/xtensa/xtensa_chip.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Xtensa Chip-level Target Support for OpenOCD * + * Copyright (C) 2020-2022 Cadence Design Systems, Inc. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "assert.h" +#include <target/target.h> +#include <target/target_type.h> +#include <target/arm_adi_v5.h> +#include <rtos/rtos.h> +#include "xtensa_chip.h" +#include "xtensa_fileio.h" + +int xtensa_chip_init_arch_info(struct target *target, void *arch_info, + struct xtensa_debug_module_config *dm_cfg) +{ + struct xtensa_chip_common *xtensa_chip = (struct xtensa_chip_common *)arch_info; + int ret = xtensa_init_arch_info(target, &xtensa_chip->xtensa, dm_cfg); + if (ret != ERROR_OK) + return ret; + /* All xtensa target structures point back to original xtensa_chip */ + xtensa_chip->xtensa.xtensa_chip = arch_info; + return ERROR_OK; +} + +int xtensa_chip_target_init(struct command_context *cmd_ctx, struct target *target) +{ + int ret = xtensa_target_init(cmd_ctx, target); + if (ret != ERROR_OK) + return ret; + return xtensa_fileio_init(target); +} + +int xtensa_chip_arch_state(struct target *target) +{ + return ERROR_OK; +} + +static int xtensa_chip_poll(struct target *target) +{ + enum target_state old_state = target->state; + int ret = xtensa_poll(target); + + if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) { + /*Call any event callbacks that are applicable */ + if (old_state == TARGET_DEBUG_RUNNING) { + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); + } else { + xtensa_fileio_detect_proc(target); + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + } + + return ret; +} + +static int xtensa_chip_virt2phys(struct target *target, + target_addr_t virtual, target_addr_t *physical) +{ + if (physical) { + *physical = virtual; + return ERROR_OK; + } + return ERROR_FAIL; +} + +static const struct xtensa_debug_ops xtensa_chip_dm_dbg_ops = { + .queue_enable = xtensa_dm_queue_enable, + .queue_reg_read = xtensa_dm_queue_reg_read, + .queue_reg_write = xtensa_dm_queue_reg_write +}; + +static const struct xtensa_power_ops xtensa_chip_dm_pwr_ops = { + .queue_reg_read = xtensa_dm_queue_pwr_reg_read, + .queue_reg_write = xtensa_dm_queue_pwr_reg_write +}; + +static int xtensa_chip_target_create(struct target *target, Jim_Interp *interp) +{ + struct xtensa_debug_module_config xtensa_chip_dm_cfg = { + .dbg_ops = &xtensa_chip_dm_dbg_ops, + .pwr_ops = &xtensa_chip_dm_pwr_ops, + .tap = NULL, + .queue_tdi_idle = NULL, + .queue_tdi_idle_arg = NULL, + .dap = NULL, + .debug_ap = NULL, + .debug_apsel = DP_APSEL_INVALID, + .ap_offset = 0, + }; + + struct adiv5_private_config *pc = target->private_config; + if (adiv5_verify_config(pc) == ERROR_OK) { + xtensa_chip_dm_cfg.dap = pc->dap; + xtensa_chip_dm_cfg.debug_apsel = pc->ap_num; + xtensa_chip_dm_cfg.ap_offset = target->dbgbase; + LOG_DEBUG("DAP: ap_num %" PRId64 " DAP %p\n", pc->ap_num, pc->dap); + } else { + xtensa_chip_dm_cfg.tap = target->tap; + LOG_DEBUG("JTAG: %s:%s pos %d", target->tap->chip, target->tap->tapname, + target->tap->abs_chain_position); + } + + struct xtensa_chip_common *xtensa_chip = calloc(1, sizeof(struct xtensa_chip_common)); + if (!xtensa_chip) { + LOG_ERROR("Failed to alloc chip-level memory!"); + return ERROR_FAIL; + } + + int ret = xtensa_chip_init_arch_info(target, xtensa_chip, &xtensa_chip_dm_cfg); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to init arch info!"); + free(xtensa_chip); + return ret; + } + + /*Assume running target. If different, the first poll will fix this. */ + target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + return ERROR_OK; +} + +static void xtensa_chip_target_deinit(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + xtensa_target_deinit(target); + free(xtensa->xtensa_chip); +} + +static int xtensa_chip_examine(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + int retval = xtensa_dm_examine(&xtensa->dbg_mod); + if (retval == ERROR_OK) + retval = xtensa_examine(target); + return retval; +} + +static int xtensa_chip_jim_configure(struct target *target, struct jim_getopt_info *goi) +{ + static bool dap_configured; + int ret = adiv5_jim_configure(target, goi); + if (ret == JIM_OK) { + LOG_DEBUG("xtensa '-dap' target option found"); + dap_configured = true; + } + if (!dap_configured) { + LOG_DEBUG("xtensa '-dap' target option not yet found, assuming JTAG..."); + target->has_dap = false; + } + return ret; +} + +/** Methods for generic example of Xtensa-based chip-level targets. */ +struct target_type xtensa_chip_target = { + .name = "xtensa", + + .poll = xtensa_chip_poll, + .arch_state = xtensa_chip_arch_state, + + .halt = xtensa_halt, + .resume = xtensa_resume, + .step = xtensa_step, + + .assert_reset = xtensa_assert_reset, + .deassert_reset = xtensa_deassert_reset, + .soft_reset_halt = xtensa_soft_reset_halt, + + .virt2phys = xtensa_chip_virt2phys, + .mmu = xtensa_mmu_is_enabled, + .read_memory = xtensa_read_memory, + .write_memory = xtensa_write_memory, + + .read_buffer = xtensa_read_buffer, + .write_buffer = xtensa_write_buffer, + + .checksum_memory = xtensa_checksum_memory, + + .get_gdb_reg_list = xtensa_get_gdb_reg_list, + + .run_algorithm = xtensa_run_algorithm, + .start_algorithm = xtensa_start_algorithm, + .wait_algorithm = xtensa_wait_algorithm, + + .add_breakpoint = xtensa_breakpoint_add, + .remove_breakpoint = xtensa_breakpoint_remove, + + .add_watchpoint = xtensa_watchpoint_add, + .remove_watchpoint = xtensa_watchpoint_remove, + + .target_create = xtensa_chip_target_create, + .target_jim_configure = xtensa_chip_jim_configure, + .init_target = xtensa_chip_target_init, + .examine = xtensa_chip_examine, + .deinit_target = xtensa_chip_target_deinit, + + .gdb_query_custom = xtensa_gdb_query_custom, + + .commands = xtensa_command_handlers, + + .get_gdb_fileio_info = xtensa_get_gdb_fileio_info, + .gdb_fileio_end = xtensa_gdb_fileio_end, +}; diff --git a/src/target/xtensa/xtensa_chip.h b/src/target/xtensa/xtensa_chip.h new file mode 100644 index 0000000000..5200deb72b --- /dev/null +++ b/src/target/xtensa/xtensa_chip.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Xtensa Chip-level Target Support for OpenOCD * + * Copyright (C) 2020-2022 Cadence Design Systems, Inc. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_XTENSA_CHIP_H +#define OPENOCD_TARGET_XTENSA_CHIP_H + +#include <target/target.h> +#include "xtensa.h" +#include "xtensa_debug_module.h" + +struct xtensa_chip_common { + struct xtensa xtensa; + /* Chip-specific extensions can be added here */ +}; + +static inline struct xtensa_chip_common *target_to_xtensa_chip(struct target *target) +{ + return container_of(target->arch_info, struct xtensa_chip_common, xtensa); +} + +int xtensa_chip_init_arch_info(struct target *target, void *arch_info, + struct xtensa_debug_module_config *dm_cfg); +int xtensa_chip_target_init(struct command_context *cmd_ctx, struct target *target); +int xtensa_chip_arch_state(struct target *target); +void xtensa_chip_queue_tdi_idle(struct target *target); +void xtensa_chip_on_reset(struct target *target); +bool xtensa_chip_on_halt(struct target *target); +void xtensa_chip_on_poll(struct target *target); + +#endif /* OPENOCD_TARGET_XTENSA_CHIP_H */ diff --git a/src/target/xtensa/xtensa_debug_module.c b/src/target/xtensa/xtensa_debug_module.c new file mode 100644 index 0000000000..8045779b81 --- /dev/null +++ b/src/target/xtensa/xtensa_debug_module.c @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Xtensa Debug Module (XDM) Support for OpenOCD * + * Copyright (C) 2020-2022 Cadence Design Systems, Inc. * + * Copyright (C) 2019 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <helper/align.h> +#include "xtensa_debug_module.h" + +#define TAPINS_PWRCTL 0x08 +#define TAPINS_PWRSTAT 0x09 +#define TAPINS_NARSEL 0x1C +#define TAPINS_IDCODE 0x1E +#define TAPINS_BYPASS 0x1F + +#define TAPINS_PWRCTL_LEN 8 +#define TAPINS_PWRSTAT_LEN 8 +#define TAPINS_NARSEL_ADRLEN 8 +#define TAPINS_NARSEL_DATALEN 32 +#define TAPINS_IDCODE_LEN 32 +#define TAPINS_BYPASS_LEN 1 + +/* Table of power register offsets for APB space */ +static const struct xtensa_dm_pwr_reg_offsets xdm_pwr_regs[XDMREG_PWRNUM] = + XTENSA_DM_PWR_REG_OFFSETS; + +/* Table of debug register offsets for Nexus and APB space */ +static const struct xtensa_dm_reg_offsets xdm_regs[XDMREG_NUM] = + XTENSA_DM_REG_OFFSETS; + +static enum xtensa_dm_reg xtensa_dm_regaddr_to_id(uint32_t addr) +{ + enum xtensa_dm_reg id; + uint32_t addr_masked = (addr & (XTENSA_DM_APB_ALIGN - 1)); + for (id = XDMREG_TRAXID; id < XDMREG_NUM; id++) + if (xdm_regs[id].apb == addr_masked) + break; + return id; +} + +static void xtensa_dm_add_set_ir(struct xtensa_debug_module *dm, uint8_t value) +{ + struct scan_field field; + uint8_t t[4] = { 0, 0, 0, 0 }; + + memset(&field, 0, sizeof(field)); + field.num_bits = dm->tap->ir_length; + field.out_value = t; + buf_set_u32(t, 0, field.num_bits, value); + jtag_add_ir_scan(dm->tap, &field, TAP_IDLE); +} + +static void xtensa_dm_add_dr_scan(struct xtensa_debug_module *dm, + int len, + const uint8_t *src, + uint8_t *dest, + tap_state_t endstate) +{ + struct scan_field field; + + memset(&field, 0, sizeof(field)); + field.num_bits = len; + field.out_value = src; + field.in_value = dest; + jtag_add_dr_scan(dm->tap, 1, &field, endstate); +} + +int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_module_config *cfg) +{ + if (!dm || !cfg) + return ERROR_FAIL; + if (!IS_ALIGNED(cfg->ap_offset, XTENSA_DM_APB_ALIGN)) { + LOG_ERROR("Xtensa DM APB offset must be aligned to a %dKB multiple", + XTENSA_DM_APB_ALIGN / 1024); + return ERROR_FAIL; + } + + dm->pwr_ops = cfg->pwr_ops; + dm->dbg_ops = cfg->dbg_ops; + dm->tap = cfg->tap; + dm->queue_tdi_idle = cfg->queue_tdi_idle; + dm->queue_tdi_idle_arg = cfg->queue_tdi_idle_arg; + dm->dap = cfg->dap; + dm->debug_ap = cfg->debug_ap; + dm->debug_apsel = cfg->debug_apsel; + dm->ap_offset = cfg->ap_offset; + return ERROR_OK; +} + +void xtensa_dm_deinit(struct xtensa_debug_module *dm) +{ + if (dm->debug_ap) { + dap_put_ap(dm->debug_ap); + dm->debug_ap = NULL; + } +} + +int xtensa_dm_poll(struct xtensa_debug_module *dm) +{ + /* Check if debug_ap is available to prevent segmentation fault. + * If the re-examination after an error does not find a MEM-AP + * (e.g. the target stopped communicating), debug_ap pointer + * can suddenly become NULL. + */ + return (!dm || (dm->dap && !dm->debug_ap)) ? ERROR_FAIL : ERROR_OK; +} + +int xtensa_dm_examine(struct xtensa_debug_module *dm) +{ + struct adiv5_dap *swjdp = dm->dap; + int retval = ERROR_OK; + + if (swjdp) { + LOG_DEBUG("DM examine: DAP AP select %d", dm->debug_apsel); + if (dm->debug_ap) { + dap_put_ap(dm->debug_ap); + dm->debug_ap = NULL; + } + if (dm->debug_apsel == DP_APSEL_INVALID) { + LOG_DEBUG("DM examine: search for APB-type MEM-AP..."); + /* TODO: Determine whether AP_TYPE_AXI_AP APs can be supported... */ + retval = dap_find_get_ap(swjdp, AP_TYPE_APB_AP, &dm->debug_ap); + if (retval != ERROR_OK) { + LOG_ERROR("Could not find MEM-AP to control the core"); + return retval; + } + } else { + dm->debug_ap = dap_get_ap(swjdp, dm->debug_apsel); + } + + /* TODO: Allow a user-specified AP instead of relying on AP_TYPE_APB_AP */ + dm->debug_apsel = dm->debug_ap->ap_num; + LOG_DEBUG("DM examine: Setting apsel to %d", dm->debug_apsel); + + /* Leave (only) generic DAP stuff for debugport_init(); */ + dm->debug_ap->memaccess_tck = 8; + + retval = mem_ap_init(dm->debug_ap); + if (retval != ERROR_OK) { + LOG_ERROR("MEM-AP init failed: %d", retval); + return retval; + } + + /* TODO: how to set autoincrement range? Hard-code it to 1024 bytes for now */ + dm->debug_ap->tar_autoincr_block = (1 << 10); + } + + return retval; +} + +int xtensa_dm_queue_enable(struct xtensa_debug_module *dm) +{ + return dm->dbg_ops->queue_reg_write(dm, XDMREG_DCRSET, OCDDCR_ENABLEOCD); +} + +int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint8_t *value) +{ + if (reg >= XDMREG_NUM) { + LOG_ERROR("Invalid DBG reg ID %d!", reg); + return ERROR_FAIL; + } + if (dm->dap) + /* NOTE: Future optimization: mem_ap_read_u32() offers higher performance with + * queued reads, but requires an API change to pass value as a 32-bit pointer. + */ + return mem_ap_read_buf(dm->debug_ap, value, 4, 1, xdm_regs[reg].apb + dm->ap_offset); + uint8_t regdata = (xdm_regs[reg].nar << 1) | 0; + uint8_t dummy[4] = { 0, 0, 0, 0 }; + xtensa_dm_add_set_ir(dm, TAPINS_NARSEL); + xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_ADRLEN, ®data, NULL, TAP_IDLE); + xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, dummy, value, TAP_IDLE); + return ERROR_OK; +} + +int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint32_t value) +{ + if (reg >= XDMREG_NUM) { + LOG_ERROR("Invalid DBG reg ID %d!", reg); + return ERROR_FAIL; + } + if (dm->dap) + return mem_ap_write_u32(dm->debug_ap, xdm_regs[reg].apb + dm->ap_offset, value); + uint8_t regdata = (xdm_regs[reg].nar << 1) | 1; + uint8_t valdata[] = { value, value >> 8, value >> 16, value >> 24 }; + xtensa_dm_add_set_ir(dm, TAPINS_NARSEL); + xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_ADRLEN, ®data, NULL, TAP_IDLE); + xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, valdata, NULL, TAP_IDLE); + return ERROR_OK; +} + +int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module *dm, + enum xtensa_dm_pwr_reg reg, + uint8_t *data, + uint32_t clear) +{ + if (reg >= XDMREG_PWRNUM) { + LOG_ERROR("Invalid PWR reg ID %d!", reg); + return ERROR_FAIL; + } + if (dm->dap) { + /* NOTE: Future optimization: mem_ap_read_u32() offers higher performance with + * queued reads, but requires an API change to pass value as a 32-bit pointer. + */ + uint32_t apbreg = xdm_pwr_regs[reg].apb + dm->ap_offset; + int retval = mem_ap_read_buf(dm->debug_ap, data, 4, 1, apbreg); + if (retval == ERROR_OK) + retval = mem_ap_write_u32(dm->debug_ap, apbreg, clear); + return retval; + } + uint8_t value_clr = (uint8_t)clear; + uint8_t tap_insn = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL : TAPINS_PWRSTAT; + int tap_insn_sz = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL_LEN : TAPINS_PWRSTAT_LEN; + xtensa_dm_add_set_ir(dm, tap_insn); + xtensa_dm_add_dr_scan(dm, tap_insn_sz, &value_clr, data, TAP_IDLE); + return ERROR_OK; +} + +int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm, + enum xtensa_dm_pwr_reg reg, + uint32_t data) +{ + if (reg >= XDMREG_PWRNUM) { + LOG_ERROR("Invalid PWR reg ID %d!", reg); + return ERROR_FAIL; + } + if (dm->dap) { + uint32_t apbreg = xdm_pwr_regs[reg].apb + dm->ap_offset; + return mem_ap_write_u32(dm->debug_ap, apbreg, data); + } + uint8_t tap_insn = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL : TAPINS_PWRSTAT; + int tap_insn_sz = (reg == XDMREG_PWRCTL) ? TAPINS_PWRCTL_LEN : TAPINS_PWRSTAT_LEN; + uint8_t value = (uint8_t)data; + xtensa_dm_add_set_ir(dm, tap_insn); + xtensa_dm_add_dr_scan(dm, tap_insn_sz, &value, NULL, TAP_IDLE); + return ERROR_OK; +} + +int xtensa_dm_device_id_read(struct xtensa_debug_module *dm) +{ + uint8_t id_buf[sizeof(uint32_t)]; + + dm->dbg_ops->queue_reg_read(dm, XDMREG_OCDID, id_buf); + xtensa_dm_queue_tdi_idle(dm); + int res = xtensa_dm_queue_execute(dm); + if (res != ERROR_OK) + return res; + dm->device_id = buf_get_u32(id_buf, 0, 32); + return ERROR_OK; +} + +int xtensa_dm_power_status_read(struct xtensa_debug_module *dm, uint32_t clear) +{ + uint8_t stat_buf[sizeof(uint32_t)] = { 0, 0, 0, 0 }; + uint8_t stath_buf[sizeof(uint32_t)] = { 0, 0, 0, 0 }; + + /* TODO: JTAG does not work when PWRCTL_JTAGDEBUGUSE is not set. + * It is set in xtensa_examine(), need to move reading of XDMREG_OCDID out of this function */ + /* dm->dbg_ops->queue_reg_read(dm, XDMREG_OCDID, id_buf); + *Read reset state */ + dm->pwr_ops->queue_reg_read(dm, XDMREG_PWRSTAT, stat_buf, clear); + dm->pwr_ops->queue_reg_read(dm, XDMREG_PWRSTAT, stath_buf, clear); + xtensa_dm_queue_tdi_idle(dm); + int res = xtensa_dm_queue_execute(dm); + if (res != ERROR_OK) + return res; + dm->power_status.stat = buf_get_u32(stat_buf, 0, 32); + dm->power_status.stath = buf_get_u32(stath_buf, 0, 32); + return res; +} + +int xtensa_dm_core_status_read(struct xtensa_debug_module *dm) +{ + uint8_t dsr_buf[sizeof(uint32_t)]; + + xtensa_dm_queue_enable(dm); + dm->dbg_ops->queue_reg_read(dm, XDMREG_DSR, dsr_buf); + xtensa_dm_queue_tdi_idle(dm); + int res = xtensa_dm_queue_execute(dm); + if (res != ERROR_OK) + return res; + dm->core_status.dsr = buf_get_u32(dsr_buf, 0, 32); + return res; +} + +int xtensa_dm_core_status_clear(struct xtensa_debug_module *dm, xtensa_dsr_t bits) +{ + dm->dbg_ops->queue_reg_write(dm, XDMREG_DSR, bits); + xtensa_dm_queue_tdi_idle(dm); + return xtensa_dm_queue_execute(dm); +} + +int xtensa_dm_read(struct xtensa_debug_module *dm, uint32_t addr, uint32_t *val) +{ + enum xtensa_dm_reg reg = xtensa_dm_regaddr_to_id(addr); + uint8_t buf[sizeof(uint32_t)]; + if (reg < XDMREG_NUM) { + xtensa_dm_queue_enable(dm); + dm->dbg_ops->queue_reg_read(dm, reg, buf); + xtensa_dm_queue_tdi_idle(dm); + int res = xtensa_dm_queue_execute(dm); + if (res == ERROR_OK && val) + *val = buf_get_u32(buf, 0, 32); + return res; + } + return ERROR_FAIL; +} + +int xtensa_dm_write(struct xtensa_debug_module *dm, uint32_t addr, uint32_t val) +{ + enum xtensa_dm_reg reg = xtensa_dm_regaddr_to_id(addr); + if (reg < XDMREG_NUM) { + xtensa_dm_queue_enable(dm); + dm->dbg_ops->queue_reg_write(dm, reg, val); + xtensa_dm_queue_tdi_idle(dm); + return xtensa_dm_queue_execute(dm); + } + return ERROR_FAIL; +} + +int xtensa_dm_trace_start(struct xtensa_debug_module *dm, struct xtensa_trace_start_config *cfg) +{ + /*Turn off trace unit so we can start a new trace. */ + dm->dbg_ops->queue_reg_write(dm, XDMREG_TRAXCTRL, 0); + xtensa_dm_queue_tdi_idle(dm); + int res = xtensa_dm_queue_execute(dm); + if (res != ERROR_OK) + return res; + + /*Set up parameters */ + dm->dbg_ops->queue_reg_write(dm, XDMREG_TRAXADDR, 0); + if (cfg->stopmask != XTENSA_STOPMASK_DISABLED) { + dm->dbg_ops->queue_reg_write(dm, XDMREG_PCMATCHCTRL, + (cfg->stopmask << PCMATCHCTRL_PCML_SHIFT)); + dm->dbg_ops->queue_reg_write(dm, XDMREG_TRIGGERPC, cfg->stoppc); + } + dm->dbg_ops->queue_reg_write(dm, XDMREG_DELAYCNT, cfg->after); + /*Options are mostly hardcoded for now. ToDo: make this more configurable. */ + dm->dbg_ops->queue_reg_write( + dm, + XDMREG_TRAXCTRL, + TRAXCTRL_TREN | + ((cfg->stopmask != XTENSA_STOPMASK_DISABLED) ? TRAXCTRL_PCMEN : 0) | TRAXCTRL_TMEN | + (cfg->after_is_words ? 0 : TRAXCTRL_CNTU) | (0 << TRAXCTRL_SMPER_SHIFT) | TRAXCTRL_PTOWS); + xtensa_dm_queue_tdi_idle(dm); + return xtensa_dm_queue_execute(dm); +} + +int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable) +{ + uint8_t traxctl_buf[sizeof(uint32_t)]; + uint32_t traxctl; + struct xtensa_trace_status trace_status; + + dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXCTRL, traxctl_buf); + xtensa_dm_queue_tdi_idle(dm); + int res = xtensa_dm_queue_execute(dm); + if (res != ERROR_OK) + return res; + traxctl = buf_get_u32(traxctl_buf, 0, 32); + + if (!pto_enable) + traxctl &= ~(TRAXCTRL_PTOWS | TRAXCTRL_PTOWT); + + dm->dbg_ops->queue_reg_write(dm, XDMREG_TRAXCTRL, traxctl | TRAXCTRL_TRSTP); + xtensa_dm_queue_tdi_idle(dm); + res = xtensa_dm_queue_execute(dm); + if (res != ERROR_OK) + return res; + + /*Check current status of trace hardware */ + res = xtensa_dm_trace_status_read(dm, &trace_status); + if (res != ERROR_OK) + return res; + + if (trace_status.stat & TRAXSTAT_TRACT) { + LOG_ERROR("Failed to stop tracing (0x%x)!", trace_status.stat); + return ERROR_FAIL; + } + return ERROR_OK; +} + +int xtensa_dm_trace_status_read(struct xtensa_debug_module *dm, struct xtensa_trace_status *status) +{ + uint8_t traxstat_buf[sizeof(uint32_t)]; + + dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXSTAT, traxstat_buf); + xtensa_dm_queue_tdi_idle(dm); + int res = xtensa_dm_queue_execute(dm); + if (res == ERROR_OK && status) + status->stat = buf_get_u32(traxstat_buf, 0, 32); + return res; +} + +int xtensa_dm_trace_config_read(struct xtensa_debug_module *dm, struct xtensa_trace_config *config) +{ + uint8_t traxctl_buf[sizeof(uint32_t)]; + uint8_t memadrstart_buf[sizeof(uint32_t)]; + uint8_t memadrend_buf[sizeof(uint32_t)]; + uint8_t adr_buf[sizeof(uint32_t)]; + + if (!config) + return ERROR_FAIL; + + dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXCTRL, traxctl_buf); + dm->dbg_ops->queue_reg_read(dm, XDMREG_MEMADDRSTART, memadrstart_buf); + dm->dbg_ops->queue_reg_read(dm, XDMREG_MEMADDREND, memadrend_buf); + dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXADDR, adr_buf); + xtensa_dm_queue_tdi_idle(dm); + int res = xtensa_dm_queue_execute(dm); + if (res == ERROR_OK) { + config->ctrl = buf_get_u32(traxctl_buf, 0, 32); + config->memaddr_start = buf_get_u32(memadrstart_buf, 0, 32); + config->memaddr_end = buf_get_u32(memadrend_buf, 0, 32); + config->addr = buf_get_u32(adr_buf, 0, 32); + } + return res; +} + +int xtensa_dm_trace_data_read(struct xtensa_debug_module *dm, uint8_t *dest, uint32_t size) +{ + if (!dest) + return ERROR_FAIL; + + for (unsigned int i = 0; i < size / 4; i++) + dm->dbg_ops->queue_reg_read(dm, XDMREG_TRAXDATA, &dest[i * 4]); + xtensa_dm_queue_tdi_idle(dm); + return xtensa_dm_queue_execute(dm); +} + +int xtensa_dm_perfmon_enable(struct xtensa_debug_module *dm, int counter_id, + const struct xtensa_perfmon_config *config) +{ + if (!config) + return ERROR_FAIL; + + uint8_t pmstat_buf[4]; + uint32_t pmctrl = ((config->tracelevel) << 4) + + (config->select << 8) + + (config->mask << 16) + + (config->kernelcnt << 3); + + /* enable performance monitor */ + dm->dbg_ops->queue_reg_write(dm, XDMREG_PMG, 0x1); + /* reset counter */ + dm->dbg_ops->queue_reg_write(dm, XDMREG_PM0 + counter_id, 0); + dm->dbg_ops->queue_reg_write(dm, XDMREG_PMCTRL0 + counter_id, pmctrl); + dm->dbg_ops->queue_reg_read(dm, XDMREG_PMSTAT0 + counter_id, pmstat_buf); + xtensa_dm_queue_tdi_idle(dm); + return xtensa_dm_queue_execute(dm); +} + +int xtensa_dm_perfmon_dump(struct xtensa_debug_module *dm, int counter_id, + struct xtensa_perfmon_result *out_result) +{ + uint8_t pmstat_buf[4]; + uint8_t pmcount_buf[4]; + + dm->dbg_ops->queue_reg_read(dm, XDMREG_PMSTAT0 + counter_id, pmstat_buf); + dm->dbg_ops->queue_reg_read(dm, XDMREG_PM0 + counter_id, pmcount_buf); + xtensa_dm_queue_tdi_idle(dm); + int res = xtensa_dm_queue_execute(dm); + if (res == ERROR_OK) { + uint32_t stat = buf_get_u32(pmstat_buf, 0, 32); + uint64_t result = buf_get_u32(pmcount_buf, 0, 32); + + /* TODO: if counter # counter_id+1 has 'select' set to 1, use its value as the + * high 32 bits of the counter. */ + if (out_result) { + out_result->overflow = ((stat & 1) != 0); + out_result->value = result; + } + } + + return res; +} diff --git a/src/target/xtensa/xtensa_debug_module.h b/src/target/xtensa/xtensa_debug_module.h new file mode 100644 index 0000000000..495da2a646 --- /dev/null +++ b/src/target/xtensa/xtensa_debug_module.h @@ -0,0 +1,602 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Xtensa Debug Module (XDM) Support for OpenOCD * + * Copyright (C) 2020-2022 Cadence Design Systems, Inc. * + * Copyright (C) 2019 Espressif Systems Ltd. * + * Derived from original ESP8266 target. * + * Author: Angus Gratton gus@projectgus.com * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_XTENSA_DEBUG_MODULE_H +#define OPENOCD_TARGET_XTENSA_DEBUG_MODULE_H + +#include <jtag/jtag.h> +#include <target/arm_adi_v5.h> +#include <helper/bits.h> +#include <target/target.h> + +/* Virtual IDs for using with xtensa_power_ops API */ +enum xtensa_dm_pwr_reg { + XDMREG_PWRCTL = 0x00, + XDMREG_PWRSTAT, + XDMREG_PWRNUM +}; + +/* Debug Module Power Register offsets within APB */ +struct xtensa_dm_pwr_reg_offsets { + uint16_t apb; +}; + +/* Debug Module Power Register offset structure; must include XDMREG_PWRNUM entries */ +#define XTENSA_DM_PWR_REG_OFFSETS { \ + /* Power/Reset Registers */ \ + { .apb = 0x3020 }, /* XDMREG_PWRCTL */ \ + { .apb = 0x3024 }, /* XDMREG_PWRSTAT */ \ +} + +/* + From the manual: + To properly use Debug registers through JTAG, software must ensure that: + - Tap is out of reset + - Xtensa Debug Module is out of reset + - Other bits of PWRCTL are set to their desired values, and finally + - JtagDebugUse transitions from 0 to 1 + The bit must continue to be 1 in order for JTAG accesses to the Debug + Module to happen correctly. When it is set, any write to this bit clears it. + Either don't access it, or re-write it to 1 so JTAG accesses continue. +*/ +#define PWRCTL_JTAGDEBUGUSE(x) (((x)->dbg_mod.dap) ? (0) : BIT(7)) +#define PWRCTL_DEBUGRESET(x) (((x)->dbg_mod.dap) ? BIT(28) : BIT(6)) +#define PWRCTL_CORERESET(x) (((x)->dbg_mod.dap) ? BIT(16) : BIT(4)) +#define PWRCTL_DEBUGWAKEUP(x) (((x)->dbg_mod.dap) ? BIT(12) : BIT(2)) +#define PWRCTL_MEMWAKEUP(x) (((x)->dbg_mod.dap) ? BIT(8) : BIT(1)) +#define PWRCTL_COREWAKEUP(x) (((x)->dbg_mod.dap) ? BIT(0) : BIT(0)) + +#define PWRSTAT_DEBUGWASRESET_DM(d) (((d)->dap) ? BIT(28) : BIT(6)) +#define PWRSTAT_COREWASRESET_DM(d) (((d)->dap) ? BIT(16) : BIT(4)) +#define PWRSTAT_DEBUGWASRESET(x) (PWRSTAT_DEBUGWASRESET_DM(&((x)->dbg_mod))) +#define PWRSTAT_COREWASRESET(x) (PWRSTAT_COREWASRESET_DM(&((x)->dbg_mod))) +#define PWRSTAT_CORESTILLNEEDED(x) (((x)->dbg_mod.dap) ? BIT(4) : BIT(3)) +#define PWRSTAT_DEBUGDOMAINON(x) (((x)->dbg_mod.dap) ? BIT(12) : BIT(2)) +#define PWRSTAT_MEMDOMAINON(x) (((x)->dbg_mod.dap) ? BIT(8) : BIT(1)) +#define PWRSTAT_COREDOMAINON(x) (((x)->dbg_mod.dap) ? BIT(0) : BIT(0)) + +/* Virtual IDs for using with xtensa_debug_ops API */ +enum xtensa_dm_reg { + /* TRAX Registers */ + XDMREG_TRAXID = 0x00, + XDMREG_TRAXCTRL, + XDMREG_TRAXSTAT, + XDMREG_TRAXDATA, + XDMREG_TRAXADDR, + XDMREG_TRIGGERPC, + XDMREG_PCMATCHCTRL, + XDMREG_DELAYCNT, + XDMREG_MEMADDRSTART, + XDMREG_MEMADDREND, + XDMREG_EXTTIMELO, + XDMREG_EXTTIMEHI, + XDMREG_TRAXRSVD48, + XDMREG_TRAXRSVD4C, + XDMREG_TRAXRSVD50, + XDMREG_TRAXRSVD54, + XDMREG_TRAXRSVD58, + XDMREG_TRAXRSVD5C, + XDMREG_TRAXRSVD60, + XDMREG_TRAXRSVD64, + XDMREG_TRAXRSVD68, + XDMREG_TRAXRSVD6C, + XDMREG_TRAXRSVD70, + XDMREG_TRAXRSVD74, + XDMREG_CONFIGID0, + XDMREG_CONFIGID1, + + /* Performance Monitor Registers */ + XDMREG_PMG, + XDMREG_INTPC, + XDMREG_PM0, + XDMREG_PM1, + XDMREG_PM2, + XDMREG_PM3, + XDMREG_PM4, + XDMREG_PM5, + XDMREG_PM6, + XDMREG_PM7, + XDMREG_PMCTRL0, + XDMREG_PMCTRL1, + XDMREG_PMCTRL2, + XDMREG_PMCTRL3, + XDMREG_PMCTRL4, + XDMREG_PMCTRL5, + XDMREG_PMCTRL6, + XDMREG_PMCTRL7, + XDMREG_PMSTAT0, + XDMREG_PMSTAT1, + XDMREG_PMSTAT2, + XDMREG_PMSTAT3, + XDMREG_PMSTAT4, + XDMREG_PMSTAT5, + XDMREG_PMSTAT6, + XDMREG_PMSTAT7, + + /* OCD Registers */ + XDMREG_OCDID, + XDMREG_DCRCLR, + XDMREG_DCRSET, + XDMREG_DSR, + XDMREG_DDR, + XDMREG_DDREXEC, + XDMREG_DIR0EXEC, + XDMREG_DIR0, + XDMREG_DIR1, + XDMREG_DIR2, + XDMREG_DIR3, + XDMREG_DIR4, + XDMREG_DIR5, + XDMREG_DIR6, + XDMREG_DIR7, + + /* Misc Registers */ + XDMREG_ERISTAT, + + /* CoreSight Registers */ + XDMREG_ITCTRL, + XDMREG_CLAIMSET, + XDMREG_CLAIMCLR, + XDMREG_LOCKACCESS, + XDMREG_LOCKSTATUS, + XDMREG_AUTHSTATUS, + XDMREG_DEVID, + XDMREG_DEVTYPE, + XDMREG_PERID4, + XDMREG_PERID5, + XDMREG_PERID6, + XDMREG_PERID7, + XDMREG_PERID0, + XDMREG_PERID1, + XDMREG_PERID2, + XDMREG_PERID3, + XDMREG_COMPID0, + XDMREG_COMPID1, + XDMREG_COMPID2, + XDMREG_COMPID3, + + XDMREG_NUM +}; + +/* Debug Module Register offsets within Nexus (NAR) or APB */ +struct xtensa_dm_reg_offsets { + uint8_t nar; + uint16_t apb; +}; + +/* Debug Module Register offset structure; must include XDMREG_NUM entries */ +#define XTENSA_DM_REG_OFFSETS { \ + /* TRAX Registers */ \ + { .nar = 0x00, .apb = 0x0000 }, /* XDMREG_TRAXID */ \ + { .nar = 0x01, .apb = 0x0004 }, /* XDMREG_TRAXCTRL */ \ + { .nar = 0x02, .apb = 0x0008 }, /* XDMREG_TRAXSTAT */ \ + { .nar = 0x03, .apb = 0x000c }, /* XDMREG_TRAXDATA */ \ + { .nar = 0x04, .apb = 0x0010 }, /* XDMREG_TRAXADDR */ \ + { .nar = 0x05, .apb = 0x0014 }, /* XDMREG_TRIGGERPC */ \ + { .nar = 0x06, .apb = 0x0018 }, /* XDMREG_PCMATCHCTRL */ \ + { .nar = 0x07, .apb = 0x001c }, /* XDMREG_DELAYCNT */ \ + { .nar = 0x08, .apb = 0x0020 }, /* XDMREG_MEMADDRSTART */ \ + { .nar = 0x09, .apb = 0x0024 }, /* XDMREG_MEMADDREND */ \ + { .nar = 0x10, .apb = 0x0040 }, /* XDMREG_EXTTIMELO */ \ + { .nar = 0x11, .apb = 0x0044 }, /* XDMREG_EXTTIMEHI */ \ + { .nar = 0x12, .apb = 0x0048 }, /* XDMREG_TRAXRSVD48 */ \ + { .nar = 0x13, .apb = 0x004c }, /* XDMREG_TRAXRSVD4C */ \ + { .nar = 0x14, .apb = 0x0050 }, /* XDMREG_TRAXRSVD50 */ \ + { .nar = 0x15, .apb = 0x0054 }, /* XDMREG_TRAXRSVD54 */ \ + { .nar = 0x16, .apb = 0x0058 }, /* XDMREG_TRAXRSVD58 */ \ + { .nar = 0x17, .apb = 0x005c }, /* XDMREG_TRAXRSVD5C */ \ + { .nar = 0x18, .apb = 0x0060 }, /* XDMREG_TRAXRSVD60 */ \ + { .nar = 0x19, .apb = 0x0064 }, /* XDMREG_TRAXRSVD64 */ \ + { .nar = 0x1a, .apb = 0x0068 }, /* XDMREG_TRAXRSVD68 */ \ + { .nar = 0x1b, .apb = 0x006c }, /* XDMREG_TRAXRSVD6C */ \ + { .nar = 0x1c, .apb = 0x0070 }, /* XDMREG_TRAXRSVD70 */ \ + { .nar = 0x1d, .apb = 0x0074 }, /* XDMREG_TRAXRSVD74 */ \ + { .nar = 0x1e, .apb = 0x0078 }, /* XDMREG_CONFIGID0 */ \ + { .nar = 0x1f, .apb = 0x007c }, /* XDMREG_CONFIGID1 */ \ + \ + /* Performance Monitor Registers */ \ + { .nar = 0x20, .apb = 0x1000 }, /* XDMREG_PMG */ \ + { .nar = 0x24, .apb = 0x1010 }, /* XDMREG_INTPC */ \ + { .nar = 0x28, .apb = 0x1080 }, /* XDMREG_PM0 */ \ + { .nar = 0x29, .apb = 0x1084 }, /* XDMREG_PM1 */ \ + { .nar = 0x2a, .apb = 0x1088 }, /* XDMREG_PM2 */ \ + { .nar = 0x2b, .apb = 0x108c }, /* XDMREG_PM3 */ \ + { .nar = 0x2c, .apb = 0x1090 }, /* XDMREG_PM4 */ \ + { .nar = 0x2d, .apb = 0x1094 }, /* XDMREG_PM5 */ \ + { .nar = 0x2e, .apb = 0x1098 }, /* XDMREG_PM6 */ \ + { .nar = 0x2f, .apb = 0x109c }, /* XDMREG_PM7 */ \ + { .nar = 0x30, .apb = 0x1100 }, /* XDMREG_PMCTRL0 */ \ + { .nar = 0x31, .apb = 0x1104 }, /* XDMREG_PMCTRL1 */ \ + { .nar = 0x32, .apb = 0x1108 }, /* XDMREG_PMCTRL2 */ \ + { .nar = 0x33, .apb = 0x110c }, /* XDMREG_PMCTRL3 */ \ + { .nar = 0x34, .apb = 0x1110 }, /* XDMREG_PMCTRL4 */ \ + { .nar = 0x35, .apb = 0x1114 }, /* XDMREG_PMCTRL5 */ \ + { .nar = 0x36, .apb = 0x1118 }, /* XDMREG_PMCTRL6 */ \ + { .nar = 0x37, .apb = 0x111c }, /* XDMREG_PMCTRL7 */ \ + { .nar = 0x38, .apb = 0x1180 }, /* XDMREG_PMSTAT0 */ \ + { .nar = 0x39, .apb = 0x1184 }, /* XDMREG_PMSTAT1 */ \ + { .nar = 0x3a, .apb = 0x1188 }, /* XDMREG_PMSTAT2 */ \ + { .nar = 0x3b, .apb = 0x118c }, /* XDMREG_PMSTAT3 */ \ + { .nar = 0x3c, .apb = 0x1190 }, /* XDMREG_PMSTAT4 */ \ + { .nar = 0x3d, .apb = 0x1194 }, /* XDMREG_PMSTAT5 */ \ + { .nar = 0x3e, .apb = 0x1198 }, /* XDMREG_PMSTAT6 */ \ + { .nar = 0x3f, .apb = 0x119c }, /* XDMREG_PMSTAT7 */ \ + \ + /* OCD Registers */ \ + { .nar = 0x40, .apb = 0x2000 }, /* XDMREG_OCDID */ \ + { .nar = 0x42, .apb = 0x2008 }, /* XDMREG_DCRCLR */ \ + { .nar = 0x43, .apb = 0x200c }, /* XDMREG_DCRSET */ \ + { .nar = 0x44, .apb = 0x2010 }, /* XDMREG_DSR */ \ + { .nar = 0x45, .apb = 0x2014 }, /* XDMREG_DDR */ \ + { .nar = 0x46, .apb = 0x2018 }, /* XDMREG_DDREXEC */ \ + { .nar = 0x47, .apb = 0x201c }, /* XDMREG_DIR0EXEC */ \ + { .nar = 0x48, .apb = 0x2020 }, /* XDMREG_DIR0 */ \ + { .nar = 0x49, .apb = 0x2024 }, /* XDMREG_DIR1 */ \ + { .nar = 0x4a, .apb = 0x2028 }, /* XDMREG_DIR2 */ \ + { .nar = 0x4b, .apb = 0x202c }, /* XDMREG_DIR3 */ \ + { .nar = 0x4c, .apb = 0x2030 }, /* XDMREG_DIR4 */ \ + { .nar = 0x4d, .apb = 0x2034 }, /* XDMREG_DIR5 */ \ + { .nar = 0x4e, .apb = 0x2038 }, /* XDMREG_DIR6 */ \ + { .nar = 0x4f, .apb = 0x203c }, /* XDMREG_DIR7 */ \ + \ + /* Misc Registers */ \ + { .nar = 0x5a, .apb = 0x3028 }, /* XDMREG_ERISTAT */ \ + \ + /* CoreSight Registers */ \ + { .nar = 0x60, .apb = 0x3f00 }, /* XDMREG_ITCTRL */ \ + { .nar = 0x68, .apb = 0x3fa0 }, /* XDMREG_CLAIMSET */ \ + { .nar = 0x69, .apb = 0x3fa4 }, /* XDMREG_CLAIMCLR */ \ + { .nar = 0x6c, .apb = 0x3fb0 }, /* XDMREG_LOCKACCESS */ \ + { .nar = 0x6d, .apb = 0x3fb4 }, /* XDMREG_LOCKSTATUS */ \ + { .nar = 0x6e, .apb = 0x3fb8 }, /* XDMREG_AUTHSTATUS */ \ + { .nar = 0x72, .apb = 0x3fc8 }, /* XDMREG_DEVID */ \ + { .nar = 0x73, .apb = 0x3fcc }, /* XDMREG_DEVTYPE */ \ + { .nar = 0x74, .apb = 0x3fd0 }, /* XDMREG_PERID4 */ \ + { .nar = 0x75, .apb = 0x3fd4 }, /* XDMREG_PERID5 */ \ + { .nar = 0x76, .apb = 0x3fd8 }, /* XDMREG_PERID6 */ \ + { .nar = 0x77, .apb = 0x3fdc }, /* XDMREG_PERID7 */ \ + { .nar = 0x78, .apb = 0x3fe0 }, /* XDMREG_PERID0 */ \ + { .nar = 0x79, .apb = 0x3fe4 }, /* XDMREG_PERID1 */ \ + { .nar = 0x7a, .apb = 0x3fe8 }, /* XDMREG_PERID2 */ \ + { .nar = 0x7b, .apb = 0x3fec }, /* XDMREG_PERID3 */ \ + { .nar = 0x7c, .apb = 0x3ff0 }, /* XDMREG_COMPID0 */ \ + { .nar = 0x7d, .apb = 0x3ff4 }, /* XDMREG_COMPID1 */ \ + { .nar = 0x7e, .apb = 0x3ff8 }, /* XDMREG_COMPID2 */ \ + { .nar = 0x7f, .apb = 0x3ffc }, /* XDMREG_COMPID3 */ \ +} + +#define XTENSA_DM_APB_ALIGN 0x4000 + +/* OCD registers, bit definitions */ +#define OCDDCR_ENABLEOCD BIT(0) +#define OCDDCR_DEBUGINTERRUPT BIT(1) +#define OCDDCR_INTERRUPTALLCONDS BIT(2) +#define OCDDCR_STEPREQUEST BIT(3) /* NX only */ +#define OCDDCR_BREAKINEN BIT(16) +#define OCDDCR_BREAKOUTEN BIT(17) +#define OCDDCR_DEBUGSWACTIVE BIT(20) +#define OCDDCR_RUNSTALLINEN BIT(21) +#define OCDDCR_DEBUGMODEOUTEN BIT(22) +#define OCDDCR_BREAKOUTITO BIT(24) +#define OCDDCR_BREAKACKITO BIT(25) + +#define OCDDSR_EXECDONE BIT(0) +#define OCDDSR_EXECEXCEPTION BIT(1) +#define OCDDSR_EXECBUSY BIT(2) +#define OCDDSR_EXECOVERRUN BIT(3) +#define OCDDSR_STOPPED BIT(4) +#define OCDDSR_STOPCAUSE (0xF << 5) /* NX only */ +#define OCDDSR_STOPCAUSE_SHIFT (5) /* NX only */ +#define OCDDSR_COREWROTEDDR BIT(10) +#define OCDDSR_COREREADDDR BIT(11) +#define OCDDSR_HOSTWROTEDDR BIT(14) +#define OCDDSR_HOSTREADDDR BIT(15) +#define OCDDSR_DEBUGPENDBREAK BIT(16) +#define OCDDSR_DEBUGPENDHOST BIT(17) +#define OCDDSR_DEBUGPENDTRAX BIT(18) +#define OCDDSR_DEBUGINTBREAK BIT(20) +#define OCDDSR_DEBUGINTHOST BIT(21) +#define OCDDSR_DEBUGINTTRAX BIT(22) +#define OCDDSR_RUNSTALLTOGGLE BIT(23) +#define OCDDSR_RUNSTALLSAMPLE BIT(24) +#define OCDDSR_BREACKOUTACKITI BIT(25) +#define OCDDSR_BREAKINITI BIT(26) +#define OCDDSR_DBGMODPOWERON BIT(31) + +/* NX stop cause */ +#define OCDDSR_STOPCAUSE_DI (0) /* Debug Interrupt */ +#define OCDDSR_STOPCAUSE_SS (1) /* Single-step completed */ +#define OCDDSR_STOPCAUSE_IB (2) /* HW breakpoint (IBREAKn match) */ +#define OCDDSR_STOPCAUSE_B1 (4) /* SW breakpoint (BREAK.1 instruction) */ +#define OCDDSR_STOPCAUSE_BN (5) /* SW breakpoint (BREAK.N instruction) */ +#define OCDDSR_STOPCAUSE_B (6) /* SW breakpoint (BREAK instruction) */ +#define OCDDSR_STOPCAUSE_DB0 (8) /* HW watchpoint (DBREAK0 match) */ +#define OCDDSR_STOPCAUSE_DB1 (9) /* HW watchpoint (DBREAK0 match) */ + +/* LX stop cause */ +#define DEBUGCAUSE_IC BIT(0) /* ICOUNT exception */ +#define DEBUGCAUSE_IB BIT(1) /* IBREAK exception */ +#define DEBUGCAUSE_DB BIT(2) /* DBREAK exception */ +#define DEBUGCAUSE_BI BIT(3) /* BREAK instruction encountered */ +#define DEBUGCAUSE_BN BIT(4) /* BREAK.N instruction encountered */ +#define DEBUGCAUSE_DI BIT(5) /* Debug Interrupt */ +#define DEBUGCAUSE_VALID BIT(31) /* Pseudo-value to trigger reread (NX only) */ + +/* TRAXID */ +#define TRAXID_PRODNO_TRAX 0 /* TRAXID.PRODNO value for TRAX module */ +#define TRAXID_PRODNO_SHIFT 28 +#define TRAXID_PRODNO_MASK 0xf + +#define TRAXCTRL_TREN BIT(0) /* Trace enable. Tracing starts on 0->1 */ +#define TRAXCTRL_TRSTP BIT(1) /* Trace Stop. Make 1 to stop trace. */ +#define TRAXCTRL_PCMEN BIT(2) /* PC match enable */ +#define TRAXCTRL_PTIEN BIT(4) /* Processor-trigger enable */ +#define TRAXCTRL_CTIEN BIT(5) /* Cross-trigger enable */ +#define TRAXCTRL_TMEN BIT(7) /* Tracemem Enable. Always set. */ +#define TRAXCTRL_CNTU BIT(9) /* Post-stop-trigger countdown units; selects when DelayCount-- happens. + * 0 - every 32-bit word written to tracemem, 1 - every cpu instruction */ +#define TRAXCTRL_TSEN BIT(11) /* Undocumented/deprecated? */ +#define TRAXCTRL_SMPER_SHIFT 12 /* Send sync every 2^(9-smper) messages. 7=reserved, 0=no sync msg */ +#define TRAXCTRL_SMPER_MASK 0x07 /* Synchronization message period */ +#define TRAXCTRL_PTOWT BIT(16) /* Processor Trigger Out (OCD halt) enabled when stop triggered */ +#define TRAXCTRL_PTOWS BIT(17) /* Processor Trigger Out (OCD halt) enabled when trace stop completes */ +#define TRAXCTRL_CTOWT BIT(20) /* Cross-trigger Out enabled when stop triggered */ +#define TRAXCTRL_CTOWS BIT(21) /* Cross-trigger Out enabled when trace stop completes */ +#define TRAXCTRL_ITCTO BIT(22) /* Integration mode: cross-trigger output */ +#define TRAXCTRL_ITCTIA BIT(23) /* Integration mode: cross-trigger ack */ +#define TRAXCTRL_ITATV BIT(24) /* replaces ATID when in integration mode: ATVALID output */ +#define TRAXCTRL_ATID_MASK 0x7F /* ARB source ID */ +#define TRAXCTRL_ATID_SHIFT 24 +#define TRAXCTRL_ATEN BIT(31) /* ATB interface enable */ + +#define TRAXSTAT_TRACT BIT(0) /* Trace active flag. */ +#define TRAXSTAT_TRIG BIT(1) /* Trace stop trigger. Clears on TREN 1->0 */ +#define TRAXSTAT_PCMTG BIT(2) /* Stop trigger caused by PC match. Clears on TREN 1->0 */ +#define TRAXSTAT_PJTR BIT(3) /* JTAG transaction result. 1=err in preceding jtag transaction. */ +#define TRAXSTAT_PTITG BIT(4) /* Stop trigger caused by Processor Trigger Input.Clears on TREN 1->0 */ +#define TRAXSTAT_CTITG BIT(5) /* Stop trigger caused by Cross-Trigger Input. Clears on TREN 1->0 */ +#define TRAXSTAT_MEMSZ_SHIFT 8 /* Traceram size inducator. Usable trace ram is 2^MEMSZ bytes. */ +#define TRAXSTAT_MEMSZ_MASK 0x1F +#define TRAXSTAT_PTO BIT(16) /* Processor Trigger Output: current value */ +#define TRAXSTAT_CTO BIT(17) /* Cross-Trigger Output: current value */ +#define TRAXSTAT_ITCTOA BIT(22) /* Cross-Trigger Out Ack: current value */ +#define TRAXSTAT_ITCTI BIT(23) /* Cross-Trigger Input: current value */ +#define TRAXSTAT_ITATR BIT(24) /* ATREADY Input: current value */ + +#define TRAXADDR_TADDR_SHIFT 0 /* Trax memory address, in 32-bit words. */ +#define TRAXADDR_TADDR_MASK 0x1FFFFF /* Actually is only as big as the trace buffer size max addr. */ +#define TRAXADDR_TWRAP_SHIFT 21 /* Amount of times TADDR has overflown */ +#define TRAXADDR_TWRAP_MASK 0x3FF +#define TRAXADDR_TWSAT BIT(31) /* 1 if TWRAP has overflown, clear by disabling tren.*/ + +#define PCMATCHCTRL_PCML_SHIFT 0 /* Amount of lower bits to ignore in pc trigger register */ +#define PCMATCHCTRL_PCML_MASK 0x1F +#define PCMATCHCTRL_PCMS BIT(31) /* PC Match Sense, 0-match when procs PC is in-range, 1-match when + * out-of-range */ + +#define XTENSA_MAX_PERF_COUNTERS 2 +#define XTENSA_MAX_PERF_SELECT 32 +#define XTENSA_MAX_PERF_MASK 0xffff + +#define XTENSA_STOPMASK_DISABLED UINT32_MAX + +struct xtensa_debug_module; + +struct xtensa_debug_ops { + /** enable operation */ + int (*queue_enable)(struct xtensa_debug_module *dm); + /** register read. */ + int (*queue_reg_read)(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint8_t *data); + /** register write. */ + int (*queue_reg_write)(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint32_t data); +}; + +/* Xtensa power registers are 8 bits wide on JTAG interfaces but 32 bits wide + * when accessed via APB/DAP. In order to use DAP queuing APIs (for optimal + * performance), the XDM power register APIs take 32-bit register params. + */ +struct xtensa_power_ops { + /** register read. */ + int (*queue_reg_read)(struct xtensa_debug_module *dm, enum xtensa_dm_pwr_reg reg, uint8_t *data, + uint32_t clear); + /** register write. */ + int (*queue_reg_write)(struct xtensa_debug_module *dm, enum xtensa_dm_pwr_reg reg, uint32_t data); +}; + +typedef uint32_t xtensa_pwrstat_t; +typedef uint32_t xtensa_ocdid_t; +typedef uint32_t xtensa_dsr_t; +typedef uint32_t xtensa_traxstat_t; + +struct xtensa_power_status { + xtensa_pwrstat_t stat; + xtensa_pwrstat_t stath; + /* TODO: do not need to keep previous status to detect that core or debug module has been + * reset, */ + /* we can clear PWRSTAT_DEBUGWASRESET and PWRSTAT_COREWASRESET after reading will do + * the job; */ + /* upon next reet those bits will be set again. So we can get rid of + * xtensa_dm_power_status_cache_reset() and xtensa_dm_power_status_cache(). */ + xtensa_pwrstat_t prev_stat; +}; + +struct xtensa_core_status { + xtensa_dsr_t dsr; +}; + +struct xtensa_trace_config { + uint32_t ctrl; + uint32_t memaddr_start; + uint32_t memaddr_end; + uint32_t addr; +}; + +struct xtensa_trace_status { + xtensa_traxstat_t stat; +}; + +struct xtensa_trace_start_config { + uint32_t stoppc; + bool after_is_words; + uint32_t after; + uint32_t stopmask; /* UINT32_MAX: disable PC match option */ +}; + +struct xtensa_perfmon_config { + int select; + uint32_t mask; + int kernelcnt; + int tracelevel; +}; + +struct xtensa_perfmon_result { + uint64_t value; + bool overflow; +}; + +struct xtensa_debug_module_config { + const struct xtensa_power_ops *pwr_ops; + const struct xtensa_debug_ops *dbg_ops; + + /* Either JTAG or DAP structures will be populated */ + struct jtag_tap *tap; + void (*queue_tdi_idle)(struct target *target); + void *queue_tdi_idle_arg; + + /* For targets conforming to ARM Debug Interface v5, + * "dap" references the Debug Access Port (DAP) + * used to make requests to the target; + * "debug_ap" is AP instance connected to processor + */ + struct adiv5_dap *dap; + struct adiv5_ap *debug_ap; + int debug_apsel; + uint32_t ap_offset; +}; + +struct xtensa_debug_module { + const struct xtensa_power_ops *pwr_ops; + const struct xtensa_debug_ops *dbg_ops; + + /* Either JTAG or DAP structures will be populated */ + struct jtag_tap *tap; + void (*queue_tdi_idle)(struct target *target); + void *queue_tdi_idle_arg; + + /* DAP struct; AP instance connected to processor */ + struct adiv5_dap *dap; + struct adiv5_ap *debug_ap; + int debug_apsel; + + struct xtensa_power_status power_status; + struct xtensa_core_status core_status; + xtensa_ocdid_t device_id; + uint32_t ap_offset; +}; + +int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_module_config *cfg); +void xtensa_dm_deinit(struct xtensa_debug_module *dm); +int xtensa_dm_poll(struct xtensa_debug_module *dm); +int xtensa_dm_examine(struct xtensa_debug_module *dm); +int xtensa_dm_queue_enable(struct xtensa_debug_module *dm); +int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint8_t *value); +int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, enum xtensa_dm_reg reg, uint32_t value); +int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module *dm, + enum xtensa_dm_pwr_reg reg, + uint8_t *data, + uint32_t clear); +int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm, + enum xtensa_dm_pwr_reg reg, + uint32_t data); + +static inline int xtensa_dm_queue_execute(struct xtensa_debug_module *dm) +{ + return dm->dap ? dap_run(dm->dap) : jtag_execute_queue(); +} + +static inline void xtensa_dm_queue_tdi_idle(struct xtensa_debug_module *dm) +{ + if (dm->queue_tdi_idle) + dm->queue_tdi_idle(dm->queue_tdi_idle_arg); +} + +int xtensa_dm_power_status_read(struct xtensa_debug_module *dm, uint32_t clear); +static inline void xtensa_dm_power_status_cache_reset(struct xtensa_debug_module *dm) +{ + dm->power_status.prev_stat = 0; +} +static inline void xtensa_dm_power_status_cache(struct xtensa_debug_module *dm) +{ + dm->power_status.prev_stat = dm->power_status.stath; +} +static inline xtensa_pwrstat_t xtensa_dm_power_status_get(struct xtensa_debug_module *dm) +{ + return dm->power_status.stat; +} + +int xtensa_dm_core_status_read(struct xtensa_debug_module *dm); +int xtensa_dm_core_status_clear(struct xtensa_debug_module *dm, xtensa_dsr_t bits); +int xtensa_dm_core_status_check(struct xtensa_debug_module *dm); +static inline xtensa_dsr_t xtensa_dm_core_status_get(struct xtensa_debug_module *dm) +{ + return dm->core_status.dsr; +} + +int xtensa_dm_read(struct xtensa_debug_module *dm, uint32_t addr, uint32_t *val); +int xtensa_dm_write(struct xtensa_debug_module *dm, uint32_t addr, uint32_t val); + +int xtensa_dm_device_id_read(struct xtensa_debug_module *dm); +static inline xtensa_ocdid_t xtensa_dm_device_id_get(struct xtensa_debug_module *dm) +{ + return dm->device_id; +} + +int xtensa_dm_trace_start(struct xtensa_debug_module *dm, struct xtensa_trace_start_config *cfg); +int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable); +int xtensa_dm_trace_config_read(struct xtensa_debug_module *dm, struct xtensa_trace_config *config); +int xtensa_dm_trace_status_read(struct xtensa_debug_module *dm, struct xtensa_trace_status *status); +int xtensa_dm_trace_data_read(struct xtensa_debug_module *dm, uint8_t *dest, uint32_t size); + +static inline bool xtensa_dm_is_online(struct xtensa_debug_module *dm) +{ + int res = xtensa_dm_device_id_read(dm); + if (res != ERROR_OK) + return false; + return dm->device_id != 0xffffffff && dm->device_id != 0; +} + +static inline bool xtensa_dm_tap_was_reset(struct xtensa_debug_module *dm) +{ + return !(dm->power_status.prev_stat & PWRSTAT_DEBUGWASRESET_DM(dm)) && + dm->power_status.stat & PWRSTAT_DEBUGWASRESET_DM(dm); +} + +static inline bool xtensa_dm_core_was_reset(struct xtensa_debug_module *dm) +{ + return !(dm->power_status.prev_stat & PWRSTAT_COREWASRESET_DM(dm)) && + dm->power_status.stat & PWRSTAT_COREWASRESET_DM(dm); +} + +static inline bool xtensa_dm_core_is_stalled(struct xtensa_debug_module *dm) +{ + return dm->core_status.dsr & OCDDSR_RUNSTALLSAMPLE; +} + +static inline bool xtensa_dm_is_powered(struct xtensa_debug_module *dm) +{ + return dm->core_status.dsr & OCDDSR_DBGMODPOWERON; +} + +int xtensa_dm_perfmon_enable(struct xtensa_debug_module *dm, int counter_id, + const struct xtensa_perfmon_config *config); +int xtensa_dm_perfmon_dump(struct xtensa_debug_module *dm, int counter_id, + struct xtensa_perfmon_result *out_result); + +#endif /* OPENOCD_TARGET_XTENSA_DEBUG_MODULE_H */ diff --git a/src/target/xtensa/xtensa_fileio.c b/src/target/xtensa/xtensa_fileio.c new file mode 100644 index 0000000000..7628fbe31b --- /dev/null +++ b/src/target/xtensa/xtensa_fileio.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Xtensa Target File-I/O Support for OpenOCD * + * Copyright (C) 2020-2023 Cadence Design Systems, Inc. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xtensa_chip.h" +#include "xtensa_fileio.h" +#include "xtensa.h" + +#define XTENSA_SYSCALL(x) XT_INS_BREAK(x, 1, 14) +#define XTENSA_SYSCALL_SZ 3 +#define XTENSA_SYSCALL_LEN_MAX 255 + + +int xtensa_fileio_init(struct target *target) +{ + char *idmem = malloc(XTENSA_SYSCALL_LEN_MAX + 1); + target->fileio_info = malloc(sizeof(struct gdb_fileio_info)); + if (!idmem || !target->fileio_info) { + LOG_TARGET_ERROR(target, "Out of memory!"); + free(idmem); + free(target->fileio_info); + return ERROR_FAIL; + } + target->fileio_info->identifier = idmem; + return ERROR_OK; +} + +/** + * Checks for and processes an Xtensa File-IO request. + * + * Return ERROR_OK if request was found and handled; or + * return ERROR_FAIL if no request was detected. + */ +int xtensa_fileio_detect_proc(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + int retval; + + xtensa_reg_val_t dbg_cause = xtensa_cause_get(target); + if ((dbg_cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN)) == 0 || xtensa->halt_request) + return ERROR_FAIL; + + uint8_t brk_insn_buf[sizeof(uint32_t)] = {0}; + xtensa_reg_val_t pc = xtensa_reg_get(target, XT_REG_IDX_PC); + retval = target_read_memory(target, + pc, + XTENSA_SYSCALL_SZ, + 1, + (uint8_t *)brk_insn_buf); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read break instruction!"); + return ERROR_FAIL; + } + if (buf_get_u32(brk_insn_buf, 0, 32) != XTENSA_SYSCALL(xtensa)) + return ERROR_FAIL; + + LOG_TARGET_DEBUG(target, "File-I/O: syscall breakpoint found at 0x%x", pc); + xtensa->proc_syscall = true; + return ERROR_OK; +} + +int xtensa_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) +{ + /* fill syscall parameters to file-I/O info */ + if (!fileio_info) { + LOG_ERROR("File-I/O data structure uninitialized"); + return ERROR_FAIL; + } + + struct xtensa *xtensa = target_to_xtensa(target); + if (!xtensa->proc_syscall) + return ERROR_FAIL; + + xtensa_reg_val_t syscall = xtensa_reg_get(target, XTENSA_SYSCALL_OP_REG); + xtensa_reg_val_t arg0 = xtensa_reg_get(target, XT_REG_IDX_A6); + xtensa_reg_val_t arg1 = xtensa_reg_get(target, XT_REG_IDX_A3); + xtensa_reg_val_t arg2 = xtensa_reg_get(target, XT_REG_IDX_A4); + xtensa_reg_val_t arg3 = xtensa_reg_get(target, XT_REG_IDX_A5); + int retval = ERROR_OK; + + LOG_TARGET_DEBUG(target, "File-I/O: syscall 0x%x 0x%x 0x%x 0x%x 0x%x", + syscall, arg0, arg1, arg2, arg3); + + switch (syscall) { + case XTENSA_SYSCALL_OPEN: + snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "open"); + fileio_info->param_1 = arg0; // pathp + fileio_info->param_2 = arg3; // len + fileio_info->param_3 = arg1; // flags + fileio_info->param_4 = arg2; // mode + break; + case XTENSA_SYSCALL_CLOSE: + snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "close"); + fileio_info->param_1 = arg0; // fd + break; + case XTENSA_SYSCALL_READ: + snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "read"); + fileio_info->param_1 = arg0; // fd + fileio_info->param_2 = arg1; // bufp + fileio_info->param_3 = arg2; // count + break; + case XTENSA_SYSCALL_WRITE: + snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "write"); + fileio_info->param_1 = arg0; // fd + fileio_info->param_2 = arg1; // bufp + fileio_info->param_3 = arg2; // count + break; + case XTENSA_SYSCALL_LSEEK: + snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "lseek"); + fileio_info->param_1 = arg0; // fd + fileio_info->param_2 = arg1; // offset + fileio_info->param_3 = arg2; // flags + break; + case XTENSA_SYSCALL_RENAME: + snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "rename"); + fileio_info->param_1 = arg0; // old pathp + fileio_info->param_2 = arg3; // old len + fileio_info->param_3 = arg1; // new pathp + fileio_info->param_4 = arg2; // new len + break; + case XTENSA_SYSCALL_UNLINK: + snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "unlink"); + fileio_info->param_1 = arg0; // pathnamep + fileio_info->param_2 = arg1; // len + break; + case XTENSA_SYSCALL_STAT: + snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "stat"); + fileio_info->param_1 = arg0; // pathnamep + fileio_info->param_2 = arg2; // len + fileio_info->param_3 = arg1; // bufp + break; + case XTENSA_SYSCALL_FSTAT: + snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "fstat"); + fileio_info->param_1 = arg0; // fd + fileio_info->param_2 = arg1; // bufp + break; + case XTENSA_SYSCALL_GETTIMEOFDAY: + snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "gettimeofday"); + fileio_info->param_1 = arg0; // tvp + fileio_info->param_2 = arg1; // tzp + break; + case XTENSA_SYSCALL_ISATTY: + snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "isatty"); + fileio_info->param_1 = arg0; // fd + break; + case XTENSA_SYSCALL_SYSTEM: + snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "system"); + fileio_info->param_1 = arg0; // cmdp + fileio_info->param_2 = arg1; // len + break; + default: + snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "unknown"); + LOG_TARGET_DEBUG(target, "File-I/O: syscall unknown (%d), pc=0x%08X", + syscall, xtensa_reg_get(target, XT_REG_IDX_PC)); + LOG_INFO("File-I/O: syscall unknown (%d), pc=0x%08X", + syscall, xtensa_reg_get(target, XT_REG_IDX_PC)); + retval = ERROR_FAIL; + break; + } + + return retval; +} + +int xtensa_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c) +{ + struct xtensa *xtensa = target_to_xtensa(target); + if (!xtensa->proc_syscall) + return ERROR_FAIL; + + LOG_TARGET_DEBUG(target, "File-I/O: syscall return code: 0x%x, errno: 0x%x , ctrl_c: %s", + retcode, fileio_errno, ctrl_c ? "true" : "false"); + + /* If interrupt was requested before FIO completion (ERRNO==4), halt and repeat + * syscall. Otherwise, set File-I/O Ax and underlying ARx registers, increment PC. + * NOTE: sporadic cases of ((ERRNO==4) && !ctrl_c) were observed; most have ctrl_c. + */ + if (fileio_errno != 4) { + xtensa_reg_set_deep_relgen(target, XTENSA_SYSCALL_RETVAL_REG, retcode); + xtensa_reg_set_deep_relgen(target, XTENSA_SYSCALL_ERRNO_REG, fileio_errno); + + xtensa_reg_val_t pc = xtensa_reg_get(target, XT_REG_IDX_PC); + xtensa_reg_set(target, XT_REG_IDX_PC, pc + XTENSA_SYSCALL_SZ); + } + + xtensa->proc_syscall = false; + xtensa->halt_request = true; + return ctrl_c ? ERROR_FAIL : ERROR_OK; +} diff --git a/src/target/xtensa/xtensa_fileio.h b/src/target/xtensa/xtensa_fileio.h new file mode 100644 index 0000000000..5e1af5f864 --- /dev/null +++ b/src/target/xtensa/xtensa_fileio.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Xtensa Target File-I/O Support for OpenOCD * + * Copyright (C) 2020-2023 Cadence Design Systems, Inc. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_XTENSA_FILEIO_H +#define OPENOCD_TARGET_XTENSA_FILEIO_H + +#include <target/target.h> +#include <helper/command.h> +#include "xtensa.h" + +#define XTENSA_SYSCALL_OP_REG XT_REG_IDX_A2 +#define XTENSA_SYSCALL_RETVAL_REG XT_REG_IDX_A2 +#define XTENSA_SYSCALL_ERRNO_REG XT_REG_IDX_A3 + +#define XTENSA_SYSCALL_OPEN (-2) +#define XTENSA_SYSCALL_CLOSE (-3) +#define XTENSA_SYSCALL_READ (-4) +#define XTENSA_SYSCALL_WRITE (-5) +#define XTENSA_SYSCALL_LSEEK (-6) +#define XTENSA_SYSCALL_RENAME (-7) +#define XTENSA_SYSCALL_UNLINK (-8) +#define XTENSA_SYSCALL_STAT (-9) +#define XTENSA_SYSCALL_FSTAT (-10) +#define XTENSA_SYSCALL_GETTIMEOFDAY (-11) +#define XTENSA_SYSCALL_ISATTY (-12) +#define XTENSA_SYSCALL_SYSTEM (-13) + +int xtensa_fileio_init(struct target *target); +int xtensa_fileio_detect_proc(struct target *target); +int xtensa_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info); +int xtensa_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c); + +#endif /* OPENOCD_TARGET_XTENSA_FILEIO_H */ diff --git a/src/target/xtensa/xtensa_regs.h b/src/target/xtensa/xtensa_regs.h new file mode 100644 index 0000000000..1d9d3657ac --- /dev/null +++ b/src/target/xtensa/xtensa_regs.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Generic Xtensa target API for OpenOCD * + * Copyright (C) 2020-2022 Cadence Design Systems, Inc. * + * Copyright (C) 2016-2019 Espressif Systems Ltd. * + * Author: Angus Gratton gus@projectgus.com * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_XTENSA_REGS_H +#define OPENOCD_TARGET_XTENSA_REGS_H + +struct reg_arch_type; + +enum xtensa_reg_id { + XT_REG_IDX_PC = 0, + XT_REG_IDX_AR0, + XT_REG_IDX_ARFIRST = XT_REG_IDX_AR0, + XT_REG_IDX_AR1, + XT_REG_IDX_AR2, + XT_REG_IDX_AR3, + XT_REG_IDX_AR4, + XT_REG_IDX_AR5, + XT_REG_IDX_AR6, + XT_REG_IDX_AR7, + XT_REG_IDX_AR8, + XT_REG_IDX_AR9, + XT_REG_IDX_AR10, + XT_REG_IDX_AR11, + XT_REG_IDX_AR12, + XT_REG_IDX_AR13, + XT_REG_IDX_AR14, + XT_REG_IDX_AR15, + XT_REG_IDX_ARLAST = 64, /* Max 64 ARs */ + XT_REG_IDX_WINDOWBASE, + XT_REG_IDX_WINDOWSTART, + XT_REG_IDX_PS, + XT_REG_IDX_IBREAKENABLE, + XT_REG_IDX_DDR, + XT_REG_IDX_IBREAKA0, + XT_REG_IDX_IBREAKA1, + XT_REG_IDX_DBREAKA0, + XT_REG_IDX_DBREAKA1, + XT_REG_IDX_DBREAKC0, + XT_REG_IDX_DBREAKC1, + XT_REG_IDX_CPENABLE, + XT_REG_IDX_EXCCAUSE, + XT_REG_IDX_DEBUGCAUSE, + XT_REG_IDX_ICOUNT, + XT_REG_IDX_ICOUNTLEVEL, + XT_REG_IDX_A0, + XT_REG_IDX_A1, + XT_REG_IDX_A2, + XT_REG_IDX_A3, + XT_REG_IDX_A4, + XT_REG_IDX_A5, + XT_REG_IDX_A6, + XT_REG_IDX_A7, + XT_REG_IDX_A8, + XT_REG_IDX_A9, + XT_REG_IDX_A10, + XT_REG_IDX_A11, + XT_REG_IDX_A12, + XT_REG_IDX_A13, + XT_REG_IDX_A14, + XT_REG_IDX_A15, + XT_NUM_REGS +}; + +typedef uint32_t xtensa_reg_val_t; + +#define XT_NUM_A_REGS 16 + +enum xtensa_reg_type { + XT_REG_GENERAL = 0, /* General-purpose register; part of the windowed register set */ + XT_REG_USER = 1, /* User register, needs RUR to read */ + XT_REG_SPECIAL = 2, /* Special register, needs RSR to read */ + XT_REG_DEBUG = 3, /* Register used for the debug interface. Don't mess with this. */ + XT_REG_RELGEN = 4, /* Relative general address. Points to the absolute addresses plus the window + * index */ + XT_REG_FR = 5, /* Floating-point register */ + XT_REG_TIE = 6, /* TIE (custom) register */ + XT_REG_OTHER = 7, /* Other (typically legacy) register */ + XT_REG_TYPE_NUM, + + /* enum names must be one of the above types + _VAL or _MASK */ + XT_REG_GENERAL_MASK = 0xFFC0, + XT_REG_GENERAL_VAL = 0x0100, + XT_REG_USER_MASK = 0xFF00, + XT_REG_USER_VAL = 0x0300, + XT_REG_SPECIAL_MASK = 0xFF00, + XT_REG_SPECIAL_VAL = 0x0200, + XT_REG_DEBUG_MASK = 0xFF00, + XT_REG_DEBUG_VAL = 0x0200, + XT_REG_RELGEN_MASK = 0xFFE0, + XT_REG_RELGEN_VAL = 0x0000, + XT_REG_FR_MASK = 0xFFF0, + XT_REG_FR_VAL = 0x0030, + XT_REG_TIE_MASK = 0xF000, + XT_REG_TIE_VAL = 0xF000, /* unused */ + XT_REG_OTHER_MASK = 0xFFFF, + XT_REG_OTHER_VAL = 0xF000, /* unused */ + + XT_REG_INDEX_MASK = 0x00FF +}; + +enum xtensa_reg_flags { + XT_REGF_NOREAD = 0x01, /* Register is write-only */ + XT_REGF_COPROC0 = 0x02, /* Can't be read if coproc0 isn't enabled */ + XT_REGF_MASK = 0x03 +}; + +struct xtensa_reg_desc { + const char *name; + bool exist; + unsigned int reg_num; /* ISA register num (meaning depends on register type) */ + unsigned int dbreg_num; /* Debugger-visible register num (reg type encoded) */ + enum xtensa_reg_type type; + enum xtensa_reg_flags flags; +}; + +#define _XT_MK_DBREGN(reg_num, reg_type) \ + ((reg_type ## _VAL) | (reg_num)) + +#define _XT_MK_DBREGN_MASK(reg_num, reg_mask) \ + ((reg_mask) | (reg_num)) + +#define XT_MK_REG_DESC(n, r, t, f) \ + { .name = (n), .exist = false, .reg_num = (r), \ + .dbreg_num = _XT_MK_DBREGN(r, t), .type = (t), \ + .flags = (f) } + +extern struct xtensa_reg_desc xtensa_regs[XT_NUM_REGS]; + +#endif /* OPENOCD_TARGET_XTENSA_REGS_H */ diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index 9076d9b68d..cb4f48f666 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libtransport.la %C%_libtransport_la_SOURCES = \ %D%/transport.c \ diff --git a/src/transport/transport.c b/src/transport/transport.c index ba1af33989..81d3d583bc 100644 --- a/src/transport/transport.c +++ b/src/transport/transport.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Copyright (c) 2010 by David Brownell - * - * 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/>. */ #ifdef HAVE_CONFIG_H @@ -115,7 +104,7 @@ int allow_transports(struct command_context *ctx, const char * const *vector) /* autoselect if there's no choice ... */ if (!vector[1]) { - LOG_INFO("only one transport option; autoselect '%s'", vector[0]); + LOG_INFO("only one transport option; autoselecting '%s'", vector[0]); return transport_select(ctx, vector[0]); } @@ -263,64 +252,62 @@ COMMAND_HANDLER(handle_transport_list) * set supported by the debug adapter being used. Return value * is scriptable (allowing "if swd then..." etc). */ -static int jim_transport_select(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(handle_transport_select) { - int res; - switch (argc) { - case 1: /* autoselect if necessary, then return/display current config */ - if (!session) { - if (!allowed_transports) { - LOG_ERROR("Debug adapter does not support any transports? Check config file order."); - return JIM_ERR; - } - LOG_INFO("auto-selecting first available session transport \"%s\". " - "To override use 'transport select <transport>'.", allowed_transports[0]); - res = transport_select(global_cmd_ctx, allowed_transports[0]); - if (res != JIM_OK) - return res; - } - Jim_SetResultString(interp, session->name, -1); - return JIM_OK; - case 2: /* assign */ - if (session) { - if (!strcmp(session->name, argv[1]->bytes)) { - LOG_WARNING("Transport \"%s\" was already selected", session->name); - Jim_SetResultString(interp, session->name, -1); - return JIM_OK; - } else { - LOG_ERROR("Can't change session's transport after the initial selection was made"); - return JIM_ERR; - } - } + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; - /* Is this transport supported by our debug adapter? - * Example, "JTAG-only" means SWD is not supported. - * - * NOTE: requires adapter to have been set up, with - * transports declared via C. - */ + if (CMD_ARGC == 0) { + /* autoselect if necessary, then return/display current config */ + if (!session) { if (!allowed_transports) { - LOG_ERROR("Debug adapter doesn't support any transports?"); - return JIM_ERR; + command_print(CMD, "Debug adapter does not support any transports? Check config file order."); + return ERROR_FAIL; } + LOG_INFO("auto-selecting first available session transport \"%s\". " + "To override use 'transport select <transport>'.", allowed_transports[0]); + int retval = transport_select(CMD_CTX, allowed_transports[0]); + if (retval != ERROR_OK) + return retval; + } + command_print(CMD, "%s", session->name); + return ERROR_OK; + } - for (unsigned i = 0; allowed_transports[i]; i++) { + /* assign transport */ + if (session) { + if (!strcmp(session->name, CMD_ARGV[0])) { + LOG_WARNING("Transport \"%s\" was already selected", session->name); + command_print(CMD, "%s", session->name); + return ERROR_OK; + } + command_print(CMD, "Can't change session's transport after the initial selection was made"); + return ERROR_FAIL; + } - if (strcmp(allowed_transports[i], argv[1]->bytes) == 0) { - if (transport_select(global_cmd_ctx, argv[1]->bytes) == ERROR_OK) { - Jim_SetResultString(interp, session->name, -1); - return JIM_OK; - } - return JIM_ERR; - } - } + /* Is this transport supported by our debug adapter? + * Example, "JTAG-only" means SWD is not supported. + * + * NOTE: requires adapter to have been set up, with + * transports declared via C. + */ + if (!allowed_transports) { + command_print(CMD, "Debug adapter doesn't support any transports?"); + return ERROR_FAIL; + } - LOG_ERROR("Debug adapter doesn't support '%s' transport", argv[1]->bytes); - return JIM_ERR; - default: - Jim_WrongNumArgs(interp, 1, argv, "[too many parameters]"); - return JIM_ERR; + for (unsigned int i = 0; allowed_transports[i]; i++) { + if (!strcmp(allowed_transports[i], CMD_ARGV[0])) { + int retval = transport_select(CMD_CTX, CMD_ARGV[0]); + if (retval != ERROR_OK) + return retval; + command_print(CMD, "%s", session->name); + return ERROR_OK; + } } + + command_print(CMD, "Debug adapter doesn't support '%s' transport", CMD_ARGV[0]); + return ERROR_FAIL; } static const struct command_registration transport_commands[] = { @@ -344,7 +331,7 @@ static const struct command_registration transport_commands[] = { }, { .name = "select", - .jim_handler = jim_transport_select, + .handler = handle_transport_select, .mode = COMMAND_ANY, .help = "Select this session's transport", .usage = "[transport_name]", diff --git a/src/transport/transport.h b/src/transport/transport.h index e04f780635..00d8b07e11 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /* * Copyright (c) 2010 by David Brownell * Copyright (C) 2011 Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) - * - * 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/>. */ #ifndef OPENOCD_TRANSPORT_TRANSPORT_H diff --git a/src/xsvf/Makefile.am b/src/xsvf/Makefile.am index 61e6fb9200..08f1cc1d86 100644 --- a/src/xsvf/Makefile.am +++ b/src/xsvf/Makefile.am @@ -1,2 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + noinst_LTLIBRARIES += %D%/libxsvf.la %C%_libxsvf_la_SOURCES = %D%/xsvf.c %D%/xsvf.h diff --git a/src/xsvf/xsvf.c b/src/xsvf/xsvf.c index c4ce55adca..0266c2120c 100644 --- a/src/xsvf/xsvf.c +++ b/src/xsvf/xsvf.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -10,19 +12,6 @@ * * * Copyright (C) 2009 SoftPLC Corporation. http://softplc.com * * Dick Hollenbeck <dick@softplc.com> * - * * - * 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/>. * ***************************************************************************/ /* The specification for SVF is available here: diff --git a/src/xsvf/xsvf.h b/src/xsvf/xsvf.h index aa0f4f0404..04ba056da7 100644 --- a/src/xsvf/xsvf.h +++ b/src/xsvf/xsvf.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * - * * - * 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/>. * ***************************************************************************/ #ifndef OPENOCD_XSVF_XSVF_H diff --git a/tcl/bitsbytes.tcl b/tcl/bitsbytes.tcl index 756c725df6..03d758e7c8 100644 --- a/tcl/bitsbytes.tcl +++ b/tcl/bitsbytes.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #---------------------------------------- # Purpose - Create some $BIT variables # Create $K and $M variables diff --git a/tcl/board/8devices-lima.cfg b/tcl/board/8devices-lima.cfg index 0d35cfbc14..a094caedee 100644 --- a/tcl/board/8devices-lima.cfg +++ b/tcl/board/8devices-lima.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Product page: # https://www.8devices.com/products/lima # diff --git a/tcl/board/actux3.cfg b/tcl/board/actux3.cfg index 0de4cb4cac..edb529c889 100644 --- a/tcl/board/actux3.cfg +++ b/tcl/board/actux3.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # board config file for AcTux3/XBA IXP42x board # Date: 2010-12-16 # Author: Michael Schwingen <michael@schwingen.org> diff --git a/tcl/board/adapteva_parallella1.cfg b/tcl/board/adapteva_parallella1.cfg index 83d1cd44b1..d6336a8e2e 100644 --- a/tcl/board/adapteva_parallella1.cfg +++ b/tcl/board/adapteva_parallella1.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Adapteva Parallella-I board (via Porcupine-1 adapter board) # diff --git a/tcl/board/adsp-sc584-ezbrd.cfg b/tcl/board/adsp-sc584-ezbrd.cfg index 82df381f61..366a24a3f4 100644 --- a/tcl/board/adsp-sc584-ezbrd.cfg +++ b/tcl/board/adsp-sc584-ezbrd.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Analog Devices ADSP-SC584-EZBRD evaluation board # diff --git a/tcl/board/advantech_imx8qm_dmsse20.cfg b/tcl/board/advantech_imx8qm_dmsse20.cfg new file mode 100644 index 0000000000..a867b2de01 --- /dev/null +++ b/tcl/board/advantech_imx8qm_dmsse20.cfg @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# configuration file for Advantech IMX8QM DMSSE20 +# + +# only JTAG supported +transport select jtag + +# set a safe JTAG clock speed, can be overridden +adapter speed 1000 + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 70 + +# board has an i.MX8QM with 4 Cortex-A53 cores and 2 Cortex-A72 +set CHIPNAME imx8qm +set CHIPCORES 6 + +# source SoC configuration +source [find tcl/target/imx8qm.cfg] diff --git a/tcl/board/alphascale_asm9260_ek.cfg b/tcl/board/alphascale_asm9260_ek.cfg index 1c126827f5..33a8354110 100644 --- a/tcl/board/alphascale_asm9260_ek.cfg +++ b/tcl/board/alphascale_asm9260_ek.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/alphascale_asm9260t.cfg] reset_config trst_and_srst diff --git a/tcl/board/altera_sockit.cfg b/tcl/board/altera_sockit.cfg index 4d10aef7b1..bbd87d6466 100644 --- a/tcl/board/altera_sockit.cfg +++ b/tcl/board/altera_sockit.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Cyclone V SocKit board # http://www.altera.com/b/arrow-sockit.html diff --git a/tcl/board/am3517evm.cfg b/tcl/board/am3517evm.cfg index 8d6eba160e..0b19be68bc 100644 --- a/tcl/board/am3517evm.cfg +++ b/tcl/board/am3517evm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # DANGER!!!! early work in progress for this PCB/target. # # The most basic operations work well enough that it is diff --git a/tcl/board/ampere_emag8180.cfg b/tcl/board/ampere_emag8180.cfg index a122e02883..736be12258 100644 --- a/tcl/board/ampere_emag8180.cfg +++ b/tcl/board/ampere_emag8180.cfg @@ -1,22 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # OpenOCD Board Configuration for eMAG Development Platform # # Copyright (c) 2019-2021, Ampere Computing LLC # -# 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; -# -# # # Configure JTAG speed diff --git a/tcl/board/ampere_qs_mq_1s.cfg b/tcl/board/ampere_qs_mq_1s.cfg new file mode 100644 index 0000000000..bc649edb8f --- /dev/null +++ b/tcl/board/ampere_qs_mq_1s.cfg @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# OpenOCD Board Configuration for Ampere Altra ("Quicksilver") and +# Ampere Altra Max ("Mystique") processors +# +# Copyright (c) 2019-2021, Ampere Computing LLC + +# Argument Description +# +# JTAGFREQ +# Set the JTAG clock frequency +# Syntax: -c "set JTAGFREQ {freq_in_khz}" +# +# SYSNAME +# Set the system name +# If not specified, defaults to "qs" +# Syntax: -c "set SYSNAME {qs}" +# +# Life-Cycle State (LCS) +# If not specified, defaults to "Secure LCS" +# LCS=0, "Secure LCS" +# LCS=1, "Chip Manufacturing LCS" +# Syntax: -c "set LCS {0}" +# Syntax: -c "set LCS {1}" +# +# CORELIST_S0 +# Specify available physical cores by number +# Example syntax to connect to physical cores 16 and 17 for S0 +# Syntax: -c "set CORELIST_S0 {16 17}" +# +# COREMASK_S0_LO +# Specify available physical cores 0-63 by mask +# Example syntax to connect to physical cores 16 and 17 for S0 +# Syntax: -c "set COREMASK_S0_LO {0x0000000000030000}" +# +# COREMASK_S0_HI +# Specify available physical cores 64 and above by mask +# Example syntax to connect to physical cores 94 and 95 for S0 +# Syntax: -c "set COREMASK_S0_HI {0x00000000C0000000}" +# +# PHYS_IDX +# Enable OpenOCD ARMv8 core target physical indexing +# If not specified, defaults to OpenOCD ARMv8 core target logical indexing +# Syntax: -c "set PHYS_IDX {}" + +# +# Configure JTAG speed +# + +if { [info exists JTAGFREQ] } { + adapter speed $JTAGFREQ +} else { + adapter speed 100 +} + +# +# Set the system name +# + +if { [info exists SYSNAME] } { + set _SYSNAME $SYSNAME +} else { + set _SYSNAME qs +} + +# +# Configure Resets +# + +jtag_ntrst_delay 100 +reset_config trst_only + +# +# Configure Targets +# + +if { [info exists CORELIST_S0] || [info exists COREMASK_S0_LO] || [info exists COREMASK_S0_HI] } { + set CHIPNAME ${_SYSNAME}0 + if { [info exists CORELIST_S0] } { + set CORELIST $CORELIST_S0 + } else { + if { [info exists COREMASK_S0_LO] } { + set COREMASK_LO $COREMASK_S0_LO + } else { + set COREMASK_LO 0x0 + } + + if { [info exists COREMASK_S0_HI] } { + set COREMASK_HI $COREMASK_S0_HI + } else { + set COREMASK_HI 0x0 + } + } +} else { + set CHIPNAME ${_SYSNAME}0 + set COREMASK_LO 0x1 + set COREMASK_HI 0x0 +} + +source [find target/ampere_qs_mq.cfg] diff --git a/tcl/board/ampere_qs_mq_2s.cfg b/tcl/board/ampere_qs_mq_2s.cfg new file mode 100644 index 0000000000..76d82d214e --- /dev/null +++ b/tcl/board/ampere_qs_mq_2s.cfg @@ -0,0 +1,164 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# OpenOCD Board Configuration for Ampere Altra ("Quicksilver") and +# Ampere Altra Max ("Mystique") processors +# +# Copyright (c) 2019-2021, Ampere Computing LLC + +# Argument Description +# +# JTAGFREQ +# Set the JTAG clock frequency +# Syntax: -c "set JTAGFREQ {freq_in_khz}" +# +# SYSNAME +# Set the system name +# If not specified, defaults to "qs" +# Syntax: -c "set SYSNAME {qs}" +# +# Life-Cycle State (LCS) +# If not specified, defaults to "Secure LCS" +# LCS=0, "Secure LCS" +# LCS=1, "Chip Manufacturing LCS" +# Syntax: -c "set LCS {0}" +# Syntax: -c "set LCS {1}" +# +# CORELIST_S0, CORELIST_S1 +# Specify available physical cores by number +# Example syntax to connect to physical cores 16 and 17 for S0 and S1 +# Syntax: -c "set CORELIST_S0 {16 17}" +# Syntax: -c "set CORELIST_S1 {16 17}" +# +# COREMASK_S0_LO, COREMASK_S1_LO +# Specify available physical cores 0-63 by mask +# Example syntax to connect to physical cores 16 and 17 for S0 and S1 +# Syntax: -c "set COREMASK_S0_LO {0x0000000000030000}" +# Syntax: -c "set COREMASK_S1_LO {0x0000000000030000}" +# +# COREMASK_S0_HI, COREMASK_S1_HI +# Specify available physical cores 64 and above by mask +# Example syntax to connect to physical cores 94 and 95 for S0 and S1 +# Syntax: -c "set COREMASK_S0_HI {0x00000000C0000000}" +# Syntax: -c "set COREMASK_S1_HI {0x00000000C0000000}" +# +# SPLITSMP +# Group all ARMv8 cores per socket into individual SMP sessions +# If not specified, group ARMv8 cores from both sockets into one SMP session +# Syntax: -c "set SPLITSMP {}" +# +# PHYS_IDX +# Enable OpenOCD ARMv8 core target physical indexing +# If not specified, defaults to OpenOCD ARMv8 core target logical indexing +# Syntax: -c "set PHYS_IDX {}" + +# +# Configure JTAG speed +# + +if { [info exists JTAGFREQ] } { + adapter speed $JTAGFREQ +} else { + adapter speed 100 +} + +# +# Set the system name +# + +if { [info exists SYSNAME] } { + set _SYSNAME $SYSNAME +} else { + set _SYSNAME qs +} + +# +# Configure Board level SMP configuration if necessary +# + +if { ![info exists SPLITSMP] } { + # Group dual chip into a single SMP configuration + set SMP_STR "target smp" + set CORE_INDEX_OFFSET 0 + set DUAL_SOCKET_SMP_ENABLED "" +} + +# +# Configure Resets +# + +jtag_ntrst_delay 100 +reset_config trst_only + +# +# Configure Targets +# + +if { [info exists CORELIST_S0] || [info exists COREMASK_S0_LO] || [info exists COREMASK_S0_HI] || \ + [info exists CORELIST_S1] || [info exists COREMASK_S1_LO] || [info exists COREMASK_S1_HI] } { + set CHIPNAME ${_SYSNAME}1 + if { [info exists CORELIST_S1] } { + set CORELIST $CORELIST_S1 + } else { + if { [info exists COREMASK_S1_LO] } { + set COREMASK_LO $COREMASK_S1_LO + } else { + set COREMASK_LO 0x0 + } + + if { [info exists COREMASK_S1_HI] } { + set COREMASK_HI $COREMASK_S1_HI + } else { + set COREMASK_HI 0x0 + } + } + source [find target/ampere_qs_mq.cfg] + + if { [info exists DUAL_SOCKET_SMP_ENABLED] && [info exists PHYS_IDX]} { + if { [info exists MQ_ENABLE] } { + set CORE_INDEX_OFFSET 128 + } else { + set CORE_INDEX_OFFSET 80 + } + } + + set CHIPNAME ${_SYSNAME}0 + if { [info exists CORELIST_S0] } { + set CORELIST $CORELIST_S0 + } else { + if { [info exists COREMASK_S0_LO] } { + set COREMASK_LO $COREMASK_S0_LO + } else { + set COREMASK_LO 0x0 + } + + if { [info exists COREMASK_S0_HI] } { + set COREMASK_HI $COREMASK_S0_HI + } else { + set COREMASK_HI 0x0 + } + } + source [find target/ampere_qs_mq.cfg] +} else { + set CHIPNAME ${_SYSNAME}1 + set COREMASK_LO 0x0 + set COREMASK_HI 0x0 + source [find target/ampere_qs_mq.cfg] + + if { [info exists DUAL_SOCKET_SMP_ENABLED] && [info exists PHYS_IDX]} { + if { [info exists MQ_ENABLE] } { + set CORE_INDEX_OFFSET 128 + } else { + set CORE_INDEX_OFFSET 80 + } + } + + set CHIPNAME ${_SYSNAME}0 + set COREMASK_LO 0x1 + set COREMASK_HI 0x0 + source [find target/ampere_qs_mq.cfg] +} + +if { [info exists DUAL_SOCKET_SMP_ENABLED] } { + # For dual socket SMP configuration, evaluate the string + eval $SMP_STR +} diff --git a/tcl/board/arm_evaluator7t.cfg b/tcl/board/arm_evaluator7t.cfg index ef4b7821f9..0fb8778ce4 100644 --- a/tcl/board/arm_evaluator7t.cfg +++ b/tcl/board/arm_evaluator7t.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This board is from ARM and has an samsung s3c45101x01 chip source [find target/samsung_s3c4510.cfg] diff --git a/tcl/board/arm_musca_a.cfg b/tcl/board/arm_musca_a.cfg index 25f8ce61af..b4880d1006 100644 --- a/tcl/board/arm_musca_a.cfg +++ b/tcl/board/arm_musca_a.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Configuration script for ARM Musca-A development board # diff --git a/tcl/board/arty_s7.cfg b/tcl/board/arty_s7.cfg index a5e26fc94a..eaa15ab407 100644 --- a/tcl/board/arty_s7.cfg +++ b/tcl/board/arty_s7.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Arty S7: Spartan7 25/50 FPGA Board for Makers and Hobbyists # diff --git a/tcl/board/asus-rt-n16.cfg b/tcl/board/asus-rt-n16.cfg index 78f111d380..a02bab853b 100644 --- a/tcl/board/asus-rt-n16.cfg +++ b/tcl/board/asus-rt-n16.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # http://wikidevi.com/wiki/ASUS_RT-N16 # diff --git a/tcl/board/asus-rt-n66u.cfg b/tcl/board/asus-rt-n66u.cfg index 4b255cf94e..dda0f33b73 100644 --- a/tcl/board/asus-rt-n66u.cfg +++ b/tcl/board/asus-rt-n66u.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # http://wikidevi.com/wiki/Asus_RT-N66U # diff --git a/tcl/board/at91cap7a-stk-sdram.cfg b/tcl/board/at91cap7a-stk-sdram.cfg index 182a4067f9..6da917ac78 100644 --- a/tcl/board/at91cap7a-stk-sdram.cfg +++ b/tcl/board/at91cap7a-stk-sdram.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4394 # # use combined on interfaces or targets that can't set TRST/SRST separately diff --git a/tcl/board/at91eb40a.cfg b/tcl/board/at91eb40a.cfg index d314e181de..60c6c6eac4 100644 --- a/tcl/board/at91eb40a.cfg +++ b/tcl/board/at91eb40a.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #Script for AT91EB40a # FIXME use some standard target config, maybe create one from this diff --git a/tcl/board/at91rm9200-dk.cfg b/tcl/board/at91rm9200-dk.cfg index b8ec00eab9..3751103fcd 100644 --- a/tcl/board/at91rm9200-dk.cfg +++ b/tcl/board/at91rm9200-dk.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # This is for the "at91rm9200-DK" (not the EK) eval board. # diff --git a/tcl/board/at91rm9200-ek.cfg b/tcl/board/at91rm9200-ek.cfg index 958bc9d518..e38914e46a 100644 --- a/tcl/board/at91rm9200-ek.cfg +++ b/tcl/board/at91rm9200-ek.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Copyright 2010 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> # diff --git a/tcl/board/at91sam9261-ek.cfg b/tcl/board/at91sam9261-ek.cfg index 1f3de48b80..c2d97b04e9 100644 --- a/tcl/board/at91sam9261-ek.cfg +++ b/tcl/board/at91sam9261-ek.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################ # Atmel AT91SAM9261-EK eval board ################################################################################ diff --git a/tcl/board/at91sam9263-ek.cfg b/tcl/board/at91sam9263-ek.cfg index ab04228ce1..328a792a4f 100644 --- a/tcl/board/at91sam9263-ek.cfg +++ b/tcl/board/at91sam9263-ek.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################ # Atmel AT91SAM9263-EK eval board ################################################################################ diff --git a/tcl/board/at91sam9g20-ek.cfg b/tcl/board/at91sam9g20-ek.cfg index 04d9a197cc..4740471c89 100644 --- a/tcl/board/at91sam9g20-ek.cfg +++ b/tcl/board/at91sam9g20-ek.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################################# # # # Author: Gary Carlson (gcarlson@carlson-minot.com) # @@ -5,10 +7,6 @@ # # ################################################################################################# -# FIXME use some standard target config, maybe create one from this -# -# source [find target/...cfg] - source [find target/at91sam9g20.cfg] set _FLASHTYPE nandflash_cs3 diff --git a/tcl/board/atmel_at91sam7s-ek.cfg b/tcl/board/atmel_at91sam7s-ek.cfg index 48edfc9a77..9cf85df235 100644 --- a/tcl/board/atmel_at91sam7s-ek.cfg +++ b/tcl/board/atmel_at91sam7s-ek.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Atmel AT91SAM7S-EK # http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3784 diff --git a/tcl/board/atmel_at91sam9260-ek.cfg b/tcl/board/atmel_at91sam9260-ek.cfg index a37f1f5d89..56fce3a718 100644 --- a/tcl/board/atmel_at91sam9260-ek.cfg +++ b/tcl/board/atmel_at91sam9260-ek.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################ # Atmel AT91SAM9260-EK eval board # diff --git a/tcl/board/atmel_at91sam9rl-ek.cfg b/tcl/board/atmel_at91sam9rl-ek.cfg index e18d1fdf3a..cc3d9744e3 100644 --- a/tcl/board/atmel_at91sam9rl-ek.cfg +++ b/tcl/board/atmel_at91sam9rl-ek.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################ # # Generated for Atmel AT91SAM9RL-EK evaluation board using Atmel SAM-ICE (J-Link) V6 diff --git a/tcl/board/atmel_sam3n_ek.cfg b/tcl/board/atmel_sam3n_ek.cfg index e43008f108..af2fd952bf 100644 --- a/tcl/board/atmel_sam3n_ek.cfg +++ b/tcl/board/atmel_sam3n_ek.cfg @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later # # Board configuration for Atmel's SAM3N-EK diff --git a/tcl/board/atmel_sam3s_ek.cfg b/tcl/board/atmel_sam3s_ek.cfg index 6e8ffe4172..136e31d22f 100644 --- a/tcl/board/atmel_sam3s_ek.cfg +++ b/tcl/board/atmel_sam3s_ek.cfg @@ -1 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/at91sam3sXX.cfg] diff --git a/tcl/board/atmel_sam3u_ek.cfg b/tcl/board/atmel_sam3u_ek.cfg index 1584879bfa..c308003a4d 100644 --- a/tcl/board/atmel_sam3u_ek.cfg +++ b/tcl/board/atmel_sam3u_ek.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/at91sam3u4e.cfg] reset_config srst_only diff --git a/tcl/board/atmel_sam3x_ek.cfg b/tcl/board/atmel_sam3x_ek.cfg index bb8cd17130..c321cfbe22 100644 --- a/tcl/board/atmel_sam3x_ek.cfg +++ b/tcl/board/atmel_sam3x_ek.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/at91sam3ax_8x.cfg] reset_config srst_only diff --git a/tcl/board/atmel_sam4e_ek.cfg b/tcl/board/atmel_sam4e_ek.cfg index 75e67a94f5..61191a925d 100644 --- a/tcl/board/atmel_sam4e_ek.cfg +++ b/tcl/board/atmel_sam4e_ek.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an SAM4E-EK board with a single SAM4E16 chip. # http://www.atmel.com/tools/sam4e-ek.aspx diff --git a/tcl/board/atmel_sam4l8_xplained_pro.cfg b/tcl/board/atmel_sam4l8_xplained_pro.cfg index 80ccc9f19f..d0c45163c8 100644 --- a/tcl/board/atmel_sam4l8_xplained_pro.cfg +++ b/tcl/board/atmel_sam4l8_xplained_pro.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Atmel SAM4L8 Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAM4L8-XPRO.aspx diff --git a/tcl/board/atmel_sam4s_ek.cfg b/tcl/board/atmel_sam4s_ek.cfg index ca11e54871..7e4bb83a5f 100644 --- a/tcl/board/atmel_sam4s_ek.cfg +++ b/tcl/board/atmel_sam4s_ek.cfg @@ -1 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/at91sam4sXX.cfg] diff --git a/tcl/board/atmel_sam4s_xplained_pro.cfg b/tcl/board/atmel_sam4s_xplained_pro.cfg index d2acc487e5..92191c7d18 100644 --- a/tcl/board/atmel_sam4s_xplained_pro.cfg +++ b/tcl/board/atmel_sam4s_xplained_pro.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Atmel SAM4S Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAM4S-XPRO.aspx diff --git a/tcl/board/atmel_samc20_xplained_pro.cfg b/tcl/board/atmel_samc20_xplained_pro.cfg index 1278eb7f17..3ac89a536a 100644 --- a/tcl/board/atmel_samc20_xplained_pro.cfg +++ b/tcl/board/atmel_samc20_xplained_pro.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Atmel SAMC20 Xplained Pro evaluation kit. # diff --git a/tcl/board/atmel_samc21_xplained_pro.cfg b/tcl/board/atmel_samc21_xplained_pro.cfg index ac269305c0..5ad6ccfda1 100644 --- a/tcl/board/atmel_samc21_xplained_pro.cfg +++ b/tcl/board/atmel_samc21_xplained_pro.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Atmel SAMC21 Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAMC21-XPRO.aspx diff --git a/tcl/board/atmel_samd10_xplained_mini.cfg b/tcl/board/atmel_samd10_xplained_mini.cfg index 64ae11ee92..f9f1d242e0 100644 --- a/tcl/board/atmel_samd10_xplained_mini.cfg +++ b/tcl/board/atmel_samd10_xplained_mini.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Atmel SAMD10 Xplained mini evaluation kit. # http://www.atmel.com/tools/atsamd10-xmini.aspx diff --git a/tcl/board/atmel_samd11_xplained_pro.cfg b/tcl/board/atmel_samd11_xplained_pro.cfg index 8ce9751b85..724c921b5d 100644 --- a/tcl/board/atmel_samd11_xplained_pro.cfg +++ b/tcl/board/atmel_samd11_xplained_pro.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Atmel SAMD11 Xplained Pro evaluation kit. # diff --git a/tcl/board/atmel_samd20_xplained_pro.cfg b/tcl/board/atmel_samd20_xplained_pro.cfg index 525aee069c..1492958aa6 100644 --- a/tcl/board/atmel_samd20_xplained_pro.cfg +++ b/tcl/board/atmel_samd20_xplained_pro.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Atmel SAMD20 Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAMD20-XPRO.aspx diff --git a/tcl/board/atmel_samd21_xplained_pro.cfg b/tcl/board/atmel_samd21_xplained_pro.cfg index 843b0ce216..f55b6b94d3 100644 --- a/tcl/board/atmel_samd21_xplained_pro.cfg +++ b/tcl/board/atmel_samd21_xplained_pro.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Atmel SAMD21 Xplained Pro evaluation kit. # diff --git a/tcl/board/atmel_same70_xplained.cfg b/tcl/board/atmel_same70_xplained.cfg index a22e801a2b..f20e2a30f5 100644 --- a/tcl/board/atmel_same70_xplained.cfg +++ b/tcl/board/atmel_same70_xplained.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Atmel SAME70 Xplained evaluation kit. # http://www.atmel.com/tools/ATSAME70-XPLD.aspx diff --git a/tcl/board/atmel_samg53_xplained_pro.cfg b/tcl/board/atmel_samg53_xplained_pro.cfg index 06638cf563..060750c48c 100644 --- a/tcl/board/atmel_samg53_xplained_pro.cfg +++ b/tcl/board/atmel_samg53_xplained_pro.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Atmel SAMG53 Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAMG53-XPRO.aspx diff --git a/tcl/board/atmel_samg55_xplained_pro.cfg b/tcl/board/atmel_samg55_xplained_pro.cfg index 3797bf8bc7..147dc732b9 100644 --- a/tcl/board/atmel_samg55_xplained_pro.cfg +++ b/tcl/board/atmel_samg55_xplained_pro.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Atmel SAMG55 Xplained Pro evaluation kit. # http://www.atmel.com/tools/ATSAMG55-XPRO.aspx diff --git a/tcl/board/atmel_saml21_xplained_pro.cfg b/tcl/board/atmel_saml21_xplained_pro.cfg index 054bda4dab..8e62eb295b 100644 --- a/tcl/board/atmel_saml21_xplained_pro.cfg +++ b/tcl/board/atmel_saml21_xplained_pro.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Atmel SAML21 Xplained Pro evaluation kit. # diff --git a/tcl/board/atmel_samr21_xplained_pro.cfg b/tcl/board/atmel_samr21_xplained_pro.cfg index 308e2bdb74..cd6d28ecd0 100644 --- a/tcl/board/atmel_samr21_xplained_pro.cfg +++ b/tcl/board/atmel_samr21_xplained_pro.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Atmel SAMR21 Xplained Pro evaluation kit. # diff --git a/tcl/board/atmel_samv71_xplained_ultra.cfg b/tcl/board/atmel_samv71_xplained_ultra.cfg index 4e0865d996..9368f610d9 100644 --- a/tcl/board/atmel_samv71_xplained_ultra.cfg +++ b/tcl/board/atmel_samv71_xplained_ultra.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Atmel SAMV71 Xplained Ultra evaluation kit. # http://www.atmel.com/tools/ATSAMV71-XULT.aspx diff --git a/tcl/board/avnet_ultrazed-eg.cfg b/tcl/board/avnet_ultrazed-eg.cfg index 3e4a11a3e4..6701fd102f 100644 --- a/tcl/board/avnet_ultrazed-eg.cfg +++ b/tcl/board/avnet_ultrazed-eg.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # AVNET UltraZED EG StarterKit # ZynqMP UlraScale-EG plus IO Carrier with on-board digilent smt2 diff --git a/tcl/board/balloon3-cpu.cfg b/tcl/board/balloon3-cpu.cfg index 468b867b27..3ee840bda7 100644 --- a/tcl/board/balloon3-cpu.cfg +++ b/tcl/board/balloon3-cpu.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Config for balloon3 board, cpu JTAG port. http://balloonboard.org/ # The board has separate JTAG ports for cpu and CPLD/FPGA devices # Chaining is done on IO interfaces if desired. diff --git a/tcl/board/bcm28155_ap.cfg b/tcl/board/bcm28155_ap.cfg index 5d3d22a3e5..99da948fff 100644 --- a/tcl/board/bcm28155_ap.cfg +++ b/tcl/board/bcm28155_ap.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # BCM28155_AP adapter speed 20000 diff --git a/tcl/board/bemicro_cycloneiii.cfg b/tcl/board/bemicro_cycloneiii.cfg new file mode 100644 index 0000000000..bd1459adc4 --- /dev/null +++ b/tcl/board/bemicro_cycloneiii.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# BeMicro Cyclone III + + +adapter driver ftdi +ftdi channel 0 +ftdi layout_init 0x0008 0x008b +ftdi vid_pid 0x0403 0xa4a0 +reset_config none +transport select jtag + +adapter speed 10000 + +source [find fpga/altera-cycloneiii.cfg] + +#quartus_cpf --option=bitstream_compression=off -c output_files\cycloneiii_blinker.sof cycloneiii_blinker.rbf + +#openocd -f board/bemicro_cycloneiii.cfg -c "init" -c "pld load cycloneiii.pld cycloneiii_blinker.rbf" +# "ipdbg -start -tap cycloneiii.tap -hub 0x00e -tool 0 -port 5555" + + +set JTAGSPI_CHAIN_ID cycloneiii.pld +source [find cpld/jtagspi.cfg] diff --git a/tcl/board/bluefield.cfg b/tcl/board/bluefield.cfg index 3058d48ca3..e96a74e0eb 100644 --- a/tcl/board/bluefield.cfg +++ b/tcl/board/bluefield.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Board configuration for BlueField SoC. # diff --git a/tcl/board/bt-homehubv1.cfg b/tcl/board/bt-homehubv1.cfg index c50c7d2b60..bbb6fa4366 100644 --- a/tcl/board/bt-homehubv1.cfg +++ b/tcl/board/bt-homehubv1.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # BT HomeHub v1 # diff --git a/tcl/board/calao-usb-a9260.cfg b/tcl/board/calao-usb-a9260.cfg new file mode 100644 index 0000000000..52fede0fa5 --- /dev/null +++ b/tcl/board/calao-usb-a9260.cfg @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# CALAO Systems USB-A9260 (C01 and C02) + +adapter driver ftdi +ftdi device_desc "USB-A9260" +ftdi vid_pid 0x0403 0x6001 0x0403 0x6010 +ftdi layout_init 0x0c08 0x0f1b +ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 +ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 + +transport select jtag + +source [find target/at91sam9260.cfg] diff --git a/tcl/board/calao-usb-a9g20-c01.cfg b/tcl/board/calao-usb-a9g20-c01.cfg new file mode 100644 index 0000000000..d2017864a9 --- /dev/null +++ b/tcl/board/calao-usb-a9g20-c01.cfg @@ -0,0 +1,172 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# CALAO Systems USB-A9G20-C01 +# Authors: Gregory Hermant, Jean-Christophe PLAGNIOL-VILLARD, Wolfram Sang + +adapter driver ftdi +ftdi device_desc "USB-A9G20" +ftdi vid_pid 0x0403 0x6010 +ftdi layout_init 0x0c08 0x0f1b +ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 +ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 + +transport select jtag + +source [find target/at91sam9g20.cfg] +source [find mem_helper.tcl] + +proc at91sam9g20_reset_start { } { + + # Make sure that the jtag is running slow, since there are a number of different ways the board + # can be configured coming into this state that can cause communication problems with the jtag + # adapter. Also since this call can be made following a "reset init" where fast memory accesses + # are enabled, Need to temporarily shut this down so that the RSTC_MR register can be written at slower + # jtag speed without causing GDB keep alive problem. + + arm7_9 fast_memory_access disable + adapter speed 2 ;# Slow-speed oscillator enabled at reset, so run jtag speed slow. + halt 0 ;# Make sure processor is halted, or error will result in following steps. + wait_halt 10000 + # RSTC_MR : enable user reset, MMU may be enabled... use physical address + mww phys 0xfffffd08 0xa5000501 +} + +proc at91sam9g20_reset_init { } { + + # At reset AT91SAM9G20 chip runs on slow clock (32.768 kHz). To shift over to a normal clock requires + # a number of steps that must be carefully performed. The process outline below follows the + # recommended procedure outlined in the AT91SAM9G20 technical manual. + # + # Several key and very important things to keep in mind: + # The SDRAM parts used currently on the Atmel evaluation board are -75 grade parts. This + # means the master clock (MCLK) must be at or below 133 MHz or timing errors will occur. The processor + # core can operate up to 400 MHz and therefore PCLK must be at or below this to function properly. + + mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog. + + # Set oscillator bypass bit (12.00 MHz external oscillator) in CKGR_MOR register. + + mww 0xfffffc20 0x00000002 + + # Set PLLA Register for 798.000 MHz (divider: bypass, multiplier: 132). + # Wait for LOCKA signal in PMC_SR to assert indicating PLLA is stable. + + mww 0xfffffc28 0x20843F02 + while { [expr { [mrw 0xfffffc68] & 0x02 } ] != 2 } { sleep 1 } + + # Set master system clock prescaler divide by 6 and processor clock divide by 2 in PMC_MCKR. + # Wait for MCKRDY signal from PMC_SR to assert. + + mww 0xfffffc30 0x00001300 + while { [expr { [mrw 0xfffffc68] & 0x08 } ] != 8 } { sleep 1 } + + # Now change PMC_MCKR register to select PLLA. + # Wait for MCKRDY signal from PMC_SR to assert. + + mww 0xfffffc30 0x00001302 + while { [expr { [mrw 0xfffffc68] & 0x08 } ] != 8 } { sleep 1 } + + # Processor and master clocks are now operating and stable at maximum frequency possible: + # -> MCLK = 133.000 MHz + # -> PCLK = 400.000 MHz + + # Switch to fast JTAG speed + + adapter speed 9500 + + # Enable faster DCC downloads. + + arm7_9 dcc_downloads enable + arm7_9 fast_memory_access enable + + # To be able to use external SDRAM, several peripheral configuration registers must + # be modified. The first change is made to PIO_ASR to select peripheral functions + # for D15 through D31. The second change is made to the PIO_PDR register to disable + # this for D15 through D31. + + mww 0xfffff870 0xffff0000 + mww 0xfffff804 0xffff0000 + + # The EBI chip select register EBI_CS must be specifically configured to enable the internal SDRAM controller + # using CS1. Additionally we want CS3 assigned to NandFlash. Also VDDIO is connected physically on + # the board to the 1.8V VDC power supply so set the appropriate register bit to notify the micrcontroller. + + mww 0xffffef1c 0x000000a + + # The USB-A9G20 Embedded computer has built-in NandFlash. The exact physical timing characteristics + # for the memory type used on the current board (MT29F2G08AACWP) can be established by setting + # four registers in order: SMC_SETUP3, SMC_PULSE3, SMC_CYCLE3, and SMC_MODE3. + + mww 0xffffec30 0x00020002 + mww 0xffffec34 0x04040404 + mww 0xffffec38 0x00070007 + mww 0xffffec3c 0x00030003 + + # Now setup SDRAM. This is tricky and configuration is very important for reliability! The current calculations + # are based on 2 x Micron LPSDRAM MT48H16M16LFBF-75 memory (4 M x 16 bit x 4 banks). If you use this file as a reference + # for a new board that uses different SDRAM devices or clock rates, you need to recalculate the value inserted + # into the SDRAM_CR register. Using the memory datasheet for the -75 grade part and assuming a master clock + # of 133.000 MHz then the SDCLK period is equal to 7.6 ns. This means the device requires: + # + # CAS latency = 3 cycles + # TXSR = 10 cycles + # TRAS = 6 cycles + # TRCD = 3 cycles + # TRP = 3 cycles + # TRC = 9 cycles + # TWR = 2 cycles + # 9 column, 13 row, 4 banks + # refresh equal to or less then 7.8 us for commercial/industrial rated devices + # + # Thus SDRAM_CR = 0xa6339279 + + mww 0xffffea08 0xa6339279 + + # Memory Device Type: SDRAM (low-power would be 0x1) + mww 0xffffea24 0x00000000 + + # Next issue a 'NOP' command through the SDRAMC_MR register followed by writing a zero value into + # the starting memory location for the SDRAM. + + mww 0xffffea00 0x00000001 + mww 0x20000000 0 + + # Issue an 'All Banks Precharge' command through the SDRAMC_MR register followed by writing a zero + # value into the starting memory location for the SDRAM. + + mww 0xffffea00 0x00000002 + mww 0x20000000 0 + + # Now issue an 'Auto-Refresh' command through the SDRAMC_MR register. Follow this operation by writing + # zero values eight times into the starting memory location for the SDRAM. + + mww 0xffffea00 0x4 + mww 0x20000000 0 + mww 0x20000000 0 + mww 0x20000000 0 + mww 0x20000000 0 + mww 0x20000000 0 + mww 0x20000000 0 + mww 0x20000000 0 + mww 0x20000000 0 + + # Almost done, so next issue a 'Load Mode Register' command followed by a zero value write to the + # the starting memory location for the SDRAM. + + mww 0xffffea00 0x3 + mww 0x20000000 0 + + # Signal normal mode using the SDRAMC_MR register and follow with a zero value write the starting + # memory location for the SDRAM. + + mww 0xffffea00 0x0 + mww 0x20000000 0 + + # Finally set the refresh rate to about every 7 us (7.5 ns x 924 cycles). + + mww 0xffffea04 0x0000039c +} + +$_TARGETNAME configure -event gdb-attach { reset init } +$_TARGETNAME configure -event reset-start {at91sam9g20_reset_start} +$_TARGETNAME configure -event reset-init {at91sam9g20_reset_init} diff --git a/tcl/board/certuspro_evaluation.cfg b/tcl/board/certuspro_evaluation.cfg new file mode 100644 index 0000000000..ba2f17c221 --- /dev/null +++ b/tcl/board/certuspro_evaluation.cfg @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# https://www.latticesemi.com/products/developmentboardsandkits/certuspro-nx-versa-board + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 + +ftdi channel 0 +ftdi layout_init 0x0008 0x008b +reset_config none +transport select jtag +adapter speed 10000 + +source [find fpga/lattice_certuspro.cfg] + +#openocd -f board/certuspro_evaluation.cfg -c "init" -c "pld load certuspro.pld shared_folder/certuspro_blinker_impl_1.bit" + +set JTAGSPI_CHAIN_ID certuspro.pld +source [find cpld/jtagspi.cfg] + +#jtagspi_init certuspro.pld "" -1 +#jtagspi_program shared_folder/certuspro_blinker_impl1.bit 0 diff --git a/tcl/board/colibri.cfg b/tcl/board/colibri.cfg index 0f30afd090..b44985d9d6 100644 --- a/tcl/board/colibri.cfg +++ b/tcl/board/colibri.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Toradex Colibri PXA270 source [find target/pxa270.cfg] reset_config trst_and_srst srst_push_pull diff --git a/tcl/board/crossbow_tech_imote2.cfg b/tcl/board/crossbow_tech_imote2.cfg index 277c353a1b..07ce8c7273 100644 --- a/tcl/board/crossbow_tech_imote2.cfg +++ b/tcl/board/crossbow_tech_imote2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Crossbow Technology iMote2 set CHIPNAME imote2 diff --git a/tcl/board/csb337.cfg b/tcl/board/csb337.cfg index a9d0139298..f75abbe0e8 100644 --- a/tcl/board/csb337.cfg +++ b/tcl/board/csb337.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Cogent CSB337 # http://cogcomp.com/csb_csb337.htm diff --git a/tcl/board/csb732.cfg b/tcl/board/csb732.cfg index 35e397ff22..6df17500c6 100644 --- a/tcl/board/csb732.cfg +++ b/tcl/board/csb732.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # The Cogent CSB732 board has a single i.MX35 chip source [find target/imx35.cfg] diff --git a/tcl/board/da850evm.cfg b/tcl/board/da850evm.cfg index fbec60921d..12de3a7e38 100644 --- a/tcl/board/da850evm.cfg +++ b/tcl/board/da850evm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #DA850 EVM board # http://focus.ti.com/dsp/docs/thirdparty/catalog/devtoolsproductfolder.tsp?actionPerformed=productFolder&productId=5939 # http://www.logicpd.com/products/development-kits/zoom-omap-l138-evm-development-kit diff --git a/tcl/board/digi_connectcore_wi-9c.cfg b/tcl/board/digi_connectcore_wi-9c.cfg index 43ad1c90e0..0ff47428a1 100644 --- a/tcl/board/digi_connectcore_wi-9c.cfg +++ b/tcl/board/digi_connectcore_wi-9c.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: DIGI ConnectCore Wi-9C ###################################### diff --git a/tcl/board/digilent_analog_discovery.cfg b/tcl/board/digilent_analog_discovery.cfg index 64cdacfa89..1bc239b632 100644 --- a/tcl/board/digilent_analog_discovery.cfg +++ b/tcl/board/digilent_analog_discovery.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Digilent Analog Discovery # diff --git a/tcl/board/digilent_atlys.cfg b/tcl/board/digilent_atlys.cfg index 3eb6219fde..568253b986 100644 --- a/tcl/board/digilent_atlys.cfg +++ b/tcl/board/digilent_atlys.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # http://digilentinc.com/atlys/ # # The Digilent Atlys normally requires proprietary tools to program and will diff --git a/tcl/board/digilent_cmod_s7.cfg b/tcl/board/digilent_cmod_s7.cfg new file mode 100644 index 0000000000..c52ee9505b --- /dev/null +++ b/tcl/board/digilent_cmod_s7.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# digilent CMOD S7 +# https://digilent.com/reference/programmable-logic/cmod-s7/reference-manual + + +adapter driver ftdi +ftdi channel 0 +ftdi layout_init 0x0008 0x008b +ftdi vid_pid 0x0403 0x6010 +reset_config none +transport select jtag + +adapter speed 10000 + +source [find cpld/xilinx-xc7.cfg] + +# "ipdbg -start -tap xc7.tap -hub 0x02 -tool 0 -port 5555" +#openocd -f board/digilent_cmod_s7.cfg -c "init" -c "pld load xc7.pld shared_folder/cmod_s7_fast.bit" + +set JTAGSPI_CHAIN_ID xc7.pld +source [find cpld/jtagspi.cfg] + +#jtagspi_init xc7.pld "shared_folder/bscan_spi_xc7s25.bit" 0xab +#jtagspi_program shared_folder/cmod_s7_fast.bit 0 diff --git a/tcl/board/digilent_zedboard.cfg b/tcl/board/digilent_zedboard.cfg index 08d1a612fc..010e8c6f3e 100644 --- a/tcl/board/digilent_zedboard.cfg +++ b/tcl/board/digilent_zedboard.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Digilent Zedboard Rev.C, Rev.D with Xilinx Zynq chip # diff --git a/tcl/board/diolan_lpc4350-db1.cfg b/tcl/board/diolan_lpc4350-db1.cfg index bd48d9ba06..c55621df04 100644 --- a/tcl/board/diolan_lpc4350-db1.cfg +++ b/tcl/board/diolan_lpc4350-db1.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Diolan LPC-4350-DB1 development board # diff --git a/tcl/board/diolan_lpc4357-db1.cfg b/tcl/board/diolan_lpc4357-db1.cfg index d24cfd02c6..155328ad50 100644 --- a/tcl/board/diolan_lpc4357-db1.cfg +++ b/tcl/board/diolan_lpc4357-db1.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Diolan LPC-4357-DB1 development board # diff --git a/tcl/board/dk-tm4c129.cfg b/tcl/board/dk-tm4c129.cfg index 2c7de290de..27bd432ce5 100644 --- a/tcl/board/dk-tm4c129.cfg +++ b/tcl/board/dk-tm4c129.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + echo "WARNING: board/dk-tm4c129.cfg is deprecated, please switch to board/ti_dk-tm4c129.cfg" source [find board/ti_dk-tm4c129.cfg] diff --git a/tcl/board/dm355evm.cfg b/tcl/board/dm355evm.cfg index bf5659cccb..0dbffa8395 100644 --- a/tcl/board/dm355evm.cfg +++ b/tcl/board/dm355evm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # DM355 EVM board # http://focus.ti.com/docs/toolsw/folders/print/tmdsevm355.html # http://c6000.spectrumdigital.com/evmdm355/ diff --git a/tcl/board/dm365evm.cfg b/tcl/board/dm365evm.cfg index 8c7f8c0a60..15db24c204 100644 --- a/tcl/board/dm365evm.cfg +++ b/tcl/board/dm365evm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # DM365 EVM board -- Beta # http://focus.ti.com/docs/toolsw/folders/print/tmdxevm365.html # http://support.spectrumdigital.com/boards/evmdm365 diff --git a/tcl/board/dm6446evm.cfg b/tcl/board/dm6446evm.cfg index 0d2f6a4d26..1236b86228 100644 --- a/tcl/board/dm6446evm.cfg +++ b/tcl/board/dm6446evm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # DM6446 EVM board # http://focus.ti.com/docs/toolsw/folders/print/tmdsevm6446.html # http://c6000.spectrumdigital.com/davincievm/ diff --git a/tcl/board/dp_busblaster_v3.cfg b/tcl/board/dp_busblaster_v3.cfg index b94b43a0b9..55996176fa 100644 --- a/tcl/board/dp_busblaster_v3.cfg +++ b/tcl/board/dp_busblaster_v3.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Dangerous Prototypes - Bus Blaster # diff --git a/tcl/board/dptechnics_dpt-board-v1.cfg b/tcl/board/dptechnics_dpt-board-v1.cfg index 21470b02b1..3ab2c684de 100644 --- a/tcl/board/dptechnics_dpt-board-v1.cfg +++ b/tcl/board/dptechnics_dpt-board-v1.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Product page: # https://www.dptechnics.com/en/products/dpt-board-v1.html # diff --git a/tcl/board/ecp5_evaluation.cfg b/tcl/board/ecp5_evaluation.cfg new file mode 100644 index 0000000000..dd663f79d8 --- /dev/null +++ b/tcl/board/ecp5_evaluation.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Lattice ECP5 evaluation Kit +# https://www.latticesemi.com/view_document?document_id=52479 +# + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 + +ftdi channel 0 +ftdi layout_init 0x0008 0x008b +reset_config none +transport select jtag +adapter speed 6000 + +source [find fpga/lattice_ecp5.cfg] + +#openocd -f board/ecp5_evaluation.cfg -c "init" -c "pld load ecp5.pld shared_folder/ecp5_blinker_impl1.bit" +#ipdbg -start -tap ecp5.tap -hub 0x32 -port 5555 -tool 0 + +set JTAGSPI_CHAIN_ID ecp5.pld +source [find cpld/jtagspi.cfg] + +#jtagspi_init ecp5.pld "" -1 +#jtagspi_program shared_folder/ecp5_blinker_impl1_slow.bit 0 diff --git a/tcl/board/efikamx.cfg b/tcl/board/efikamx.cfg index 007b312beb..90835434a7 100644 --- a/tcl/board/efikamx.cfg +++ b/tcl/board/efikamx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Genesi USA EfikaMX # http://www.genesi-usa.com/products/efika diff --git a/tcl/board/efm32.cfg b/tcl/board/efm32.cfg index adbdda72e5..0ffab04fd4 100644 --- a/tcl/board/efm32.cfg +++ b/tcl/board/efm32.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Configuration for EFM32 boards with on-board SEGGER J-Link # # Tested with Tiny, Giant and Zero Gecko Starter Kit. diff --git a/tcl/board/eir.cfg b/tcl/board/eir.cfg index 67758b81e1..d6342499fb 100644 --- a/tcl/board/eir.cfg +++ b/tcl/board/eir.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Elector Internet Radio board # http://www.ethernut.de/en/hardware/eir/index.html diff --git a/tcl/board/ek-lm3s1968.cfg b/tcl/board/ek-lm3s1968.cfg index bbb04baa61..c794a17a01 100644 --- a/tcl/board/ek-lm3s1968.cfg +++ b/tcl/board/ek-lm3s1968.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI/Luminary Stellaris LM3S1968 Evaluation Kits # diff --git a/tcl/board/ek-lm3s3748.cfg b/tcl/board/ek-lm3s3748.cfg index 36ecfcd321..705cb64ce0 100644 --- a/tcl/board/ek-lm3s3748.cfg +++ b/tcl/board/ek-lm3s3748.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI/Luminary Stellaris lm3s3748 Evaluation Kits # diff --git a/tcl/board/ek-lm3s6965.cfg b/tcl/board/ek-lm3s6965.cfg index c7696690dc..ee4e15f8a8 100644 --- a/tcl/board/ek-lm3s6965.cfg +++ b/tcl/board/ek-lm3s6965.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI/Luminary Stellaris LM3S6965 Evaluation Kits # diff --git a/tcl/board/ek-lm3s811-revb.cfg b/tcl/board/ek-lm3s811-revb.cfg index 8729f1596b..f968eece5f 100644 --- a/tcl/board/ek-lm3s811-revb.cfg +++ b/tcl/board/ek-lm3s811-revb.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI/Luminary Stellaris LM3S811 Evaluation Kits (rev B and earlier) # diff --git a/tcl/board/ek-lm3s811.cfg b/tcl/board/ek-lm3s811.cfg index d7fe243e64..0cf36c2843 100644 --- a/tcl/board/ek-lm3s811.cfg +++ b/tcl/board/ek-lm3s811.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI/Luminary Stellaris LM3S811 Evaluation Kits # diff --git a/tcl/board/ek-lm3s8962.cfg b/tcl/board/ek-lm3s8962.cfg index d02ce449ac..71a1b1090c 100644 --- a/tcl/board/ek-lm3s8962.cfg +++ b/tcl/board/ek-lm3s8962.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI/Luminary Stellaris LM3S8962 Evaluation Kits # diff --git a/tcl/board/ek-lm3s9b9x.cfg b/tcl/board/ek-lm3s9b9x.cfg index 6dd7b31a89..289a2cc091 100644 --- a/tcl/board/ek-lm3s9b9x.cfg +++ b/tcl/board/ek-lm3s9b9x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI/Luminary Stellaris LM3S9B9x Evaluation Kits # diff --git a/tcl/board/ek-lm3s9d92.cfg b/tcl/board/ek-lm3s9d92.cfg index a0253d6462..08bbbdb586 100644 --- a/tcl/board/ek-lm3s9d92.cfg +++ b/tcl/board/ek-lm3s9d92.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI/Luminary Stellaris LM3S9D92 Evaluation Kits # diff --git a/tcl/board/ek-lm4f120xl.cfg b/tcl/board/ek-lm4f120xl.cfg index b2ebfa8cf1..db8b2010ba 100644 --- a/tcl/board/ek-lm4f120xl.cfg +++ b/tcl/board/ek-lm4f120xl.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI Stellaris Launchpad ek-lm4f120xl Evaluation Kits # diff --git a/tcl/board/ek-lm4f232.cfg b/tcl/board/ek-lm4f232.cfg index 2e3fc7ca10..89b2c3ce88 100644 --- a/tcl/board/ek-lm4f232.cfg +++ b/tcl/board/ek-lm4f232.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI Stellaris LM4F232 Evaluation Kits # diff --git a/tcl/board/ek-tm4c123gxl.cfg b/tcl/board/ek-tm4c123gxl.cfg index 3e497ba199..d569e58cd9 100644 --- a/tcl/board/ek-tm4c123gxl.cfg +++ b/tcl/board/ek-tm4c123gxl.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + echo "WARNING: board/ek-tm4c123gxl.cfg is deprecated, please switch to board/ti_ek-tm4c123gxl.cfg" source [find board/ti_ek-tm4c123gxl.cfg] diff --git a/tcl/board/ek-tm4c1294xl.cfg b/tcl/board/ek-tm4c1294xl.cfg index 6763866809..5c1167451e 100644 --- a/tcl/board/ek-tm4c1294xl.cfg +++ b/tcl/board/ek-tm4c1294xl.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + echo "WARNING: board/ek-tm4c1294xl.cfg is deprecated, please switch to board/ti_ek-tm4c1294xl.cfg" source [find board/ti_ek-tm4c1294xl.cfg] diff --git a/tcl/board/embedded-artists_lpc2478-32.cfg b/tcl/board/embedded-artists_lpc2478-32.cfg index a73d83263f..ef61060800 100644 --- a/tcl/board/embedded-artists_lpc2478-32.cfg +++ b/tcl/board/embedded-artists_lpc2478-32.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Embedded Artists eval board for LPC2478 # http://www.embeddedartists.com/ diff --git a/tcl/board/emcraft_imx8m-som-bsb.cfg b/tcl/board/emcraft_imx8m-som-bsb.cfg index 248c0d4000..7b9f7b1cc8 100644 --- a/tcl/board/emcraft_imx8m-som-bsb.cfg +++ b/tcl/board/emcraft_imx8m-som-bsb.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # configuration file for Emcraft IMX8M-SOM-BSB # diff --git a/tcl/board/emcraft_twr-vf6-som-bsb.cfg b/tcl/board/emcraft_twr-vf6-som-bsb.cfg index 3818b6793d..57efa8f96c 100644 --- a/tcl/board/emcraft_twr-vf6-som-bsb.cfg +++ b/tcl/board/emcraft_twr-vf6-som-bsb.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # EmCraft Systems TWR-VF6-SOM-BSB # diff --git a/tcl/board/emcraft_vf6-som.cfg b/tcl/board/emcraft_vf6-som.cfg index 558651683d..0a6f0f88da 100644 --- a/tcl/board/emcraft_vf6-som.cfg +++ b/tcl/board/emcraft_vf6-som.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # EmCraft Systems Vybrid VF6 SOM # diff --git a/tcl/board/esp32-bridge.cfg b/tcl/board/esp32-bridge.cfg new file mode 100644 index 0000000000..17146e59c3 --- /dev/null +++ b/tcl/board/esp32-bridge.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for ESP32 connected via ESP USB Bridge board +# +# For example, OpenOCD can be started for ESP32 debugging on +# +# openocd -f board/esp32-bridge.cfg +# + +# Source the JTAG interface configuration file +source [find interface/esp_usb_bridge.cfg] +# ESP32 chip id defined in the idf esp_chip_model_t +espusbjtag chip_id 1 +# Source the ESP32 configuration file +source [find target/esp32.cfg] diff --git a/tcl/board/esp32-ethernet-kit-3.3v.cfg b/tcl/board/esp32-ethernet-kit-3.3v.cfg new file mode 100644 index 0000000000..3bfe84b3fe --- /dev/null +++ b/tcl/board/esp32-ethernet-kit-3.3v.cfg @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for ESP32-ETHERNET-KIT board. +# +# For example, OpenOCD can be started for ESP32 debugging on +# +# openocd -f board/esp32-ethernet-kit-3.3v.cfg +# + +# Source the JTAG interface configuration file +source [find interface/ftdi/esp32_devkitj_v1.cfg] +set ESP32_FLASH_VOLTAGE 3.3 +# Source the ESP32 configuration file +source [find target/esp32.cfg] + +# The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they +# do not relate to OpenOCD trying to read from a memory range without physical +# memory being present there), you can try lowering this. +# +# On DevKit-J, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz +# if CPU frequency is 160MHz or 240MHz. +adapter speed 20000 diff --git a/tcl/board/esp32-wrover-kit-1.8v.cfg b/tcl/board/esp32-wrover-kit-1.8v.cfg new file mode 100644 index 0000000000..9aa3954551 --- /dev/null +++ b/tcl/board/esp32-wrover-kit-1.8v.cfg @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for ESP32-WROVER-KIT board. +# +# For example, OpenOCD can be started for ESP32 debugging on +# +# openocd -f board/esp32-wrover-kit-1.8v.cfg +# + +# Source the JTAG interface configuration file +source [find interface/ftdi/esp32_devkitj_v1.cfg] +set ESP32_FLASH_VOLTAGE 1.8 +# Source the ESP32 configuration file +source [find target/esp32.cfg] + +# The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they +# do not relate to OpenOCD trying to read from a memory range without physical +# memory being present there), you can try lowering this. +# +# On DevKit-J, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz +# if CPU frequency is 160MHz or 240MHz. +adapter speed 20000 diff --git a/tcl/board/esp32-wrover-kit-3.3v.cfg b/tcl/board/esp32-wrover-kit-3.3v.cfg new file mode 100644 index 0000000000..ce6243600e --- /dev/null +++ b/tcl/board/esp32-wrover-kit-3.3v.cfg @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for ESP32-WROVER-KIT board. +# +# For example, OpenOCD can be started for ESP32 debugging on +# +# openocd -f board/esp32-wrover-kit-3.3v.cfg +# + +# Source the JTAG interface configuration file +source [find interface/ftdi/esp32_devkitj_v1.cfg] +set ESP32_FLASH_VOLTAGE 3.3 +# Source the ESP32 configuration file +source [find target/esp32.cfg] + +# The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they +# do not relate to OpenOCD trying to read from a memory range without physical +# memory being present there), you can try lowering this. +# +# On DevKit-J, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz +# if CPU frequency is 160MHz or 240MHz. +adapter speed 20000 diff --git a/tcl/board/esp32c3-builtin.cfg b/tcl/board/esp32c3-builtin.cfg new file mode 100644 index 0000000000..9e19b1b93c --- /dev/null +++ b/tcl/board/esp32c3-builtin.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for ESP32-C3 connected via builtin USB-JTAG adapter. +# +# For example, OpenOCD can be started for ESP32-C3 debugging on +# +# openocd -f board/esp32c3-builtin.cfg +# + +# Source the JTAG interface configuration file +source [find interface/esp_usb_jtag.cfg] +# Source the ESP32-C3 configuration file +source [find target/esp32c3.cfg] + +adapter speed 40000 diff --git a/tcl/board/esp32c6-builtin.cfg b/tcl/board/esp32c6-builtin.cfg new file mode 100644 index 0000000000..abc96b2d14 --- /dev/null +++ b/tcl/board/esp32c6-builtin.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for ESP32-C6 connected via builtin USB-JTAG adapter. +# +# For example, OpenOCD can be started for ESP32-C6 debugging on +# +# openocd -f board/esp32c6-builtin.cfg +# + +# Source the JTAG interface configuration file +source [find interface/esp_usb_jtag.cfg] +# Source the ESP32-C6 configuration file +source [find target/esp32c6.cfg] + +adapter speed 40000 diff --git a/tcl/board/esp32h2-builtin.cfg b/tcl/board/esp32h2-builtin.cfg new file mode 100644 index 0000000000..1ce596104a --- /dev/null +++ b/tcl/board/esp32h2-builtin.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for ESP32-C3 connected via builtin USB-JTAG adapter. +# +# For example, OpenOCD can be started for ESP32-C3 debugging on +# +# openocd -f board/esp32c3-builtin.cfg +# + +# Source the JTAG interface configuration file +source [find interface/esp_usb_jtag.cfg] +# Source the ESP32-C3 configuration file +source [find target/esp32h2.cfg] + +adapter speed 40000 diff --git a/tcl/board/esp32s2-bridge.cfg b/tcl/board/esp32s2-bridge.cfg new file mode 100644 index 0000000000..b87be8b64c --- /dev/null +++ b/tcl/board/esp32s2-bridge.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for ESP32-S2 connected via ESP USB Bridge board +# +# For example, OpenOCD can be started for ESP32-S2 debugging on +# +# openocd -f board/esp32s2-bridge.cfg +# + +# Source the JTAG interface configuration file +source [find interface/esp_usb_bridge.cfg] +# ESP32S2 chip id defined in the idf esp_chip_model_t +espusbjtag chip_id 2 +# Source the ESP32-S2 configuration file +source [find target/esp32s2.cfg] diff --git a/tcl/board/esp32s2-kaluga-1.cfg b/tcl/board/esp32s2-kaluga-1.cfg new file mode 100644 index 0000000000..783ea214b4 --- /dev/null +++ b/tcl/board/esp32s2-kaluga-1.cfg @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for ESP32-S2 Kaluga board. +# +# For example, OpenOCD can be started for ESP32-S2 debugging on +# +# openocd -f board/esp32s2-kaluga-1.cfg +# + +source [find interface/ftdi/esp32s2_kaluga_v1.cfg] +source [find target/esp32s2.cfg] + +# The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they +# do not relate to OpenOCD trying to read from a memory range without physical +# memory being present there), you can try lowering this. +# On ESP32-S2, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz +# if CPU frequency is 160MHz or 240MHz. +adapter speed 20000 diff --git a/tcl/board/esp32s3-bridge.cfg b/tcl/board/esp32s3-bridge.cfg new file mode 100644 index 0000000000..a42e257c58 --- /dev/null +++ b/tcl/board/esp32s3-bridge.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for ESP32-S3 connected via ESP USB Bridge board +# +# For example, OpenOCD can be started for ESP32-S3 debugging on +# +# openocd -f board/esp32s3-bridge.cfg +# + +# Source the JTAG interface configuration file +source [find interface/esp_usb_bridge.cfg] +# ESP32S3 chip id defined in the idf esp_chip_model_t +espusbjtag chip_id 9 +# Source the ESP32-S3 configuration file +source [find target/esp32s3.cfg] diff --git a/tcl/board/esp32s3-builtin.cfg b/tcl/board/esp32s3-builtin.cfg new file mode 100644 index 0000000000..353099c98f --- /dev/null +++ b/tcl/board/esp32s3-builtin.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for ESP32-S3 connected via builtin USB-JTAG adapter. +# +# For example, OpenOCD can be started for ESP32-S3 debugging on +# +# openocd -f board/esp32s3-builtin.cfg +# + +# Source the JTAG interface configuration file +source [find interface/esp_usb_jtag.cfg] +# Source the ESP32-S3 configuration file +source [find target/esp32s3.cfg] + +adapter speed 40000 diff --git a/tcl/board/esp32s3-ftdi.cfg b/tcl/board/esp32s3-ftdi.cfg new file mode 100644 index 0000000000..60706646d8 --- /dev/null +++ b/tcl/board/esp32s3-ftdi.cfg @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for ESP32-S3 connected via ESP-Prog. +# +# For example, OpenOCD can be started for ESP32-S3 debugging on +# +# openocd -f board/esp32s3-ftdi.cfg +# + +# Source the JTAG interface configuration file +source [find interface/ftdi/esp32_devkitj_v1.cfg] +# Source the ESP32-S3 configuration file +source [find target/esp32s3.cfg] + +# The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they +# do not relate to OpenOCD trying to read from a memory range without physical +# memory being present there), you can try lowering this. +# +# On DevKit-J, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz +# if CPU frequency is 160MHz or 240MHz. +adapter speed 20000 diff --git a/tcl/board/ethernut3.cfg b/tcl/board/ethernut3.cfg index 72fc5ade3f..384db1d232 100644 --- a/tcl/board/ethernut3.cfg +++ b/tcl/board/ethernut3.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Ethernut 3 board configuration file # diff --git a/tcl/board/frdm-kl25z.cfg b/tcl/board/frdm-kl25z.cfg index 89ee32deea..68dc48d494 100644 --- a/tcl/board/frdm-kl25z.cfg +++ b/tcl/board/frdm-kl25z.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an Freescale Freedom eval board with a single MKL25Z128VLK4 chip. # http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=FRDM-KL25Z # diff --git a/tcl/board/frdm-kl46z.cfg b/tcl/board/frdm-kl46z.cfg index eee4d8ead7..3fb7205d7b 100644 --- a/tcl/board/frdm-kl46z.cfg +++ b/tcl/board/frdm-kl46z.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an Freescale Freedom eval board with a single MKL46Z256VLL4 chip. # http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=FRDM-KL46Z # diff --git a/tcl/board/fsl_imx6q_sabresd.cfg b/tcl/board/fsl_imx6q_sabresd.cfg index cf34cd16d5..faeeafb1fd 100644 --- a/tcl/board/fsl_imx6q_sabresd.cfg +++ b/tcl/board/fsl_imx6q_sabresd.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Board configuration file for the Freescale IMX6Q Sabre SD EVM # diff --git a/tcl/board/gatemate_eval.cfg b/tcl/board/gatemate_eval.cfg new file mode 100644 index 0000000000..c4d3f3dfda --- /dev/null +++ b/tcl/board/gatemate_eval.cfg @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# GateMateTM FPGA Evaluation Board +# https://www.colognechip.com/programmable-logic/gatemate-evaluation-board/ +# + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 + +ftdi channel 0 +ftdi layout_init 0x0014 0x011b +reset_config none +transport select jtag +adapter speed 6000 + +source [find fpga/gatemate.cfg] + +set JTAGSPI_CHAIN_ID gatemate.pld +source [find cpld/jtagspi.cfg] + +#jtagspi_init gatemate.pld "" -1 +#jtagspi_program workspace/blink/blink_slow.cfg.bit 0 diff --git a/tcl/board/glyn_tonga2.cfg b/tcl/board/glyn_tonga2.cfg index f48702ca67..d847bec8a8 100644 --- a/tcl/board/glyn_tonga2.cfg +++ b/tcl/board/glyn_tonga2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Glyn Tonga2 SO-DIMM CPU module (Toshiba TMPA900CMXBG, ARM9) # diff --git a/tcl/board/gowin_runber.cfg b/tcl/board/gowin_runber.cfg new file mode 100644 index 0000000000..9496c6f008 --- /dev/null +++ b/tcl/board/gowin_runber.cfg @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Gowin RUNBER FPGA Development Board +# https://www.seeedstudio.com/Gowin-RUNBER-Development-Board-p-4779.html + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 + +ftdi channel 0 +ftdi layout_init 0x0008 0x008b +reset_config none +transport select jtag +adapter speed 6000 + +source [find fpga/gowin_gw1n.cfg] + + +#openocd -f board/gowin_runber.cfg -c "init" -c "pld load 0 impl/pnr/gw1n_blinker.fs" +#ipdbg -start -tap gw1n.tap -hub 0x42 -port 5555 -tool 0 diff --git a/tcl/board/gti/espressobin.cfg b/tcl/board/gti/espressobin.cfg index 20d0452fd3..d1492dfd8b 100644 --- a/tcl/board/gti/espressobin.cfg +++ b/tcl/board/gti/espressobin.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # config for ESPRESSObin from # Globalscale Technologies Inc. diff --git a/tcl/board/gumstix-aerocore.cfg b/tcl/board/gumstix-aerocore.cfg index 565df4cf88..ddadc88c0b 100644 --- a/tcl/board/gumstix-aerocore.cfg +++ b/tcl/board/gumstix-aerocore.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # JTAG for the STM32F4x chip used on the Gumstix AeroCore is available on # the first interface of a Quad FTDI chip. nTRST is bit 4. adapter driver ftdi diff --git a/tcl/board/hammer.cfg b/tcl/board/hammer.cfg index ea3da81230..79d58ae19e 100644 --- a/tcl/board/hammer.cfg +++ b/tcl/board/hammer.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Target Configuration for the TinCanTools S3C2410 Based Hammer Module # http://www.tincantools.com diff --git a/tcl/board/hilscher_nxdb500sys.cfg b/tcl/board/hilscher_nxdb500sys.cfg index 20fa3ea033..68e1cdaf25 100644 --- a/tcl/board/hilscher_nxdb500sys.cfg +++ b/tcl/board/hilscher_nxdb500sys.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ diff --git a/tcl/board/hilscher_nxeb500hmi.cfg b/tcl/board/hilscher_nxeb500hmi.cfg index a51fa03bcf..a81436584c 100644 --- a/tcl/board/hilscher_nxeb500hmi.cfg +++ b/tcl/board/hilscher_nxeb500hmi.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ diff --git a/tcl/board/hilscher_nxhx10.cfg b/tcl/board/hilscher_nxhx10.cfg index 6e2eba79eb..e116a6cc32 100644 --- a/tcl/board/hilscher_nxhx10.cfg +++ b/tcl/board/hilscher_nxhx10.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ diff --git a/tcl/board/hilscher_nxhx50.cfg b/tcl/board/hilscher_nxhx50.cfg index 0867f2ed6a..8aef6ca382 100644 --- a/tcl/board/hilscher_nxhx50.cfg +++ b/tcl/board/hilscher_nxhx50.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ diff --git a/tcl/board/hilscher_nxhx500.cfg b/tcl/board/hilscher_nxhx500.cfg index 2ba030ec10..9ddf65790c 100644 --- a/tcl/board/hilscher_nxhx500.cfg +++ b/tcl/board/hilscher_nxhx500.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ diff --git a/tcl/board/hilscher_nxsb100.cfg b/tcl/board/hilscher_nxsb100.cfg index c332beec0f..b59ea177a7 100644 --- a/tcl/board/hilscher_nxsb100.cfg +++ b/tcl/board/hilscher_nxsb100.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ diff --git a/tcl/board/hitex_lpc1768stick.cfg b/tcl/board/hitex_lpc1768stick.cfg index ac176cad7b..52cf370c97 100644 --- a/tcl/board/hitex_lpc1768stick.cfg +++ b/tcl/board/hitex_lpc1768stick.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Hitex LPC1768 Stick # # http://www.hitex.com/?id=1602 diff --git a/tcl/board/hitex_lpc2929.cfg b/tcl/board/hitex_lpc2929.cfg index 8268306695..35007c0655 100644 --- a/tcl/board/hitex_lpc2929.cfg +++ b/tcl/board/hitex_lpc2929.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Hitex eval board for LPC2929/LPC2939 # http://www.hitex.com/ diff --git a/tcl/board/hitex_stm32-performancestick.cfg b/tcl/board/hitex_stm32-performancestick.cfg index 74dc5839a7..bab59648d9 100644 --- a/tcl/board/hitex_stm32-performancestick.cfg +++ b/tcl/board/hitex_stm32-performancestick.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Hitex stm32 performance stick reset_config trst_and_srst diff --git a/tcl/board/hitex_str9-comstick.cfg b/tcl/board/hitex_str9-comstick.cfg index 3b9225213d..a508046900 100644 --- a/tcl/board/hitex_str9-comstick.cfg +++ b/tcl/board/hitex_str9-comstick.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Hitex STR9-comStick # http://www.hitex.com/index.php?id=383 # This works for the STR9-comStick revisions STR912CS-A1 and STR912CS-A2. diff --git a/tcl/board/iar_lpc1768.cfg b/tcl/board/iar_lpc1768.cfg index 38ffc3582a..d8d669e989 100644 --- a/tcl/board/iar_lpc1768.cfg +++ b/tcl/board/iar_lpc1768.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Board from IAR KickStart Kit for LPC1768 # See www.iar.com and also # http://www.olimex.com/dev/lpc-1766stk.html diff --git a/tcl/board/iar_str912_sk.cfg b/tcl/board/iar_str912_sk.cfg index 54f517b738..d94c0ce5b8 100644 --- a/tcl/board/iar_str912_sk.cfg +++ b/tcl/board/iar_str912_sk.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # The IAR str912-sk evaluation kick start board has an str912 source [find target/str912.cfg] diff --git a/tcl/board/icnova_imx53_sodimm.cfg b/tcl/board/icnova_imx53_sodimm.cfg index 363d7b4f3f..c4e8bdec0b 100644 --- a/tcl/board/icnova_imx53_sodimm.cfg +++ b/tcl/board/icnova_imx53_sodimm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################################# # Author: Benjamin Tietz <benjamin.tietz@in-circuit.de> ;# # based on work from: Wjatscheslaw Stoljarski (Slawa) <wjatscheslaw.stoljarski@kiwigrid.com> ;# diff --git a/tcl/board/icnova_sam9g45_sodimm.cfg b/tcl/board/icnova_sam9g45_sodimm.cfg index 91e0107c25..7efa8c2b52 100644 --- a/tcl/board/icnova_sam9g45_sodimm.cfg +++ b/tcl/board/icnova_sam9g45_sodimm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################################# # # # Author: Lars Poeschel (larsi@wh2.tu-dresden.de) # diff --git a/tcl/board/imx27ads.cfg b/tcl/board/imx27ads.cfg index e705b1e166..79d3c51359 100644 --- a/tcl/board/imx27ads.cfg +++ b/tcl/board/imx27ads.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # The IMX27 ADS eval board has a single IMX27 chip # Note: tested on IMX27ADS Board REV-2.6 and REV-2.8 source [find target/imx27.cfg] diff --git a/tcl/board/imx27lnst.cfg b/tcl/board/imx27lnst.cfg index ac5a9f3e6b..24f6ed8b2e 100644 --- a/tcl/board/imx27lnst.cfg +++ b/tcl/board/imx27lnst.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # The Linuxstamp-mx27 is board has a single IMX27 chip # For further info see http://opencircuits.com/Linuxstamp_mx27#OpenOCD source [find target/imx27.cfg] diff --git a/tcl/board/imx28evk.cfg b/tcl/board/imx28evk.cfg index a85c2ca678..cc13c51854 100644 --- a/tcl/board/imx28evk.cfg +++ b/tcl/board/imx28evk.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # The IMX28EVK eval board has a IMX28 chip # Tested on SCH-26241 Rev D board with Olimex ARM-USB-OCD # Date: 201-02-01 diff --git a/tcl/board/imx31pdk.cfg b/tcl/board/imx31pdk.cfg index 6c196543cd..65fa520e45 100644 --- a/tcl/board/imx31pdk.cfg +++ b/tcl/board/imx31pdk.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # The IMX31PDK eval board has a single IMX31 chip source [find target/imx31.cfg] source [find target/imx.cfg] diff --git a/tcl/board/imx35pdk.cfg b/tcl/board/imx35pdk.cfg index 2a7efaba7e..41206c68b6 100644 --- a/tcl/board/imx35pdk.cfg +++ b/tcl/board/imx35pdk.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # The IMX35PDK eval board has a single IMX35 chip source [find target/imx35.cfg] source [find target/imx.cfg] diff --git a/tcl/board/imx53-m53evk.cfg b/tcl/board/imx53-m53evk.cfg index 04f0f9f154..6f9210a261 100644 --- a/tcl/board/imx53-m53evk.cfg +++ b/tcl/board/imx53-m53evk.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ####################################### # DENX M53EVK # # http://www.denx-cs.de/?q=M53EVK # diff --git a/tcl/board/imx53loco.cfg b/tcl/board/imx53loco.cfg index c4d45f0e32..fcc2f4dda0 100644 --- a/tcl/board/imx53loco.cfg +++ b/tcl/board/imx53loco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################## # Author: Wjatscheslaw Stoljarski (Slawa) <wjatscheslaw.stoljarski@kiwigrid.com> # # Kiwigrid GmbH # diff --git a/tcl/board/imx8mp-evk.cfg b/tcl/board/imx8mp-evk.cfg index 97a303ac7f..898f3b747f 100644 --- a/tcl/board/imx8mp-evk.cfg +++ b/tcl/board/imx8mp-evk.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # configuration file for NXP MC-IMX8MP-EVK # diff --git a/tcl/board/insignal_arndale.cfg b/tcl/board/insignal_arndale.cfg index 09a7223f08..c7c28b3dcc 100644 --- a/tcl/board/insignal_arndale.cfg +++ b/tcl/board/insignal_arndale.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # InSignal Arndale board # diff --git a/tcl/board/kasli.cfg b/tcl/board/kasli.cfg index 7cfdcf20e9..d85e1ca152 100644 --- a/tcl/board/kasli.cfg +++ b/tcl/board/kasli.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + adapter driver ftdi ftdi device_desc "Quad RS232-HS" ftdi vid_pid 0x0403 0x6011 diff --git a/tcl/board/kc100.cfg b/tcl/board/kc100.cfg index 1d383bef5f..2fd6965a5f 100644 --- a/tcl/board/kc100.cfg +++ b/tcl/board/kc100.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Knovative KC-100 cable modem # TNETC4401PYP, 208-QFP U3 diff --git a/tcl/board/kc705.cfg b/tcl/board/kc705.cfg index 51ea14d461..fad9fff4df 100644 --- a/tcl/board/kc705.cfg +++ b/tcl/board/kc705.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # http://www.xilinx.com/products/boards-and-kits/ek-k7-kc705-g.html source [find interface/ftdi/digilent-hs1.cfg] diff --git a/tcl/board/kcu105.cfg b/tcl/board/kcu105.cfg index e2b68ca758..1510a06160 100644 --- a/tcl/board/kcu105.cfg +++ b/tcl/board/kcu105.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # xilinx ultrascale # http://www.xilinx.com/support/documentation/user_guides/ug570-ultrascale-configuration.pdf diff --git a/tcl/board/keil_mcb1700.cfg b/tcl/board/keil_mcb1700.cfg index 05f12dfba2..6efbd63525 100644 --- a/tcl/board/keil_mcb1700.cfg +++ b/tcl/board/keil_mcb1700.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Keil MCB1700 eval board # diff --git a/tcl/board/keil_mcb2140.cfg b/tcl/board/keil_mcb2140.cfg index bb41a2ab55..bb1d10bd0a 100644 --- a/tcl/board/keil_mcb2140.cfg +++ b/tcl/board/keil_mcb2140.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Keil MCB2140 eval board # diff --git a/tcl/board/kindle2.cfg b/tcl/board/kindle2.cfg index 71dca741c9..8c032cb3af 100644 --- a/tcl/board/kindle2.cfg +++ b/tcl/board/kindle2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Board configuration file for Amazon Kindle Model No. D00701 and D00801 # AKA Kindle 2nd generation and Kindle DX # using a Freescale MCIMX31LDVKN5D i.MX31 processor diff --git a/tcl/board/kontron_sl28.cfg b/tcl/board/kontron_sl28.cfg new file mode 100644 index 0000000000..9816f3802a --- /dev/null +++ b/tcl/board/kontron_sl28.cfg @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Kontron SMARC-sAL28 + +transport select jtag +reset_config srst_only srst_nogate + +jtag newtap unknown0 tap -irlen 12 + +set _CPUS 2 +source [find target/ls1028a.cfg] + +source [find tcl/cpld/altera-epm240.cfg] + +adapter speed 2000 diff --git a/tcl/board/kwikstik.cfg b/tcl/board/kwikstik.cfg index f936d6e92a..ade0c913b2 100644 --- a/tcl/board/kwikstik.cfg +++ b/tcl/board/kwikstik.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Freescale KwikStik development board # diff --git a/tcl/board/la_fonera-fon2200.cfg b/tcl/board/la_fonera-fon2200.cfg index f46b04200a..b0b2966af3 100644 --- a/tcl/board/la_fonera-fon2200.cfg +++ b/tcl/board/la_fonera-fon2200.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/atheros_ar2315.cfg] reset_config trst_and_srst diff --git a/tcl/board/lemaker_hikey.cfg b/tcl/board/lemaker_hikey.cfg index 325b6fdda0..fc044359c1 100644 --- a/tcl/board/lemaker_hikey.cfg +++ b/tcl/board/lemaker_hikey.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # board configuration for LeMaker Hikey # diff --git a/tcl/board/linksys-wag200g.cfg b/tcl/board/linksys-wag200g.cfg index aa4887f948..26900a7d7a 100644 --- a/tcl/board/linksys-wag200g.cfg +++ b/tcl/board/linksys-wag200g.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Linksys WAG200G Router # diff --git a/tcl/board/linksys-wrt54gl.cfg b/tcl/board/linksys-wrt54gl.cfg index ffe53ffbb3..58dfec398d 100644 --- a/tcl/board/linksys-wrt54gl.cfg +++ b/tcl/board/linksys-wrt54gl.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Linksys WRT54GL v1.1 # diff --git a/tcl/board/linksys_nslu2.cfg b/tcl/board/linksys_nslu2.cfg index 0b0f58b845..536f97e236 100644 --- a/tcl/board/linksys_nslu2.cfg +++ b/tcl/board/linksys_nslu2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is for the LinkSys (CISCO) NSLU2 board # It is an Intel XSCALE IXP420 CPU. diff --git a/tcl/board/lisa-l.cfg b/tcl/board/lisa-l.cfg index 73f51a26da..1607fb8621 100644 --- a/tcl/board/lisa-l.cfg +++ b/tcl/board/lisa-l.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # the Lost Illusions Serendipitous Autopilot # http://paparazzi.enac.fr/wiki/Lisa diff --git a/tcl/board/logicpd_imx27.cfg b/tcl/board/logicpd_imx27.cfg index da0b46223d..8365d4fdb1 100644 --- a/tcl/board/logicpd_imx27.cfg +++ b/tcl/board/logicpd_imx27.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # The LogicPD Eval IMX27 eval board has a single IMX27 chip source [find target/imx27.cfg] diff --git a/tcl/board/lpc1850_spifi_generic.cfg b/tcl/board/lpc1850_spifi_generic.cfg index bff4af6050..167b624b50 100644 --- a/tcl/board/lpc1850_spifi_generic.cfg +++ b/tcl/board/lpc1850_spifi_generic.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Generic LPC1850 board w/ SPIFI flash. # This config file is intended as an example of how to diff --git a/tcl/board/lpc4350_spifi_generic.cfg b/tcl/board/lpc4350_spifi_generic.cfg index b363f1eff8..8a017ec7da 100644 --- a/tcl/board/lpc4350_spifi_generic.cfg +++ b/tcl/board/lpc4350_spifi_generic.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Generic LPC4350 board w/ SPIFI flash. # This config file is intended as an example of how to diff --git a/tcl/board/lubbock.cfg b/tcl/board/lubbock.cfg index d803e6fb24..e4de385a4f 100644 --- a/tcl/board/lubbock.cfg +++ b/tcl/board/lubbock.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Intel "Lubbock" Development Board with PXA255 (dbpxa255) # Obsolete; this was Intel's original PXA255 development system # Board also had CPU cards for SA1100, PXA210, PXA250, and more. diff --git a/tcl/board/marsohod.cfg b/tcl/board/marsohod.cfg index b1393a914d..2be8391af8 100644 --- a/tcl/board/marsohod.cfg +++ b/tcl/board/marsohod.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Marsohod CPLD Development and Education board # diff --git a/tcl/board/marsohod2.cfg b/tcl/board/marsohod2.cfg index 31819a2f95..9575100541 100644 --- a/tcl/board/marsohod2.cfg +++ b/tcl/board/marsohod2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Marsohod2 FPGA Development and Education board # diff --git a/tcl/board/marsohod3.cfg b/tcl/board/marsohod3.cfg index fa00706d35..b4f2d30177 100644 --- a/tcl/board/marsohod3.cfg +++ b/tcl/board/marsohod3.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Marsohod3 FPGA Development and Education board # diff --git a/tcl/board/mbed-lpc11u24.cfg b/tcl/board/mbed-lpc11u24.cfg index b1ec2a5194..9f5be884cd 100644 --- a/tcl/board/mbed-lpc11u24.cfg +++ b/tcl/board/mbed-lpc11u24.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an mbed eval board with a single NXP LPC11U24 chip. # http://mbed.org/handbook/mbed-NXP-LPC11U24 # diff --git a/tcl/board/mbed-lpc1768.cfg b/tcl/board/mbed-lpc1768.cfg index 67f834011d..62b0911b71 100644 --- a/tcl/board/mbed-lpc1768.cfg +++ b/tcl/board/mbed-lpc1768.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an mbed eval board with a single NXP LPC1768 chip. # http://mbed.org/handbook/mbed-NXP-LPC1768 # diff --git a/tcl/board/mcb1700.cfg b/tcl/board/mcb1700.cfg index a5e19024a9..8ab6e88c2b 100644 --- a/tcl/board/mcb1700.cfg +++ b/tcl/board/mcb1700.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Keil MCB1700 PCB with 1768 # # Reset init script sets it to 100MHz diff --git a/tcl/board/microchip_explorer16.cfg b/tcl/board/microchip_explorer16.cfg index 7c036c665c..6b528d62a7 100644 --- a/tcl/board/microchip_explorer16.cfg +++ b/tcl/board/microchip_explorer16.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Microchip Explorer 16 with PIC32MX360F512L PIM module. # http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en024858 diff --git a/tcl/board/microchip_same54_xplained_pro.cfg b/tcl/board/microchip_same54_xplained_pro.cfg index 7482de47fe..3588165987 100644 --- a/tcl/board/microchip_same54_xplained_pro.cfg +++ b/tcl/board/microchip_same54_xplained_pro.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Microchip (former Atmel) SAM E54 Xplained Pro evaluation kit. # http://www.microchip.com/developmenttools/productdetails.aspx?partno=atsame54-xpro diff --git a/tcl/board/microchip_saml11_xplained_pro.cfg b/tcl/board/microchip_saml11_xplained_pro.cfg index 2ab61118f3..c2fcd65e0b 100644 --- a/tcl/board/microchip_saml11_xplained_pro.cfg +++ b/tcl/board/microchip_saml11_xplained_pro.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Microchip (formerly Atmel) SAM L11 Xplained Pro Evaluation Kit. # https://www.microchip.com/DevelopmentTools/ProductDetails/dm320205 diff --git a/tcl/board/mini2440.cfg b/tcl/board/mini2440.cfg index 3d01b38a27..85d9a35b9a 100644 --- a/tcl/board/mini2440.cfg +++ b/tcl/board/mini2440.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #------------------------------------------------------------------------- # Mini2440 Samsung s3c2440A Processor with 64MB DRAM, 64MB NAND, 2 MB N0R # NOTE: Configured for NAND boot (switch S2 in NANDBOOT) @@ -121,7 +123,6 @@ reset_config trst_and_srst #------------------------------------------------------------------------- adapter speed 12000 - jtag interface #------------------------------------------------------------------------- # GDB Setup diff --git a/tcl/board/mini6410.cfg b/tcl/board/mini6410.cfg index 2cee939357..18f9e8d25a 100644 --- a/tcl/board/mini6410.cfg +++ b/tcl/board/mini6410.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Target configuration for the Samsung s3c6410 system on chip # Tested on a tiny6410 # Processor : ARM1176 diff --git a/tcl/board/minispartan6.cfg b/tcl/board/minispartan6.cfg index 3de9e99d4b..011cc542c1 100644 --- a/tcl/board/minispartan6.cfg +++ b/tcl/board/minispartan6.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # https://www.scarabhardware.com/minispartan6/ source [find interface/ftdi/minispartan6.cfg] diff --git a/tcl/board/nds32_xc5.cfg b/tcl/board/nds32_xc5.cfg deleted file mode 100644 index 7d86996bd0..0000000000 --- a/tcl/board/nds32_xc5.cfg +++ /dev/null @@ -1,5 +0,0 @@ -set _CPUTAPID 0x1000063d -set _CHIPNAME nds32 -source [find target/nds32v3.cfg] - -jtag init diff --git a/tcl/board/netgear-dg834v3.cfg b/tcl/board/netgear-dg834v3.cfg index 48d23daf9f..a9938889c6 100644 --- a/tcl/board/netgear-dg834v3.cfg +++ b/tcl/board/netgear-dg834v3.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Netgear DG834v3 Router # Internal 4Kb RAM (@0x80000000) diff --git a/tcl/board/netgear-wg102.cfg b/tcl/board/netgear-wg102.cfg index 232d2e4230..15f9c118af 100644 --- a/tcl/board/netgear-wg102.cfg +++ b/tcl/board/netgear-wg102.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/atheros_ar2313.cfg] reset_config trst_and_srst diff --git a/tcl/board/nordic_nrf51822_mkit.cfg b/tcl/board/nordic_nrf51822_mkit.cfg index aa6161f5d6..266d710704 100644 --- a/tcl/board/nordic_nrf51822_mkit.cfg +++ b/tcl/board/nordic_nrf51822_mkit.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Nordic Semiconductor PCA10024 board (aka nRF51822-mKIT) # diff --git a/tcl/board/nordic_nrf51_dk.cfg b/tcl/board/nordic_nrf51_dk.cfg index 96f5471a5f..7ddae2d438 100644 --- a/tcl/board/nordic_nrf51_dk.cfg +++ b/tcl/board/nordic_nrf51_dk.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Nordic Semiconductor NRF51 Development Kit (nRF6824) # diff --git a/tcl/board/nordic_nrf52_dk.cfg b/tcl/board/nordic_nrf52_dk.cfg index 9f528669cb..7366bf94af 100644 --- a/tcl/board/nordic_nrf52_dk.cfg +++ b/tcl/board/nordic_nrf52_dk.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Nordic Semiconductor NRF52 Development Kit (nRF52832) # diff --git a/tcl/board/nordic_nrf52_ftx232.cfg b/tcl/board/nordic_nrf52_ftx232.cfg index 938efedae3..c3c69a89a5 100644 --- a/tcl/board/nordic_nrf52_ftx232.cfg +++ b/tcl/board/nordic_nrf52_ftx232.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # nordic module NRF52 (nRF52832/52840) attached to an adafruit ft232h module # or any FT232H/FT2232H/FT4232H based board/module diff --git a/tcl/board/novena-internal-fpga.cfg b/tcl/board/novena-internal-fpga.cfg index 780586223d..c36938c35a 100644 --- a/tcl/board/novena-internal-fpga.cfg +++ b/tcl/board/novena-internal-fpga.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Novena open hardware and F/OSS-friendly computing platform # diff --git a/tcl/board/numato_mimas_a7.cfg b/tcl/board/numato_mimas_a7.cfg index 12df8913dc..82d6a561b2 100644 --- a/tcl/board/numato_mimas_a7.cfg +++ b/tcl/board/numato_mimas_a7.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Numato Mimas A7 - Artix 7 FPGA Board # diff --git a/tcl/board/numato_opsis.cfg b/tcl/board/numato_opsis.cfg index e54a4eca81..ea07ff3e91 100644 --- a/tcl/board/numato_opsis.cfg +++ b/tcl/board/numato_opsis.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # http://opsis.hdmi2usb.tv # # The Numato Opsis is an FPGA based, open video platform. diff --git a/tcl/board/nxp_frdm-ls1012a.cfg b/tcl/board/nxp_frdm-ls1012a.cfg index 3973b3cdfd..17a50c9a6a 100644 --- a/tcl/board/nxp_frdm-ls1012a.cfg +++ b/tcl/board/nxp_frdm-ls1012a.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # NXP FRDM-LS1012A (Freedom) # diff --git a/tcl/board/nxp_imx7sabre.cfg b/tcl/board/nxp_imx7sabre.cfg index 789fc5b629..9b0c743aff 100644 --- a/tcl/board/nxp_imx7sabre.cfg +++ b/tcl/board/nxp_imx7sabre.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP IMX7SABRE board # use on-board JTAG header transport select jtag diff --git a/tcl/board/nxp_lpc-link2.cfg b/tcl/board/nxp_lpc-link2.cfg index 593fa599a5..52f13fa80c 100644 --- a/tcl/board/nxp_lpc-link2.cfg +++ b/tcl/board/nxp_lpc-link2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # NXP LPC-Link2 # diff --git a/tcl/board/nxp_mcimx8m-evk.cfg b/tcl/board/nxp_mcimx8m-evk.cfg index dd9bd53ac6..bcd0f67c25 100644 --- a/tcl/board/nxp_mcimx8m-evk.cfg +++ b/tcl/board/nxp_mcimx8m-evk.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # configuration file for NXP MC-IMX8M-EVK # diff --git a/tcl/board/olimex_LPC2378STK.cfg b/tcl/board/olimex_LPC2378STK.cfg index 7e9e58e708..23588aea81 100644 --- a/tcl/board/olimex_LPC2378STK.cfg +++ b/tcl/board/olimex_LPC2378STK.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ##################################################### # Olimex LPC2378STK eval board # diff --git a/tcl/board/olimex_lpc_h2148.cfg b/tcl/board/olimex_lpc_h2148.cfg index d8fb5bef91..96ae40516e 100644 --- a/tcl/board/olimex_lpc_h2148.cfg +++ b/tcl/board/olimex_lpc_h2148.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Olimex LPC-H2148 eval board # diff --git a/tcl/board/olimex_sam7_ex256.cfg b/tcl/board/olimex_sam7_ex256.cfg index 08ed4c17ef..9924f2748e 100644 --- a/tcl/board/olimex_sam7_ex256.cfg +++ b/tcl/board/olimex_sam7_ex256.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Olimex SAM7-EX256 has a single Atmel at91sam7ex256 on it. source [find target/at91sam7x256.cfg] diff --git a/tcl/board/olimex_sam7_la2.cfg b/tcl/board/olimex_sam7_la2.cfg index 038fe67b6d..d91432b1a2 100644 --- a/tcl/board/olimex_sam7_la2.cfg +++ b/tcl/board/olimex_sam7_la2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/at91sam7a2.cfg] # delays needed to get stable reads of cpu state diff --git a/tcl/board/olimex_sam9_l9260.cfg b/tcl/board/olimex_sam9_l9260.cfg index 72dce87b1c..7491a0ed52 100644 --- a/tcl/board/olimex_sam9_l9260.cfg +++ b/tcl/board/olimex_sam9_l9260.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################ # Olimex SAM9-L9260 Development Board # diff --git a/tcl/board/olimex_stm32_h103.cfg b/tcl/board/olimex_stm32_h103.cfg index ec03034c10..92ca7ae589 100644 --- a/tcl/board/olimex_stm32_h103.cfg +++ b/tcl/board/olimex_stm32_h103.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Olimex STM32-H103 eval board # http://olimex.com/dev/stm32-h103.html diff --git a/tcl/board/olimex_stm32_h107.cfg b/tcl/board/olimex_stm32_h107.cfg index e54fb4e707..c199cdcf42 100644 --- a/tcl/board/olimex_stm32_h107.cfg +++ b/tcl/board/olimex_stm32_h107.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Olimex STM32-H107 # diff --git a/tcl/board/olimex_stm32_p107.cfg b/tcl/board/olimex_stm32_p107.cfg index 98c72a6e7e..9511030b76 100644 --- a/tcl/board/olimex_stm32_p107.cfg +++ b/tcl/board/olimex_stm32_p107.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Olimex STM32-P107 # diff --git a/tcl/board/omap2420_h4.cfg b/tcl/board/omap2420_h4.cfg index d789e25313..ec169654fa 100644 --- a/tcl/board/omap2420_h4.cfg +++ b/tcl/board/omap2420_h4.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # OMAP2420 SDP board ("H4") source [find target/omap2420.cfg] diff --git a/tcl/board/openrd.cfg b/tcl/board/openrd.cfg index fda01d1291..f6c8317700 100644 --- a/tcl/board/openrd.cfg +++ b/tcl/board/openrd.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Marvell OpenRD source [find interface/ftdi/openrd.cfg] diff --git a/tcl/board/or1k_generic.cfg b/tcl/board/or1k_generic.cfg index 7c19565632..915a0de249 100644 --- a/tcl/board/or1k_generic.cfg +++ b/tcl/board/or1k_generic.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # If you want to use the VJTAG TAP or the XILINX BSCAN, # you must set your FPGA TAP ID here diff --git a/tcl/board/osk5912.cfg b/tcl/board/osk5912.cfg index f4378f8cfe..0759a27ac0 100644 --- a/tcl/board/osk5912.cfg +++ b/tcl/board/osk5912.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # http://omap.spectrumdigital.com/osk5912/ source [find target/omap5912.cfg] diff --git a/tcl/board/phone_se_j100i.cfg b/tcl/board/phone_se_j100i.cfg index ec61425ac2..70387ee154 100644 --- a/tcl/board/phone_se_j100i.cfg +++ b/tcl/board/phone_se_j100i.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Sony Ericsson J100I Phone # diff --git a/tcl/board/phytec_lpc3250.cfg b/tcl/board/phytec_lpc3250.cfg index cee28cdd26..036b16f2bb 100644 --- a/tcl/board/phytec_lpc3250.cfg +++ b/tcl/board/phytec_lpc3250.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/lpc3250.cfg] adapter srst delay 200 diff --git a/tcl/board/pic-p32mx.cfg b/tcl/board/pic-p32mx.cfg index 661e3d63f4..0703220ab2 100644 --- a/tcl/board/pic-p32mx.cfg +++ b/tcl/board/pic-p32mx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # The Olimex PIC-P32MX has a PIC32MX set CPUTAPID 0x40916053 diff --git a/tcl/board/pipistrello.cfg b/tcl/board/pipistrello.cfg index 87193b4a1e..17584a0bda 100644 --- a/tcl/board/pipistrello.cfg +++ b/tcl/board/pipistrello.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # http://pipistrello.saanlima.com/ source [find interface/ftdi/pipistrello.cfg] diff --git a/tcl/board/propox_mmnet1001.cfg b/tcl/board/propox_mmnet1001.cfg index 39ae5cbc1e..0e126044f5 100644 --- a/tcl/board/propox_mmnet1001.cfg +++ b/tcl/board/propox_mmnet1001.cfg @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later ## Chip: set CHIPNAME at91sam9260 diff --git a/tcl/board/pxa255_sst.cfg b/tcl/board/pxa255_sst.cfg index 2b44a05411..8d00dfe6a4 100644 --- a/tcl/board/pxa255_sst.cfg +++ b/tcl/board/pxa255_sst.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # A PXA255 test board with SST 39LF400A flash # # At reset the memory map is as follows. Note that diff --git a/tcl/board/quark_d2000_refboard.cfg b/tcl/board/quark_d2000_refboard.cfg index a89895d89b..3af5735a8b 100644 --- a/tcl/board/quark_d2000_refboard.cfg +++ b/tcl/board/quark_d2000_refboard.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Intel Quark microcontroller D2000 Reference Board (web search for doc num 333582) # the board has an onboard FTDI FT232H chip diff --git a/tcl/board/quark_x10xx_board.cfg b/tcl/board/quark_x10xx_board.cfg index 4ecf30ed8b..aa6adaf526 100644 --- a/tcl/board/quark_x10xx_board.cfg +++ b/tcl/board/quark_x10xx_board.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # There are many Quark boards that can host the quark_x10xx SoC # Galileo is an example board diff --git a/tcl/board/redbee.cfg b/tcl/board/redbee.cfg index 046e7a478b..714dfdc84b 100644 --- a/tcl/board/redbee.cfg +++ b/tcl/board/redbee.cfg @@ -1 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/mc13224v.cfg] diff --git a/tcl/board/reflexces_achilles_i-dev_kit_arria10.cfg b/tcl/board/reflexces_achilles_i-dev_kit_arria10.cfg index c9f8d36959..2d98cc5d19 100644 --- a/tcl/board/reflexces_achilles_i-dev_kit_arria10.cfg +++ b/tcl/board/reflexces_achilles_i-dev_kit_arria10.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Achilles Instant-Development Kit Arria 10 SoC SoM # https://www.reflexces.com/products-solutions/achilles-instant-development-kit-arria-10-soc-som # diff --git a/tcl/board/renesas_dk-s7g2.cfg b/tcl/board/renesas_dk-s7g2.cfg index 3f29ec3ae9..e310112822 100644 --- a/tcl/board/renesas_dk-s7g2.cfg +++ b/tcl/board/renesas_dk-s7g2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Renesas Synergy DK-S7G2 # diff --git a/tcl/board/renesas_gr_peach.cfg b/tcl/board/renesas_gr_peach.cfg index ee6efe02b9..b3823ca25b 100644 --- a/tcl/board/renesas_gr_peach.cfg +++ b/tcl/board/renesas_gr_peach.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Renesas RZ/A1H GR-Peach board reset_config srst_only diff --git a/tcl/board/renesas_porter.cfg b/tcl/board/renesas_porter.cfg index 7f23fb63c2..134e9ba96e 100644 --- a/tcl/board/renesas_porter.cfg +++ b/tcl/board/renesas_porter.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Renesas R-Car M2 Evaluation Board set SOC M2 diff --git a/tcl/board/renesas_salvator-xs.cfg b/tcl/board/renesas_salvator-xs.cfg index 6d3096ec1a..1323c13e71 100644 --- a/tcl/board/renesas_salvator-xs.cfg +++ b/tcl/board/renesas_salvator-xs.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Renesas R-Car Gen3 Salvator-X(S) Board Config # The Salvator-X(S) boards come with either an H3, M3W, or M3N SOC. diff --git a/tcl/board/renesas_silk.cfg b/tcl/board/renesas_silk.cfg index 08bcb666fd..dd61e1d5d6 100644 --- a/tcl/board/renesas_silk.cfg +++ b/tcl/board/renesas_silk.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Renesas R-Car E2 Evaluation Board set SOC E2 diff --git a/tcl/board/renesas_stout.cfg b/tcl/board/renesas_stout.cfg index 51b53e1549..69a524bf13 100644 --- a/tcl/board/renesas_stout.cfg +++ b/tcl/board/renesas_stout.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Renesas R-Car H2 Evaluation Board set SOC H2 diff --git a/tcl/board/rigado_bmd300_ek.cfg b/tcl/board/rigado_bmd300_ek.cfg index 8e1e65ed0d..601041d157 100644 --- a/tcl/board/rigado_bmd300_ek.cfg +++ b/tcl/board/rigado_bmd300_ek.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Rigado BMD-300 Evaluation Kit # diff --git a/tcl/board/rsc-w910.cfg b/tcl/board/rsc-w910.cfg index 574de0c076..b07f9405f7 100644 --- a/tcl/board/rsc-w910.cfg +++ b/tcl/board/rsc-w910.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Avalue RSC-W8910 sbc # http://www.avalue.com.tw/products/RSC-W910.cfm # 2MB NOR Flash diff --git a/tcl/board/sayma_amc.cfg b/tcl/board/sayma_amc.cfg index 0bd76ba01e..b714609221 100644 --- a/tcl/board/sayma_amc.cfg +++ b/tcl/board/sayma_amc.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Sayma AMC is an FPGA board for the µTCA AMC format # The board is open hardware (CERN OHL) and the gateware and software # running on it are open source (ARTIQ, LGPLv3+). diff --git a/tcl/board/sheevaplug.cfg b/tcl/board/sheevaplug.cfg index 455163777f..734fab6407 100644 --- a/tcl/board/sheevaplug.cfg +++ b/tcl/board/sheevaplug.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Marvell SheevaPlug source [find interface/ftdi/sheevaplug.cfg] diff --git a/tcl/board/sifive-e31arty.cfg b/tcl/board/sifive-e31arty.cfg index 8e701f1563..b3e980f408 100644 --- a/tcl/board/sifive-e31arty.cfg +++ b/tcl/board/sifive-e31arty.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Be sure you include the speed and interface before this file # Example: diff --git a/tcl/board/sifive-e51arty.cfg b/tcl/board/sifive-e51arty.cfg index a543987bb4..3133c39023 100644 --- a/tcl/board/sifive-e51arty.cfg +++ b/tcl/board/sifive-e51arty.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Be sure you include the speed and interface before this file # Example: diff --git a/tcl/board/sifive-hifive1-revb.cfg b/tcl/board/sifive-hifive1-revb.cfg index 7f2a2122ae..7fcab0c63a 100644 --- a/tcl/board/sifive-hifive1-revb.cfg +++ b/tcl/board/sifive-hifive1-revb.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + adapter speed 4000 adapter driver jlink diff --git a/tcl/board/sifive-hifive1.cfg b/tcl/board/sifive-hifive1.cfg index c47485bf23..f69dc4fcc0 100644 --- a/tcl/board/sifive-hifive1.cfg +++ b/tcl/board/sifive-hifive1.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + adapter speed 10000 adapter driver ftdi diff --git a/tcl/board/smdk6410.cfg b/tcl/board/smdk6410.cfg index dd8bf87ad7..be61ae993e 100644 --- a/tcl/board/smdk6410.cfg +++ b/tcl/board/smdk6410.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Target configuration for the Samsung s3c6410 system on chip # Tested on a SMDK6410 # Processor : ARM1176 diff --git a/tcl/board/snps_em_sk.cfg b/tcl/board/snps_em_sk.cfg index 3d93407350..56eed93df7 100644 --- a/tcl/board/snps_em_sk.cfg +++ b/tcl/board/snps_em_sk.cfg @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (C) 2014-2016,2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> -# -# SPDX-License-Identifier: GPL-2.0-or-later # # Synopsys DesignWare ARC EM Starter Kit v2.x diff --git a/tcl/board/snps_em_sk_v1.cfg b/tcl/board/snps_em_sk_v1.cfg index 0c1539ee52..94aab14edc 100644 --- a/tcl/board/snps_em_sk_v1.cfg +++ b/tcl/board/snps_em_sk_v1.cfg @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (C) 2014-2016,2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> -# -# SPDX-License-Identifier: GPL-2.0-or-later # # Synopsys DesignWare ARC EM Starter Kit v1.0 and v1.1 diff --git a/tcl/board/snps_em_sk_v2.1.cfg b/tcl/board/snps_em_sk_v2.1.cfg index c1fb232d53..96391df372 100644 --- a/tcl/board/snps_em_sk_v2.1.cfg +++ b/tcl/board/snps_em_sk_v2.1.cfg @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (C) 2014-2016,2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> -# -# SPDX-License-Identifier: GPL-2.0-or-later # # Synopsys DesignWare ARC EM Starter Kit v2.1 diff --git a/tcl/board/snps_em_sk_v2.2.cfg b/tcl/board/snps_em_sk_v2.2.cfg index 674d9f65c8..c1f6a7223d 100644 --- a/tcl/board/snps_em_sk_v2.2.cfg +++ b/tcl/board/snps_em_sk_v2.2.cfg @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (C) 2016,2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> -# -# SPDX-License-Identifier: GPL-2.0-or-later # # Synopsys DesignWare ARC EM Starter Kit v2.2 diff --git a/tcl/board/snps_hsdk.cfg b/tcl/board/snps_hsdk.cfg index a6228f4c1e..24022e5a80 100644 --- a/tcl/board/snps_hsdk.cfg +++ b/tcl/board/snps_hsdk.cfg @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (C) 2019, 2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> -# -# SPDX-License-Identifier: GPL-2.0-or-later # # Synopsys DesignWare ARC HSDK Software Development Platform (HS38 cores) diff --git a/tcl/board/snps_hsdk_4xd.cfg b/tcl/board/snps_hsdk_4xd.cfg new file mode 100644 index 0000000000..5901533d28 --- /dev/null +++ b/tcl/board/snps_hsdk_4xd.cfg @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Copyright (C) 2023 Synopsys, Inc. +# Artemiy Volkov <artemiy@synopsys.com> + +# Adapted from tcl/board/snps_hsdk.cfg. + +# +# Synopsys DesignWare ARC HSDK Software Development Platform (HS47D cores) +# + +source [find interface/ftdi/snps_sdp.cfg] +adapter speed 10000 + +# ARCs supports only JTAG. +transport select jtag + +# Configure SoC +source [find target/snps_hsdk_4xd.cfg] diff --git a/tcl/board/spansion_sk-fm4-176l-s6e2cc.cfg b/tcl/board/spansion_sk-fm4-176l-s6e2cc.cfg index 2855c5d41f..c22ace8d85 100644 --- a/tcl/board/spansion_sk-fm4-176l-s6e2cc.cfg +++ b/tcl/board/spansion_sk-fm4-176l-s6e2cc.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Spansion SK-FM4-176L-S6E2CC # diff --git a/tcl/board/spansion_sk-fm4-u120-9b560.cfg b/tcl/board/spansion_sk-fm4-u120-9b560.cfg index 38ad4a8831..15477a2c93 100644 --- a/tcl/board/spansion_sk-fm4-u120-9b560.cfg +++ b/tcl/board/spansion_sk-fm4-u120-9b560.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Spansion SK-FM4-U120-9B560 # diff --git a/tcl/board/spear300evb.cfg b/tcl/board/spear300evb.cfg index 9f957038d3..f2cf5969fd 100644 --- a/tcl/board/spear300evb.cfg +++ b/tcl/board/spear300evb.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Configuration for the ST SPEAr300 Evaluation board # EVALSPEAr300 Rev. 1.0 # http://www.st.com/spear diff --git a/tcl/board/spear300evb_mod.cfg b/tcl/board/spear300evb_mod.cfg index 91cad5f199..4b1d578fdd 100644 --- a/tcl/board/spear300evb_mod.cfg +++ b/tcl/board/spear300evb_mod.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Configuration for the ST SPEAr300 Evaluation board # EVALSPEAr300 Rev. 1.0, modified to enable SRST on JTAG connector # http://www.st.com/spear diff --git a/tcl/board/spear310evb20.cfg b/tcl/board/spear310evb20.cfg index c45873ca99..c37bd1d6bf 100644 --- a/tcl/board/spear310evb20.cfg +++ b/tcl/board/spear310evb20.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Configuration for the ST SPEAr310 Evaluation board # EVALSPEAr310 Rev. 2.0 # http://www.st.com/spear diff --git a/tcl/board/spear310evb20_mod.cfg b/tcl/board/spear310evb20_mod.cfg index a7bac55a5c..2c56254f7b 100644 --- a/tcl/board/spear310evb20_mod.cfg +++ b/tcl/board/spear310evb20_mod.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Configuration for the ST SPEAr310 Evaluation board # EVALSPEAr310 Rev. 2.0, modified to enable SRST on JTAG connector # http://www.st.com/spear diff --git a/tcl/board/spear320cpu.cfg b/tcl/board/spear320cpu.cfg index e21db34125..df713ea393 100644 --- a/tcl/board/spear320cpu.cfg +++ b/tcl/board/spear320cpu.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Configuration for the ST SPEAr320 CPU board # EVAL_SPEAr320CPU Rev. 2.0 # http://www.st.com/spear diff --git a/tcl/board/spear320cpu_mod.cfg b/tcl/board/spear320cpu_mod.cfg index 1d62e3b554..d12607d667 100644 --- a/tcl/board/spear320cpu_mod.cfg +++ b/tcl/board/spear320cpu_mod.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Configuration for the ST SPEAr320 Evaluation board # EVAL_SPEAr320CPU Rev. 2.0, modified to enable SRST on JTAG connector # http://www.st.com/spear diff --git a/tcl/board/st_nucleo_8l152r8.cfg b/tcl/board/st_nucleo_8l152r8.cfg index d3372693d1..7cb8bcecd8 100644 --- a/tcl/board/st_nucleo_8l152r8.cfg +++ b/tcl/board/st_nucleo_8l152r8.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is a ST NUCLEO 8L152R8 board with a single STM8L152R8T6 chip. # http://www.st.com/en/evaluation-tools/nucleo-8l152r8.html @@ -5,6 +7,6 @@ source [find interface/stlink-dap.cfg] transport select swim -source [find target/stm8l152.cfg] +source [find target/stm8l15xx8.cfg] reset_config srst_only diff --git a/tcl/board/st_nucleo_f0.cfg b/tcl/board/st_nucleo_f0.cfg index e6a03bba8d..31a95f59d2 100644 --- a/tcl/board/st_nucleo_f0.cfg +++ b/tcl/board/st_nucleo_f0.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is for all ST NUCLEO with any STM32F0. Known boards at the moment: # STM32F030R8 # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF259997 diff --git a/tcl/board/st_nucleo_f103rb.cfg b/tcl/board/st_nucleo_f103rb.cfg index e1990dcf47..9815d4546e 100644 --- a/tcl/board/st_nucleo_f103rb.cfg +++ b/tcl/board/st_nucleo_f103rb.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an ST NUCLEO F103RB board with a single STM32F103RBT6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF259875 diff --git a/tcl/board/st_nucleo_f3.cfg b/tcl/board/st_nucleo_f3.cfg index fec612b398..8833724945 100644 --- a/tcl/board/st_nucleo_f3.cfg +++ b/tcl/board/st_nucleo_f3.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an ST NUCLEO F334R8 board with a single STM32F334R8T6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260004 diff --git a/tcl/board/st_nucleo_f4.cfg b/tcl/board/st_nucleo_f4.cfg index 11f6f87783..a1908e4031 100644 --- a/tcl/board/st_nucleo_f4.cfg +++ b/tcl/board/st_nucleo_f4.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is for all ST NUCLEO with any STM32F4. Known boards at the moment: # STM32F401RET6 # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260000 diff --git a/tcl/board/st_nucleo_f7.cfg b/tcl/board/st_nucleo_f7.cfg index f94679b70e..9c5b36ea46 100644 --- a/tcl/board/st_nucleo_f7.cfg +++ b/tcl/board/st_nucleo_f7.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STMicroelectronics STM32F7 Nucleo development board # Known boards: NUCLEO-F746ZG and NUCLEO-F767ZI diff --git a/tcl/board/st_nucleo_h743zi.cfg b/tcl/board/st_nucleo_h743zi.cfg index cfe2cda1b5..b857b00e05 100644 --- a/tcl/board/st_nucleo_h743zi.cfg +++ b/tcl/board/st_nucleo_h743zi.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an ST NUCLEO-H743ZI board with single STM32H743ZI chip. # http://www.st.com/en/evaluation-tools/nucleo-h743zi.html diff --git a/tcl/board/st_nucleo_h745zi.cfg b/tcl/board/st_nucleo_h745zi.cfg index 22d36f686c..ad563b7d31 100644 --- a/tcl/board/st_nucleo_h745zi.cfg +++ b/tcl/board/st_nucleo_h745zi.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an ST NUCLEO-H745ZI-Q board with single STM32H745ZITx chip. source [find interface/stlink-dap.cfg] diff --git a/tcl/board/st_nucleo_l073rz.cfg b/tcl/board/st_nucleo_l073rz.cfg index b32f8d5fb6..10fac5ef84 100644 --- a/tcl/board/st_nucleo_l073rz.cfg +++ b/tcl/board/st_nucleo_l073rz.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an ST NUCLEO-L073RZ board with single STM32L073RZ chip. # http://www.st.com/en/evaluation-tools/nucleo-l073rz.html source [find interface/stlink.cfg] diff --git a/tcl/board/st_nucleo_l1.cfg b/tcl/board/st_nucleo_l1.cfg index a508bb69c6..50688d2b67 100644 --- a/tcl/board/st_nucleo_l1.cfg +++ b/tcl/board/st_nucleo_l1.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an ST NUCLEO L152RE board with a single STM32L152RET6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260002 diff --git a/tcl/board/st_nucleo_l4.cfg b/tcl/board/st_nucleo_l4.cfg index 1ab9da9b4d..8c63d8cbf8 100644 --- a/tcl/board/st_nucleo_l4.cfg +++ b/tcl/board/st_nucleo_l4.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Should work with all STM32L4 Nucleo Dev Boards. # http://www.st.com/en/evaluation-tools/stm32-mcu-nucleo.html diff --git a/tcl/board/st_nucleo_wb55.cfg b/tcl/board/st_nucleo_wb55.cfg index 5b5b8f7794..29b7ec98d6 100644 --- a/tcl/board/st_nucleo_wb55.cfg +++ b/tcl/board/st_nucleo_wb55.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Configuration for STM32WB55 Nucleo board (STM32WB55RGV6) # diff --git a/tcl/board/steval-idb007v1.cfg b/tcl/board/steval-idb007v1.cfg index 24dbd1e9cb..69d4585e81 100644 --- a/tcl/board/steval-idb007v1.cfg +++ b/tcl/board/steval-idb007v1.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an evaluation board with a single BlueNRG-1 chip. # http://www.st.com/content/st_com/en/products/evaluation-tools/solution-evaluation-tools/communication-and-connectivity-solution-eval-boards/steval-idb008v1.html set CHIPNAME bluenrg-1 diff --git a/tcl/board/steval-idb008v1.cfg b/tcl/board/steval-idb008v1.cfg index 3e9d0e5ee0..057c0dd6bb 100644 --- a/tcl/board/steval-idb008v1.cfg +++ b/tcl/board/steval-idb008v1.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an evaluation board with a single BlueNRG-2 chip. # http://www.st.com/content/st_com/en/products/evaluation-tools/solution-evaluation-tools/communication-and-connectivity-solution-eval-boards/steval-idb007v1.html set CHIPNAME bluenrg-2 diff --git a/tcl/board/steval-idb011v1.cfg b/tcl/board/steval-idb011v1.cfg index 5988c6386d..1163508e95 100644 --- a/tcl/board/steval-idb011v1.cfg +++ b/tcl/board/steval-idb011v1.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an evaluation board with a single BlueNRG-LP chip. set CHIPNAME bluenrg-lp source [find target/bluenrg-x.cfg] diff --git a/tcl/board/steval-idb012v1.cfg b/tcl/board/steval-idb012v1.cfg new file mode 100644 index 0000000000..288cbb2609 --- /dev/null +++ b/tcl/board/steval-idb012v1.cfg @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is an evaluation board with a single BlueNRG-LPS chip. +set CHIPNAME bluenrg-lps +source [find interface/cmsis-dap.cfg] +source [find target/bluenrg-x.cfg] diff --git a/tcl/board/steval_pcc010.cfg b/tcl/board/steval_pcc010.cfg index 94108d1ca2..6e006ba88b 100644 --- a/tcl/board/steval_pcc010.cfg +++ b/tcl/board/steval_pcc010.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Use for the STM207VG plug-in board (1 MiB Flash and 112+16 KiB Ram # coming with the STEVAL-PCC010 board # http://www.st.com/internet/evalboard/product/251530.jsp diff --git a/tcl/board/stm320518_eval.cfg b/tcl/board/stm320518_eval.cfg index 6f1f322717..04486fce83 100644 --- a/tcl/board/stm320518_eval.cfg +++ b/tcl/board/stm320518_eval.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STM320518-EVAL: This is an STM32F0 eval board with a single STM32F051R8T6 # (64KB) chip. # http://www.st.com/internet/evalboard/product/252994.jsp diff --git a/tcl/board/stm320518_eval_stlink.cfg b/tcl/board/stm320518_eval_stlink.cfg index a7fef07653..153f7e5cbc 100644 --- a/tcl/board/stm320518_eval_stlink.cfg +++ b/tcl/board/stm320518_eval_stlink.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STM320518-EVAL: This is an STM32F0 eval board with a single STM32F051R8T6 # (64KB) chip. # http://www.st.com/internet/evalboard/product/252994.jsp diff --git a/tcl/board/stm32100b_eval.cfg b/tcl/board/stm32100b_eval.cfg index 41153e555b..ebb56810de 100644 --- a/tcl/board/stm32100b_eval.cfg +++ b/tcl/board/stm32100b_eval.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32 eval board with a single STM32F100VBT6 chip. # http://www.st.com/internet/evalboard/product/247099.jsp diff --git a/tcl/board/stm3210b_eval.cfg b/tcl/board/stm3210b_eval.cfg index ff3f7771ab..072f54270d 100644 --- a/tcl/board/stm3210b_eval.cfg +++ b/tcl/board/stm3210b_eval.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32 eval board with a single STM32F10x (128KB) chip. # http://www.st.com/internet/evalboard/product/176090.jsp diff --git a/tcl/board/stm3210c_eval.cfg b/tcl/board/stm3210c_eval.cfg index e069c04994..ec56f63a5e 100644 --- a/tcl/board/stm3210c_eval.cfg +++ b/tcl/board/stm3210c_eval.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32 eval board with a single STM32F107VCT chip. # http://www.st.com/internet/evalboard/product/217965.jsp diff --git a/tcl/board/stm3210e_eval.cfg b/tcl/board/stm3210e_eval.cfg index f30253c116..f08e04b0e4 100644 --- a/tcl/board/stm3210e_eval.cfg +++ b/tcl/board/stm3210e_eval.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32 eval board with a single STM32F103ZET6 chip. # http://www.st.com/internet/evalboard/product/204176.jsp diff --git a/tcl/board/stm3220g_eval.cfg b/tcl/board/stm3220g_eval.cfg index 4728432987..9782a0710c 100644 --- a/tcl/board/stm3220g_eval.cfg +++ b/tcl/board/stm3220g_eval.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STM3220G-EVAL: This is an STM32F2 eval board with a single STM32F207IGH6 # (128KB) chip. # http://www.st.com/internet/evalboard/product/250374.jsp diff --git a/tcl/board/stm3220g_eval_stlink.cfg b/tcl/board/stm3220g_eval_stlink.cfg index b58e42fe5d..d5296720c2 100644 --- a/tcl/board/stm3220g_eval_stlink.cfg +++ b/tcl/board/stm3220g_eval_stlink.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STM3220G-EVAL: This is an STM32F2 eval board with a single STM32F207IGH6 # (128KB) chip. # http://www.st.com/internet/evalboard/product/250374.jsp diff --git a/tcl/board/stm3241g_eval.cfg b/tcl/board/stm3241g_eval.cfg index 5f1c449d35..7df373faf2 100644 --- a/tcl/board/stm3241g_eval.cfg +++ b/tcl/board/stm3241g_eval.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STM3241G-EVAL: This is an STM32F4 eval board with a single STM32F417IGH6 # (1024KB) chip. # http://www.st.com/internet/evalboard/product/252216.jsp diff --git a/tcl/board/stm3241g_eval_stlink.cfg b/tcl/board/stm3241g_eval_stlink.cfg index b1c54a2c67..d2d5790776 100644 --- a/tcl/board/stm3241g_eval_stlink.cfg +++ b/tcl/board/stm3241g_eval_stlink.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STM3241G-EVAL: This is an STM32F4 eval board with a single STM32F417IGH6 # (1024KB) chip. # http://www.st.com/internet/evalboard/product/252216.jsp diff --git a/tcl/board/stm32429i_eval.cfg b/tcl/board/stm32429i_eval.cfg index a5d3f53c92..3304ef6252 100644 --- a/tcl/board/stm32429i_eval.cfg +++ b/tcl/board/stm32429i_eval.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STM32429I-EVAL: This is an STM32F4 eval board with a single STM32F429NIH6 # (2048KB) chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF259093 diff --git a/tcl/board/stm32429i_eval_stlink.cfg b/tcl/board/stm32429i_eval_stlink.cfg index 010d371985..be3c482263 100644 --- a/tcl/board/stm32429i_eval_stlink.cfg +++ b/tcl/board/stm32429i_eval_stlink.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STM32429I-EVAL: This is an STM32F4 eval board with a single STM32F429NIH6 # (2048KB) chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF259093 diff --git a/tcl/board/stm32439i_eval.cfg b/tcl/board/stm32439i_eval.cfg index 8ebdc82675..c29d4dea59 100644 --- a/tcl/board/stm32439i_eval.cfg +++ b/tcl/board/stm32439i_eval.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STM32439I-EVAL: This is an STM32F4 eval board with a single STM32F439NIH6 # (2048KB) chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF259094 diff --git a/tcl/board/stm32439i_eval_stlink.cfg b/tcl/board/stm32439i_eval_stlink.cfg index b722ce67c1..7a1a396fcb 100644 --- a/tcl/board/stm32439i_eval_stlink.cfg +++ b/tcl/board/stm32439i_eval_stlink.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STM32439I-EVAL: This is an STM32F4 eval board with a single STM32F439NIH6 # (2048KB) chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF259094 diff --git a/tcl/board/stm327x6g_eval.cfg b/tcl/board/stm327x6g_eval.cfg index 3d522f59d4..03fe949a72 100644 --- a/tcl/board/stm327x6g_eval.cfg +++ b/tcl/board/stm327x6g_eval.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STM327[4|5]6G-EVAL: This is for the STM32F7 eval boards. # STM32746G-EVAL # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1199/PF261639 diff --git a/tcl/board/stm32f0discovery.cfg b/tcl/board/stm32f0discovery.cfg index e2b5e38444..60fb4a65e4 100644 --- a/tcl/board/stm32f0discovery.cfg +++ b/tcl/board/stm32f0discovery.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32F0 discovery board with a single STM32F051R8T6 chip. # http://www.st.com/internet/evalboard/product/253215.jsp diff --git a/tcl/board/stm32f103c8_blue_pill.cfg b/tcl/board/stm32f103c8_blue_pill.cfg index 2487f35008..0b84f72e91 100644 --- a/tcl/board/stm32f103c8_blue_pill.cfg +++ b/tcl/board/stm32f103c8_blue_pill.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STM32F103C8 "Blue Pill" # NOTE: diff --git a/tcl/board/stm32f334discovery.cfg b/tcl/board/stm32f334discovery.cfg index be817d7165..3ff296803c 100644 --- a/tcl/board/stm32f334discovery.cfg +++ b/tcl/board/stm32f334discovery.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32F334 discovery board with a single STM32F334C8T6 chip. # As it is one of the few boards with stlink V.2-1, we source the corresponding # nucleo file. diff --git a/tcl/board/stm32f3discovery.cfg b/tcl/board/stm32f3discovery.cfg index 9bb62f5f2a..f28e11f6a6 100644 --- a/tcl/board/stm32f3discovery.cfg +++ b/tcl/board/stm32f3discovery.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32F3 discovery board with a single STM32F303VCT6 chip. # http://www.st.com/internet/evalboard/product/254044.jsp diff --git a/tcl/board/stm32f412g-disco.cfg b/tcl/board/stm32f412g-disco.cfg index b6bdb64a56..757b25d75c 100644 --- a/tcl/board/stm32f412g-disco.cfg +++ b/tcl/board/stm32f412g-disco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32F412G discovery board with a single STM32F412ZGT6 chip. # http://www.st.com/en/evaluation-tools/32f412gdiscovery.html diff --git a/tcl/board/stm32f413h-disco.cfg b/tcl/board/stm32f413h-disco.cfg index 99f2a49332..6abf495514 100644 --- a/tcl/board/stm32f413h-disco.cfg +++ b/tcl/board/stm32f413h-disco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32F413H discovery board with a single STM32F413ZHT6 chip. # http://www.st.com/en/evaluation-tools/32f413hdiscovery.html diff --git a/tcl/board/stm32f429disc1.cfg b/tcl/board/stm32f429disc1.cfg index c0bcebae4e..657aa1986f 100644 --- a/tcl/board/stm32f429disc1.cfg +++ b/tcl/board/stm32f429disc1.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # This is an STM32F429 discovery board with a single STM32F429ZI chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF259090 diff --git a/tcl/board/stm32f429discovery.cfg b/tcl/board/stm32f429discovery.cfg index 7aef09d4f0..d1b5f5a118 100644 --- a/tcl/board/stm32f429discovery.cfg +++ b/tcl/board/stm32f429discovery.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # This is an STM32F429 discovery board with a single STM32F429ZI chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF259090 diff --git a/tcl/board/stm32f469discovery.cfg b/tcl/board/stm32f469discovery.cfg index a9559a756b..cca25b7f04 100644 --- a/tcl/board/stm32f469discovery.cfg +++ b/tcl/board/stm32f469discovery.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # This is an STM32F469 discovery board with a single STM32F469NI chip. # http://www.st.com/web/catalog/tools/FM116/CL1620/SC959/SS1532/LN1848/PF262395 diff --git a/tcl/board/stm32f469i-disco.cfg b/tcl/board/stm32f469i-disco.cfg index ab6751225f..7ce57f6e75 100644 --- a/tcl/board/stm32f469i-disco.cfg +++ b/tcl/board/stm32f469i-disco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32F469I discovery board with a single STM32F469NIH6 chip. # http://www.st.com/en/evaluation-tools/32f469idiscovery.html diff --git a/tcl/board/stm32f4discovery.cfg b/tcl/board/stm32f4discovery.cfg index 60b7f42b5c..714f1e9032 100644 --- a/tcl/board/stm32f4discovery.cfg +++ b/tcl/board/stm32f4discovery.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32F4 discovery board with a single STM32F407VGT6 chip. # http://www.st.com/internet/evalboard/product/252419.jsp diff --git a/tcl/board/stm32f723e-disco.cfg b/tcl/board/stm32f723e-disco.cfg index b809c5e46c..2dee2f9023 100644 --- a/tcl/board/stm32f723e-disco.cfg +++ b/tcl/board/stm32f723e-disco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32F723E discovery board with a single STM32F723IEK6 chip. # http://www.st.com/en/evaluation-tools/32f723ediscovery.html diff --git a/tcl/board/stm32f746g-disco.cfg b/tcl/board/stm32f746g-disco.cfg index 5d2c1a4653..fed1d8ec9b 100644 --- a/tcl/board/stm32f746g-disco.cfg +++ b/tcl/board/stm32f746g-disco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32F746G discovery board with a single STM32F746NGH6 chip. # http://www.st.com/en/evaluation-tools/32f746gdiscovery.html diff --git a/tcl/board/stm32f769i-disco.cfg b/tcl/board/stm32f769i-disco.cfg index 75dffd8db7..2969bb9272 100644 --- a/tcl/board/stm32f769i-disco.cfg +++ b/tcl/board/stm32f769i-disco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32F769I discovery board with a single STM32F769NIH6 chip. # http://www.st.com/en/evaluation-tools/32f769idiscovery.html diff --git a/tcl/board/stm32f7discovery.cfg b/tcl/board/stm32f7discovery.cfg index d6cbff465b..4cc22ea625 100644 --- a/tcl/board/stm32f7discovery.cfg +++ b/tcl/board/stm32f7discovery.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32F7 discovery board with a single STM32F756NGH6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1848/PF261641 diff --git a/tcl/board/stm32h735g-disco.cfg b/tcl/board/stm32h735g-disco.cfg index cb5caa4af7..4097ae28b2 100644 --- a/tcl/board/stm32h735g-disco.cfg +++ b/tcl/board/stm32h735g-disco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is a stm32h735g-dk with a single STM32H735IGK6 chip. # https://www.st.com/en/evaluation-tools/stm32h735g-dk.html # diff --git a/tcl/board/stm32h745i-disco.cfg b/tcl/board/stm32h745i-disco.cfg index 5a587ae8c5..1c0bc6748c 100644 --- a/tcl/board/stm32h745i-disco.cfg +++ b/tcl/board/stm32h745i-disco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is a stm32h745i-disco with a single STM32H745XIH6 chip. # www.st.com/en/product/stm32h745i-disco.html # diff --git a/tcl/board/stm32h747i-disco.cfg b/tcl/board/stm32h747i-disco.cfg index 698ef58846..e0a348ef08 100644 --- a/tcl/board/stm32h747i-disco.cfg +++ b/tcl/board/stm32h747i-disco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is a stm32h747i-disco with a single STM32H747XIH6 chip. # www.st.com/en/product/stm32h747i-disco.html # diff --git a/tcl/board/stm32h750b-disco.cfg b/tcl/board/stm32h750b-disco.cfg index 609cf38537..efb32b1dfb 100644 --- a/tcl/board/stm32h750b-disco.cfg +++ b/tcl/board/stm32h750b-disco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is a stm32h750b-dk with a single STM32H750XBH6 chip. # www.st.com/en/product/stm32h750b-dk.html # diff --git a/tcl/board/stm32h7b3i-disco.cfg b/tcl/board/stm32h7b3i-disco.cfg index 0c4cc23beb..58ad9f7814 100644 --- a/tcl/board/stm32h7b3i-disco.cfg +++ b/tcl/board/stm32h7b3i-disco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is a stm32h7b3i-dk with a single STM32H7B3LIH6Q chip. # https://www.st.com/en/evaluation-tools/stm32h7b3i-dk.html # diff --git a/tcl/board/stm32h7x3i_eval.cfg b/tcl/board/stm32h7x3i_eval.cfg index caf68b6c44..b9c4c74c26 100644 --- a/tcl/board/stm32h7x3i_eval.cfg +++ b/tcl/board/stm32h7x3i_eval.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STM32H7[4|5]3I-EVAL: this is for the H7 eval boards. # This is an ST EVAL-H743XI board with single STM32H743XI chip. # http://www.st.com/en/evaluation-tools/stm32h743i-eval.html diff --git a/tcl/board/stm32h7x_dual_qspi.cfg b/tcl/board/stm32h7x_dual_qspi.cfg index bdff9c1b81..0349fadc54 100644 --- a/tcl/board/stm32h7x_dual_qspi.cfg +++ b/tcl/board/stm32h7x_dual_qspi.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # stm32h754i-disco and stm32h750b-dk dual quad qspi. # QUADSPI initialization diff --git a/tcl/board/stm32l0discovery.cfg b/tcl/board/stm32l0discovery.cfg index aabbf8170a..c711d9c8a8 100644 --- a/tcl/board/stm32l0discovery.cfg +++ b/tcl/board/stm32l0discovery.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32L053 discovery board with a single STM32L053 chip. # http://www.st.com/web/en/catalog/tools/PF260319 diff --git a/tcl/board/stm32l476g-disco.cfg b/tcl/board/stm32l476g-disco.cfg index dab2fe12de..a32d20fb3f 100644 --- a/tcl/board/stm32l476g-disco.cfg +++ b/tcl/board/stm32l476g-disco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32L476G discovery board with a single STM32L476VGT6 chip. # http://www.st.com/en/evaluation-tools/32l476gdiscovery.html diff --git a/tcl/board/stm32l496g-disco.cfg b/tcl/board/stm32l496g-disco.cfg index a93b07cc17..1ba2299ca9 100644 --- a/tcl/board/stm32l496g-disco.cfg +++ b/tcl/board/stm32l496g-disco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32L496G discovery board with a single STM32L496AGI6 chip. # http://www.st.com/en/evaluation-tools/32l496gdiscovery.html diff --git a/tcl/board/stm32l4discovery.cfg b/tcl/board/stm32l4discovery.cfg index 8b79841ed8..f089550780 100644 --- a/tcl/board/stm32l4discovery.cfg +++ b/tcl/board/stm32l4discovery.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Explicitly for the STM32L476 discovery board: # http://www.st.com/web/en/catalog/tools/PF261635 # but perfectly functional for any other STM32L4 board connected via diff --git a/tcl/board/stm32l4p5g-disco.cfg b/tcl/board/stm32l4p5g-disco.cfg index d7420edf20..20d781a1a4 100644 --- a/tcl/board/stm32l4p5g-disco.cfg +++ b/tcl/board/stm32l4p5g-disco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is a STM32L4P5G discovery board with a single STM32L4R9AGI6 chip. # http://www.st.com/en/evaluation-tools/stm32l4p5g-dk.html diff --git a/tcl/board/stm32l4r9i-disco.cfg b/tcl/board/stm32l4r9i-disco.cfg index 70ed199407..f364ad3d58 100644 --- a/tcl/board/stm32l4r9i-disco.cfg +++ b/tcl/board/stm32l4r9i-disco.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is a STM32L4R9I discovery board with a single STM32L4R9AII6 chip. # http://www.st.com/en/evaluation-tools/32l4r9idiscovery.html diff --git a/tcl/board/stm32ldiscovery.cfg b/tcl/board/stm32ldiscovery.cfg index 3e397cba4b..d760edaba7 100644 --- a/tcl/board/stm32ldiscovery.cfg +++ b/tcl/board/stm32ldiscovery.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32L discovery board with a single STM32L152RBT6 chip. # http://www.st.com/internet/evalboard/product/250990.jsp diff --git a/tcl/board/stm32mp13x_dk.cfg b/tcl/board/stm32mp13x_dk.cfg index 6993b1bc0f..6328ddb4c0 100644 --- a/tcl/board/stm32mp13x_dk.cfg +++ b/tcl/board/stm32mp13x_dk.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # board MB1635x # http://www.st.com/en/evaluation-tools/stm32mp135f-dk.html diff --git a/tcl/board/stm32mp15x_dk2.cfg b/tcl/board/stm32mp15x_dk2.cfg index 0233c6d751..9503428d1a 100644 --- a/tcl/board/stm32mp15x_dk2.cfg +++ b/tcl/board/stm32mp15x_dk2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # board MB1272B # http://www.st.com/en/evaluation-tools/stm32mp157a-dk1.html # http://www.st.com/en/evaluation-tools/stm32mp157c-dk2.html diff --git a/tcl/board/stm32vldiscovery.cfg b/tcl/board/stm32vldiscovery.cfg index 60805b32c3..30e35b9817 100644 --- a/tcl/board/stm32vldiscovery.cfg +++ b/tcl/board/stm32vldiscovery.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an STM32VL discovery board with a single STM32F100RB chip. # http://www.st.com/internet/evalboard/product/250863.jsp diff --git a/tcl/board/str910-eval.cfg b/tcl/board/str910-eval.cfg index 5fe7a4e733..b6e9837720 100644 --- a/tcl/board/str910-eval.cfg +++ b/tcl/board/str910-eval.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # str910-eval eval board # # Need reset scripts diff --git a/tcl/board/telo.cfg b/tcl/board/telo.cfg index 2c98ca3bd2..721c01975d 100644 --- a/tcl/board/telo.cfg +++ b/tcl/board/telo.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/c100.cfg] # basic register definition for C100 source [find target/c100regs.tcl] diff --git a/tcl/board/ti_am243_launchpad.cfg b/tcl/board/ti_am243_launchpad.cfg new file mode 100644 index 0000000000..aa75dda888 --- /dev/null +++ b/tcl/board/ti_am243_launchpad.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments AM243 Launchpad +# https://www.ti.com/tool/LP-AM243 +# + +# AM243 Launchpad has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC am243 +} + +source [find target/ti_k3.cfg] + +adapter speed 250 diff --git a/tcl/board/ti_am263_launchpad.cfg b/tcl/board/ti_am263_launchpad.cfg new file mode 100644 index 0000000000..a07a21b3d5 --- /dev/null +++ b/tcl/board/ti_am263_launchpad.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments AM263 Launchpad +# https://www.ti.com/tool/LP-AM263 +# + +# AM263 Launchpad has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC am263 +} + +source [find target/ti_k3.cfg] + +adapter speed 250 diff --git a/tcl/board/ti_am273_launchpad.cfg b/tcl/board/ti_am273_launchpad.cfg new file mode 100644 index 0000000000..c17170bf13 --- /dev/null +++ b/tcl/board/ti_am273_launchpad.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments AM273 Launchpad +# https://www.ti.com/tool/LP-AM273 +# + +# AM273 Launchpad has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC am273 +} + +source [find target/ti_k3.cfg] + +adapter speed 250 diff --git a/tcl/board/ti_am335xevm.cfg b/tcl/board/ti_am335xevm.cfg index 3e2ee3ff97..af058ecf70 100644 --- a/tcl/board/ti_am335xevm.cfg +++ b/tcl/board/ti_am335xevm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI AM335x Evaluation Module # diff --git a/tcl/board/ti_am437x_idk.cfg b/tcl/board/ti_am437x_idk.cfg index fc2b81b29f..b4277628ee 100644 --- a/tcl/board/ti_am437x_idk.cfg +++ b/tcl/board/ti_am437x_idk.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Texas Instruments AM437x Industrial Development Kit # The JTAG interface is built directly on the board. diff --git a/tcl/board/ti_am43xx_evm.cfg b/tcl/board/ti_am43xx_evm.cfg index dbc37ae826..005421f423 100644 --- a/tcl/board/ti_am43xx_evm.cfg +++ b/tcl/board/ti_am43xx_evm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Works on both AM437x GP EVM and AM438x ePOS EVM transport select jtag adapter speed 16000 diff --git a/tcl/board/ti_am625_swd_native.cfg b/tcl/board/ti_am625_swd_native.cfg new file mode 100644 index 0000000000..dc4b20579d --- /dev/null +++ b/tcl/board/ti_am625_swd_native.cfg @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2022-2023 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments am625 +# Link: https://www.ti.com/product/AM625 +# +# This configuration file is used as a self hosted debug configuration that +# works on every AM625 platform based on firewall configuration permitted +# in the system. +# +# In this system openOCD runs on one of the CPUs inside AM625 and provides +# network ports that can then be used to debug the microcontrollers on the +# SoC - either self hosted IDE OR remotely. + +# We are using dmem, which uses dapdirect_swd transport +adapter driver dmem + +if { ![info exists SOC] } { + set SOC am625 +} + +source [find target/ti_k3.cfg] diff --git a/tcl/board/ti_am62a7evm.cfg b/tcl/board/ti_am62a7evm.cfg new file mode 100644 index 0000000000..e40790950b --- /dev/null +++ b/tcl/board/ti_am62a7evm.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments am62a7 EVM/SK +# Link: https://www.ti.com/tool/SK-AM62A-LP +# + +# AM62a7 EVM/SK has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC am62a7 +} + +source [find target/ti_k3.cfg] + +adapter speed 2500 diff --git a/tcl/board/ti_am62pevm.cfg b/tcl/board/ti_am62pevm.cfg new file mode 100644 index 0000000000..2322b3d943 --- /dev/null +++ b/tcl/board/ti_am62pevm.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments SK-AM62P: https://www.ti.com/lit/zip/sprr487 +# + +# AM62P SK/EVM has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC am62p +} + +source [find target/ti_k3.cfg] + +adapter speed 2500 diff --git a/tcl/board/ti_beagleboard.cfg b/tcl/board/ti_beagleboard.cfg index 9b3b8b0166..6767bd6df1 100644 --- a/tcl/board/ti_beagleboard.cfg +++ b/tcl/board/ti_beagleboard.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # OMAP3 BeagleBoard # http://beagleboard.org diff --git a/tcl/board/ti_beagleboard_xm.cfg b/tcl/board/ti_beagleboard_xm.cfg index 683f583b26..fd176a0016 100644 --- a/tcl/board/ti_beagleboard_xm.cfg +++ b/tcl/board/ti_beagleboard_xm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # BeagleBoard xM (DM37x) # http://beagleboard.org diff --git a/tcl/board/ti_beaglebone-base.cfg b/tcl/board/ti_beaglebone-base.cfg index 82d3c312b6..566f0a4b30 100644 --- a/tcl/board/ti_beaglebone-base.cfg +++ b/tcl/board/ti_beaglebone-base.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # AM335x Beaglebone family base configuration # http://beagleboard.org/bone diff --git a/tcl/board/ti_beaglebone.cfg b/tcl/board/ti_beaglebone.cfg index 7ba8c50f24..d96e45f6ad 100644 --- a/tcl/board/ti_beaglebone.cfg +++ b/tcl/board/ti_beaglebone.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # AM335x Beaglebone # http://beagleboard.org/bone diff --git a/tcl/board/ti_beaglebone_black.cfg b/tcl/board/ti_beaglebone_black.cfg index c730814cc5..d72bf09dd6 100644 --- a/tcl/board/ti_beaglebone_black.cfg +++ b/tcl/board/ti_beaglebone_black.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # AM335x Beaglebone Black # http://beagleboard.org/bone diff --git a/tcl/board/ti_blaze.cfg b/tcl/board/ti_blaze.cfg index 488138982b..e28b05b83a 100644 --- a/tcl/board/ti_blaze.cfg +++ b/tcl/board/ti_blaze.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + jtag_rclk 6000 source [find target/omap4430.cfg] diff --git a/tcl/board/ti_cc13x0_launchpad.cfg b/tcl/board/ti_cc13x0_launchpad.cfg index 4fbce41200..f6dfbcda3d 100644 --- a/tcl/board/ti_cc13x0_launchpad.cfg +++ b/tcl/board/ti_cc13x0_launchpad.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI CC13x0 LaunchPad Evaluation Kit # diff --git a/tcl/board/ti_cc13x2_launchpad.cfg b/tcl/board/ti_cc13x2_launchpad.cfg index dc0c182301..900842a2fd 100644 --- a/tcl/board/ti_cc13x2_launchpad.cfg +++ b/tcl/board/ti_cc13x2_launchpad.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI CC13x2 LaunchPad Evaluation Kit # diff --git a/tcl/board/ti_cc26x0_launchpad.cfg b/tcl/board/ti_cc26x0_launchpad.cfg index 372e57cebd..431383db1c 100644 --- a/tcl/board/ti_cc26x0_launchpad.cfg +++ b/tcl/board/ti_cc26x0_launchpad.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI CC26x0 LaunchPad Evaluation Kit # diff --git a/tcl/board/ti_cc26x2_launchpad.cfg b/tcl/board/ti_cc26x2_launchpad.cfg index c8057ad3db..133f57e07f 100644 --- a/tcl/board/ti_cc26x2_launchpad.cfg +++ b/tcl/board/ti_cc26x2_launchpad.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI CC26x2 LaunchPad Evaluation Kit # diff --git a/tcl/board/ti_cc3200_launchxl.cfg b/tcl/board/ti_cc3200_launchxl.cfg index b37b406ad6..5f39b8a83f 100644 --- a/tcl/board/ti_cc3200_launchxl.cfg +++ b/tcl/board/ti_cc3200_launchxl.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI SimpleLink Wi-Fi CC3200 LaunchPad # diff --git a/tcl/board/ti_cc3220sf_launchpad.cfg b/tcl/board/ti_cc3220sf_launchpad.cfg index 7c8310af06..fe34554dfc 100644 --- a/tcl/board/ti_cc3220sf_launchpad.cfg +++ b/tcl/board/ti_cc3220sf_launchpad.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI CC3220SF-LaunchXL LaunchPad Evaluation Kit # diff --git a/tcl/board/ti_cc32xx_launchpad.cfg b/tcl/board/ti_cc32xx_launchpad.cfg index d0f2a831cd..343da485d3 100644 --- a/tcl/board/ti_cc32xx_launchpad.cfg +++ b/tcl/board/ti_cc32xx_launchpad.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI CC32xx-LaunchXL LaunchPad Evaluation Kit # diff --git a/tcl/board/ti_dk-tm4c129.cfg b/tcl/board/ti_dk-tm4c129.cfg index f1171af124..d8210e32d2 100644 --- a/tcl/board/ti_dk-tm4c129.cfg +++ b/tcl/board/ti_dk-tm4c129.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI Tiva C DK-TM4C129X Connected Development Kit # diff --git a/tcl/board/ti_ek-tm4c123gxl.cfg b/tcl/board/ti_ek-tm4c123gxl.cfg index 4fc1050c73..91390fa82f 100644 --- a/tcl/board/ti_ek-tm4c123gxl.cfg +++ b/tcl/board/ti_ek-tm4c123gxl.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI Tiva C Series ek-tm4c123gxl Launchpad Evaluation Kit # diff --git a/tcl/board/ti_ek-tm4c1294xl.cfg b/tcl/board/ti_ek-tm4c1294xl.cfg index b3f384c0e1..63612c686b 100644 --- a/tcl/board/ti_ek-tm4c1294xl.cfg +++ b/tcl/board/ti_ek-tm4c1294xl.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI Tiva C Series ek-tm4c1294xl Launchpad Evaluation Kit # diff --git a/tcl/board/ti_j721e_swd_native.cfg b/tcl/board/ti_j721e_swd_native.cfg new file mode 100644 index 0000000000..3041c3c345 --- /dev/null +++ b/tcl/board/ti_j721e_swd_native.cfg @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2022-2023 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments TDA4VM/J721E +# Link: https://www.ti.com/product/TDA4VM +# +# This configuration file is used as a self hosted debug configuration that +# works on every TDA4VM platform based on firewall configuration permitted +# in the system. +# +# In this system openOCD runs on one of the CPUs inside TDA4VM and provides +# network ports that can then be used to debug the microcontrollers on the +# SoC - either self hosted IDE OR remotely. + +# We are using dmem, which uses dapdirect_swd transport +adapter driver dmem + +if { ![info exists SOC] } { + set SOC j721e +} +source [find target/ti_k3.cfg] diff --git a/tcl/board/ti_j722sevm.cfg b/tcl/board/ti_j722sevm.cfg new file mode 100644 index 0000000000..6a5c2d9cd9 --- /dev/null +++ b/tcl/board/ti_j722sevm.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ +# +# Texas Instruments EVM-J722S: https://www.ti.com/lit/zip/sprr495 +# + +# J722S EVM has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC j722s +} + +source [find target/ti_k3.cfg] + +adapter speed 2500 diff --git a/tcl/board/ti_j784s4evm.cfg b/tcl/board/ti_j784s4evm.cfg new file mode 100644 index 0000000000..d23dc8ce67 --- /dev/null +++ b/tcl/board/ti_j784s4evm.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments J784S4 EVM: https://www.ti.com/tool/J784S4XEVM +# Texas Instruments SK-AM69: https://www.ti.com/tool/SK-AM69 +# + +# J784S4/AM69 SK/EVM has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC j784s4 +} + +source [find target/ti_k3.cfg] + +adapter speed 2500 diff --git a/tcl/board/ti_msp432_launchpad.cfg b/tcl/board/ti_msp432_launchpad.cfg index 6d2b15dd46..4832b837b0 100644 --- a/tcl/board/ti_msp432_launchpad.cfg +++ b/tcl/board/ti_msp432_launchpad.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI MSP432 LaunchPad Evaluation Kit # diff --git a/tcl/board/ti_pandaboard.cfg b/tcl/board/ti_pandaboard.cfg index bc92596101..45092e067d 100644 --- a/tcl/board/ti_pandaboard.cfg +++ b/tcl/board/ti_pandaboard.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + jtag_rclk 6000 source [find target/omap4430.cfg] diff --git a/tcl/board/ti_pandaboard_es.cfg b/tcl/board/ti_pandaboard_es.cfg index 756fa33eee..f83735844d 100644 --- a/tcl/board/ti_pandaboard_es.cfg +++ b/tcl/board/ti_pandaboard_es.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + jtag_rclk 6000 source [find target/omap4460.cfg] diff --git a/tcl/board/ti_tmdx570ls20susb.cfg b/tcl/board/ti_tmdx570ls20susb.cfg index e71136cfea..9c5ef74eaa 100644 --- a/tcl/board/ti_tmdx570ls20susb.cfg +++ b/tcl/board/ti_tmdx570ls20susb.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # TMS570 Microcontroller USB Kit # http://www.ti.com/tool/TMDX570LS20SUSB diff --git a/tcl/board/ti_tmdx570ls31usb.cfg b/tcl/board/ti_tmdx570ls31usb.cfg index 6d7350297f..324f003d38 100644 --- a/tcl/board/ti_tmdx570ls31usb.cfg +++ b/tcl/board/ti_tmdx570ls31usb.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + adapter speed 1500 source [find interface/ftdi/xds100v2.cfg] diff --git a/tcl/board/tocoding_poplar.cfg b/tcl/board/tocoding_poplar.cfg index 36d5aec47d..5f9dba43b0 100644 --- a/tcl/board/tocoding_poplar.cfg +++ b/tcl/board/tocoding_poplar.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # board configuration for Tocoding Poplar # diff --git a/tcl/board/topas910.cfg b/tcl/board/topas910.cfg index 9f994c8ea6..f45f6e7eea 100644 --- a/tcl/board/topas910.cfg +++ b/tcl/board/topas910.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: Toshiba TOPAS910 -- TMPA910 Starterkit # diff --git a/tcl/board/topasa900.cfg b/tcl/board/topasa900.cfg index 4fa63831bc..d6ddc44efe 100644 --- a/tcl/board/topasa900.cfg +++ b/tcl/board/topasa900.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Thanks to Pieter Conradie for this script! # Target: Toshiba TOPAS900 -- TMPA900 Starterkit ###################################### diff --git a/tcl/board/tp-link_tl-mr3020.cfg b/tcl/board/tp-link_tl-mr3020.cfg index 366bec8e1a..1d1d627bc2 100644 --- a/tcl/board/tp-link_tl-mr3020.cfg +++ b/tcl/board/tp-link_tl-mr3020.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/atheros_ar9331.cfg] $_TARGETNAME configure -event reset-init { diff --git a/tcl/board/tp-link_wdr4300.cfg b/tcl/board/tp-link_wdr4300.cfg index 7aa79aba7a..9947366f7a 100644 --- a/tcl/board/tp-link_wdr4300.cfg +++ b/tcl/board/tp-link_wdr4300.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/atheros_ar9344.cfg] reset_config trst_only separate diff --git a/tcl/board/trion_t20_bga256.cfg b/tcl/board/trion_t20_bga256.cfg new file mode 100644 index 0000000000..dc76d39104 --- /dev/null +++ b/tcl/board/trion_t20_bga256.cfg @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Trion® T20 BGA256 Development Kit +# https://www.efinixinc.com/docs/trion20-devkit-ug-v1.5.pdf +# +# works after power cycle or pushing sw1. +# it is because we cannot control CDONE which is connected to ftdi channel 0 +# note from an006: For JTAG programming, T4, T8, T13, and T20 FPGAs use the +# CRESET_N and SS_N pins in addition to the standard JTAG pins. + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 + +ftdi channel 1 +ftdi layout_init 0x0008 0x008b +reset_config none +transport select jtag +adapter speed 6000 + +source [find fpga/efinix_trion.cfg] + +#openocd -f board/trion_t20_bga256.cfg -c "init" -c "pld load trion.pld outflow/trion_blinker.bit" +#ipdbg -start -tap trion.tap -hub 0x8 -port 5555 -tool 0 + +set JTAGSPI_CHAIN_ID trion.pld +source [find cpld/jtagspi.cfg] + +#jtagspi_init trion.pld "trion_jtagspi/outflow/trion_jtagspi.bit" 0xAB +#jtagspi_program trion_blinker/outflow/trion_blinker.bin 0 diff --git a/tcl/board/twr-k60f120m.cfg b/tcl/board/twr-k60f120m.cfg index c4d87db262..5914cf0c11 100644 --- a/tcl/board/twr-k60f120m.cfg +++ b/tcl/board/twr-k60f120m.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Freescale TWRK60F120M development board # diff --git a/tcl/board/twr-k60n512.cfg b/tcl/board/twr-k60n512.cfg index 5babeb8c13..b7743a551a 100644 --- a/tcl/board/twr-k60n512.cfg +++ b/tcl/board/twr-k60n512.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Freescale TWRK60N512 development board # diff --git a/tcl/board/twr-vf65gs10.cfg b/tcl/board/twr-vf65gs10.cfg index 0d6d3329aa..bfc7288586 100644 --- a/tcl/board/twr-vf65gs10.cfg +++ b/tcl/board/twr-vf65gs10.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Board configuration file for the Freescale VF65GS10 tower board # diff --git a/tcl/board/twr-vf65gs10_cmsisdap.cfg b/tcl/board/twr-vf65gs10_cmsisdap.cfg index ab4548f99c..86930c5c3d 100644 --- a/tcl/board/twr-vf65gs10_cmsisdap.cfg +++ b/tcl/board/twr-vf65gs10_cmsisdap.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Board configuration file for the Freescale VF65GS10 tower board # diff --git a/tcl/board/tx25_stk5.cfg b/tcl/board/tx25_stk5.cfg index 9d77afdf33..5bf8fd03e7 100644 --- a/tcl/board/tx25_stk5.cfg +++ b/tcl/board/tx25_stk5.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # ------------------------------------------------------------------------- # KaRo TX25 CPU Module on a StarterkitV base board # http://www.karo-electronics.com/tx25.html diff --git a/tcl/board/tx27_stk5.cfg b/tcl/board/tx27_stk5.cfg index bb933e149d..061f1f9cca 100644 --- a/tcl/board/tx27_stk5.cfg +++ b/tcl/board/tx27_stk5.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # KaRo TX27 CPU Module on a StarterkitV base board # # http://www.karo-electronics.com/tx27.html diff --git a/tcl/board/unknown_at91sam9260.cfg b/tcl/board/unknown_at91sam9260.cfg index 5570ef04b0..cab18b61f7 100644 --- a/tcl/board/unknown_at91sam9260.cfg +++ b/tcl/board/unknown_at91sam9260.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Thanks to Pieter Conradie for this script! # # Unknown vendor board contains: diff --git a/tcl/board/uptech_2410.cfg b/tcl/board/uptech_2410.cfg index 0a2c475f71..ba269f5d07 100644 --- a/tcl/board/uptech_2410.cfg +++ b/tcl/board/uptech_2410.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Target Configuration for the Uptech 2410 board. # This configuration should also work on smdk2410, but I haven't tested it yet. # Author: xionglingfeng@Gmail.com diff --git a/tcl/board/vd_a53x2_dap.cfg b/tcl/board/vd_a53x2_dap.cfg new file mode 100644 index 0000000000..bcf8b44098 --- /dev/null +++ b/tcl/board/vd_a53x2_dap.cfg @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm Cortex A53x2 through DAP + +source [find interface/vdebug.cfg] + +set CORES 2 +set CHIPNAME a53 +set ACCESSPORT 0 +set MEMSTART 0x00000000 +set MEMSIZE 0x1000000 +set DBGBASE {0x80810000 0x80910000} +set CTIBASE {0x80820000 0x80920000} + +# vdebug select transport +transport select dapdirect_swd + +# JTAG reset config, frequency and reset delay +adapter speed 50000 +adapter srst delay 5 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_swdp_bfm 10ns + +# DMA Memories to access backdoor (up to 20) +vdebug mem_path tbench.u_memory.mem_array $MEMSTART $MEMSIZE + +swd newdap $CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf + +source [find target/vd_aarch64.cfg] diff --git a/tcl/board/vd_a53x2_jtag.cfg b/tcl/board/vd_a53x2_jtag.cfg index 869bc4db01..0c3eebd7a7 100644 --- a/tcl/board/vd_a53x2_jtag.cfg +++ b/tcl/board/vd_a53x2_jtag.cfg @@ -4,14 +4,17 @@ source [find interface/vdebug.cfg] -set _CORES 2 -set _CHIPNAME a53 -set _MEMSTART 0x00000000 -set _MEMSIZE 0x1000000 -set _CPUTAPID 0x5ba00477 +set CORES 2 +set CHIPNAME a53 +set ACCESSPORT 0 +set MEMSTART 0x00000000 +set MEMSIZE 0x1000000 +set DBGBASE {0x80810000 0x80910000} +set CTIBASE {0x80820000 0x80920000} +set CPUTAPID 0x5ba00477 # vdebug select transport -#transport select jtag +transport select jtag # JTAG reset config, frequency and reset delay reset_config trst_and_srst @@ -21,11 +24,10 @@ adapter srst delay 5 # BFM hierarchical path and input clk period vdebug bfm_path tbench.u_vd_jtag_bfm 10ns -# DMA Memories to access backdoor (up to 4) -vdebug mem_path tbench.u_memory.mem_array $_MEMSTART $_MEMSIZE - -jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +# DMA Memories to access backdoor (up to 20) +vdebug mem_path tbench.u_memory.mem_array $MEMSTART $MEMSIZE +jtag newtap $CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $CPUTAPID jtag arp_init-reset source [find target/vd_aarch64.cfg] diff --git a/tcl/board/vd_a75x4_dap.cfg b/tcl/board/vd_a75x4_dap.cfg new file mode 100644 index 0000000000..5c2a2efe87 --- /dev/null +++ b/tcl/board/vd_a75x4_dap.cfg @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm Cortex A53x2 through DAP + +source [find interface/vdebug.cfg] + +set CORES 4 +set CHIPNAME a75 +set ACCESSPORT 0x00040000 +set MEMSTART 0x00000000 +set MEMSIZE 0x1000000 +set DBGBASE {0x01010000 0x01110000 0x01210000 0x01310000} +set CTIBASE {0x01020000 0x01120000 0x01220000 0x01320000} + +# vdebug select transport +transport select dapdirect_swd + +# JTAG reset config, frequency and reset delay +adapter speed 200000 +adapter srst delay 5 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_dap6_bfm 2250ps + +# DMA Memories to access backdoor (up to 20) +#vdebug mem_path tbench.u_memory.mem_array $_MEMSTART $_MEMSIZE + +swd newdap $CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf + +source [find target/vd_aarch64.cfg] diff --git a/tcl/board/vd_a75x4_jtag.cfg b/tcl/board/vd_a75x4_jtag.cfg new file mode 100644 index 0000000000..c94a71972d --- /dev/null +++ b/tcl/board/vd_a75x4_jtag.cfg @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm Cortex A53x2 through DAP + +source [find interface/vdebug.cfg] + +set CORES 4 +set CHIPNAME a75 +set ACCESSPORT 0x00040000 +set MEMSTART 0x00000000 +set MEMSIZE 0x1000000 +set DBGBASE {0x01010000 0x01110000 0x01210000 0x01310000} +set CTIBASE {0x01020000 0x01120000 0x01220000 0x01320000} +set CPUTAPID 0x4ba06477 + +# vdebug select transport +transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 1500000 +adapter srst delay 5 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_jtag_bfm 333ps + +jtag newtap $CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $CPUTAPID +jtag arp_init-reset + +source [find target/vd_aarch64.cfg] diff --git a/tcl/board/vd_m4_dap.cfg b/tcl/board/vd_m4_dap.cfg new file mode 100644 index 0000000000..5d3605aa37 --- /dev/null +++ b/tcl/board/vd_m4_dap.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm Cortex m4 through DAP + +source [find interface/vdebug.cfg] + +set CHIPNAME m4 +set MEMSTART 0x00000000 +set MEMSIZE 0x10000 + +# vdebug select transport +transport select dapdirect_swd +adapter speed 25000 +adapter srst delay 5 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_swdp_bfm 20ns + +# DMA Memories to access backdoor (up to 20) +vdebug mem_path tbench.u_mcu.u_sys.u_rom.rom $MEMSTART $MEMSIZE + +swd newdap $CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf + +source [find target/vd_cortex_m.cfg] diff --git a/tcl/board/vd_m4_jtag.cfg b/tcl/board/vd_m4_jtag.cfg index ca21476d29..3b32e17be3 100644 --- a/tcl/board/vd_m4_jtag.cfg +++ b/tcl/board/vd_m4_jtag.cfg @@ -4,13 +4,13 @@ source [find interface/vdebug.cfg] -set _CHIPNAME m4 -set _MEMSTART 0x00000000 -set _MEMSIZE 0x10000 -set _CPUTAPID 0x4ba00477 +set CHIPNAME m4 +set MEMSTART 0x00000000 +set MEMSIZE 0x10000 +set CPUTAPID 0x4ba00477 # vdebug select transport -#transport select jtag +transport select jtag # JTAG reset config, frequency and reset delay reset_config trst_and_srst @@ -20,11 +20,10 @@ adapter srst delay 5 # BFM hierarchical path and input clk period vdebug bfm_path tbench.u_vd_jtag_bfm 20ns -# DMA Memories to access backdoor (up to 4) -vdebug mem_path tbench.u_mcu.u_sys.u_rom.rom $_MEMSTART $_MEMSIZE - -jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +# DMA Memories to access backdoor (up to 20) +vdebug mem_path tbench.u_mcu.u_sys.u_rom.rom $MEMSTART $MEMSIZE +jtag newtap $CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $CPUTAPID jtag arp_init-reset source [find target/vd_cortex_m.cfg] diff --git a/tcl/board/vd_m7_jtag.cfg b/tcl/board/vd_m7_jtag.cfg new file mode 100644 index 0000000000..9a89584c83 --- /dev/null +++ b/tcl/board/vd_m7_jtag.cfg @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm Cortex m7 through JTAG + +source [find interface/vdebug.cfg] + +set CHIPNAME m7 +set MEMSTART 0x00000000 +set MEMSIZE 0x100000 +set CPUTAPID 0x0ba02477 + +# vdebug select JTAG transport +transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 50000 +adapter srst delay 5 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_jtag_bfm 10ns + +# DMA Memories to access backdoor (up to 20) +vdebug mem_path tbench.u_mcu.u_sys.u_itcm_ram.Mem $MEMSTART $MEMSIZE + +jtag newtap $CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $CPUTAPID +jtag arp_init-reset + +source [find target/vd_cortex_m.cfg] diff --git a/tcl/board/vd_pulpissimo_jtag.cfg b/tcl/board/vd_pulpissimo_jtag.cfg index 69dd9e6dbe..a3f5a84886 100644 --- a/tcl/board/vd_pulpissimo_jtag.cfg +++ b/tcl/board/vd_pulpissimo_jtag.cfg @@ -9,7 +9,7 @@ set _HARTID 0x20 set _CPUTAPID 0x249511c3 # vdebug select transport -#transport select jtag +transport select jtag # JTAG reset config, frequency and reset delay reset_config trst_and_srst diff --git a/tcl/board/vd_swerv_jtag.cfg b/tcl/board/vd_swerv_jtag.cfg index ff6c6835fc..c5d33f268a 100644 --- a/tcl/board/vd_swerv_jtag.cfg +++ b/tcl/board/vd_swerv_jtag.cfg @@ -11,7 +11,7 @@ set _MEMSTART 0x00000000 set _MEMSIZE 0x10000 # vdebug select transport -#transport select jtag +transport select jtag # JTAG reset config, frequency and reset delay reset_config trst_and_srst diff --git a/tcl/board/vd_xt8_jtag.cfg b/tcl/board/vd_xt8_jtag.cfg new file mode 100644 index 0000000000..867b9e76e5 --- /dev/null +++ b/tcl/board/vd_xt8_jtag.cfg @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Xtensa xt8 through JTAG + +source [find interface/vdebug.cfg] + +set CHIPNAME xt8 +set CPUTAPID 0x120034e5 + +# vdebug select transport +transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 50000 +adapter srst delay 5 + +# BFM hierarchical path and input clk period +vdebug bfm_path Testbench.u_vd_jtag_bfm 10ns + +# DMA Memories to access backdoor, the values come from generated xtensa-core-xt8.cfg +#vdebug mem_path Testbench.Xtsubsystem.Core0.iram0.iram0.mem.dataArray 0x40000000 0x100000 +#vdebug mem_path Testbench.Xtsubsystem.Core0.dram0.dram0.mem.dataArray 0x3ff00000 0x40000 + +# Create Xtensa target first +source [find target/xtensa.cfg] +# Generate [xtensa-core-XXX.cfg] via "xt-gdb --dump-oocd-config" +source [find target/xtensa-core-xt8.cfg] diff --git a/tcl/board/verdex.cfg b/tcl/board/verdex.cfg index dd267fcbea..85111208f1 100644 --- a/tcl/board/verdex.cfg +++ b/tcl/board/verdex.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Config for Gumstix Verdex XM4 and XL6P (PXA270) set CHIPNAME verdex diff --git a/tcl/board/voipac.cfg b/tcl/board/voipac.cfg index c59277ec43..74e651a437 100644 --- a/tcl/board/voipac.cfg +++ b/tcl/board/voipac.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Config for Voipac PXA270/PXA270M module. set CHIPNAME voipac diff --git a/tcl/board/voltcraft_dso-3062c.cfg b/tcl/board/voltcraft_dso-3062c.cfg index f300cf2b62..fd56a817d7 100644 --- a/tcl/board/voltcraft_dso-3062c.cfg +++ b/tcl/board/voltcraft_dso-3062c.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Voltcraft DSO-3062C digital oscilloscope (uses a Samsung S3C2440) # diff --git a/tcl/board/x300t.cfg b/tcl/board/x300t.cfg index 9d9a320fbb..c57c9d9e42 100644 --- a/tcl/board/x300t.cfg +++ b/tcl/board/x300t.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is for the T-Home X300T / X301T IPTV box, # which are based on IPTV reference designs from Kiss/Cisco KMM-3*** # diff --git a/tcl/board/xmc-2go.cfg b/tcl/board/xmc-2go.cfg index 90dbf43660..dd78a12148 100644 --- a/tcl/board/xmc-2go.cfg +++ b/tcl/board/xmc-2go.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Infineon XMC 2Go # diff --git a/tcl/board/xmc1100-boot-kit.cfg b/tcl/board/xmc1100-boot-kit.cfg index 5e7c607344..12ee3e220b 100644 --- a/tcl/board/xmc1100-boot-kit.cfg +++ b/tcl/board/xmc1100-boot-kit.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Infineon XMC1100 Boot Kit # diff --git a/tcl/board/xmc4200-application-kit-actuator.cfg b/tcl/board/xmc4200-application-kit-actuator.cfg index 4e3dde8d76..79befaade1 100644 --- a/tcl/board/xmc4200-application-kit-actuator.cfg +++ b/tcl/board/xmc4200-application-kit-actuator.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Infineon XMC4200 Application Kit - Actuator # diff --git a/tcl/board/xmc4300-relax.cfg b/tcl/board/xmc4300-relax.cfg index bb46ccfd97..b7487936a9 100644 --- a/tcl/board/xmc4300-relax.cfg +++ b/tcl/board/xmc4300-relax.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Infineon XMC4300 Relax EtherCAT Kit # diff --git a/tcl/board/xmc4500-application-kit-general.cfg b/tcl/board/xmc4500-application-kit-general.cfg index 47c8b9982a..dbb532547a 100644 --- a/tcl/board/xmc4500-application-kit-general.cfg +++ b/tcl/board/xmc4500-application-kit-general.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Infineon XMC4500 Application Kit - General Purpose # diff --git a/tcl/board/xmc4500-application-kit-sdram.cfg b/tcl/board/xmc4500-application-kit-sdram.cfg index fe44d01a90..580dfd8a9a 100644 --- a/tcl/board/xmc4500-application-kit-sdram.cfg +++ b/tcl/board/xmc4500-application-kit-sdram.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Infineon XMC4500 Application Kit - SDRAM # diff --git a/tcl/board/xmc4500-relax.cfg b/tcl/board/xmc4500-relax.cfg index 1753b24c1e..1239f04bb7 100644 --- a/tcl/board/xmc4500-relax.cfg +++ b/tcl/board/xmc4500-relax.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Infineon XMC4500 Relax Kit / Relax Lite Kit # diff --git a/tcl/board/xmc4700-relax.cfg b/tcl/board/xmc4700-relax.cfg index 29953f6347..ac8ce26750 100644 --- a/tcl/board/xmc4700-relax.cfg +++ b/tcl/board/xmc4700-relax.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Infineon XMC4700 Relax Lite Kit / Relax Kit for 5V Shields / Relax Kit # diff --git a/tcl/board/xmc4800-relax.cfg b/tcl/board/xmc4800-relax.cfg index fa3fc8f3fb..d63159f89a 100644 --- a/tcl/board/xmc4800-relax.cfg +++ b/tcl/board/xmc4800-relax.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Infineon XMC4800 Relax EtherCAT Kit # diff --git a/tcl/board/xmos_xk-xac-xa8_arm.cfg b/tcl/board/xmos_xk-xac-xa8_arm.cfg index 3d12afb2c5..2e839772e8 100644 --- a/tcl/board/xmos_xk-xac-xa8_arm.cfg +++ b/tcl/board/xmos_xk-xac-xa8_arm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # xCORE-XA Core Module # diff --git a/tcl/board/xtensa-kc705-ext-dap.cfg b/tcl/board/xtensa-kc705-ext-dap.cfg new file mode 100644 index 0000000000..ac92c708d6 --- /dev/null +++ b/tcl/board/xtensa-kc705-ext-dap.cfg @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence KC705 FPGA Development Platform for Xtensa targets +# Can be used with various external adapters that support DAP, e.g. JLink +# + +adapter speed 5000 + +# KC705 supports DAP/JTAG +transport select jtag +set XTENSA_DAP enable +set XTENSA_DAP_BASE 0x10000 + +# Create Xtensa target first +source [find target/xtensa.cfg] diff --git a/tcl/board/xtensa-kc705-ext.cfg b/tcl/board/xtensa-kc705-ext.cfg new file mode 100644 index 0000000000..6be06817c2 --- /dev/null +++ b/tcl/board/xtensa-kc705-ext.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence KC705 FPGA Development Platform for Xtensa targets +# Can be used with various external adapters, e.g. Flyswatter2 or JLink +# + +adapter speed 10000 + +# KC705 supports JTAG only +transport select jtag + +# Create Xtensa target first +source [find target/xtensa.cfg] diff --git a/tcl/board/xtensa-kc705-onboard.cfg b/tcl/board/xtensa-kc705-onboard.cfg new file mode 100644 index 0000000000..f0a616cd7d --- /dev/null +++ b/tcl/board/xtensa-kc705-onboard.cfg @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence KC705 FPGA Development Platform for Xtensa targets +# Can be used with on-board (FTDI) adapter or various external adapters +# + +source [find interface/ftdi/xt_kc705_ml605.cfg] +adapter speed 10000 + +# KC705 supports JTAG only +transport select jtag + +# Create Xtensa target first +source [find target/xtensa.cfg] diff --git a/tcl/board/xtensa-palladium-vdebug-dual.cfg b/tcl/board/xtensa-palladium-vdebug-dual.cfg new file mode 100644 index 0000000000..447bc1fa0c --- /dev/null +++ b/tcl/board/xtensa-palladium-vdebug-dual.cfg @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# for Palladium emulation systems +# + +source [find interface/vdebug.cfg] + +# vdebug select JTAG transport +transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 50000 +adapter srst delay 5 + +# Future improvement: Enable backdoor memory access +# set _MEMSTART 0x00000000 +# set _MEMSIZE 0x100000 + +# BFM hierarchical path and input clk period +vdebug bfm_path Testbench.VJTAG 10ns + +# DMA Memories to access backdoor (up to 4) +# vdebug mem_path tbench.u_mcu.u_sys.u_itcm_ram.Mem $_MEMSTART $_MEMSIZE + +# Configure dual-core TAP chain +set XTENSA_NUM_CORES 2 + +# Create Xtensa target first +source [find target/xtensa.cfg] + +# Configure Xtensa core parameters next +# Generate [xtensa-core-XXX.cfg] via "xt-gdb --dump-oocd-config" diff --git a/tcl/board/xtensa-palladium-vdebug.cfg b/tcl/board/xtensa-palladium-vdebug.cfg new file mode 100644 index 0000000000..f14d92da86 --- /dev/null +++ b/tcl/board/xtensa-palladium-vdebug.cfg @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# for Palladium emulation systems +# + +source [find interface/vdebug.cfg] + +# vdebug select JTAG transport +transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 50000 +adapter srst delay 5 + +# Future improvement: Enable backdoor memory access +# set _MEMSTART 0x00000000 +# set _MEMSIZE 0x100000 + +# BFM hierarchical path and input clk period +vdebug bfm_path Testbench.VJTAG 10ns + +# DMA Memories to access backdoor (up to 4) +# vdebug mem_path tbench.u_mcu.u_sys.u_itcm_ram.Mem $_MEMSTART $_MEMSIZE + +# Create Xtensa target first +source [find target/xtensa.cfg] + +# Configure Xtensa core parameters next +# Generate [xtensa-core-XXX.cfg] via "xt-gdb --dump-oocd-config" diff --git a/tcl/board/xtensa-rt685-ext.cfg b/tcl/board/xtensa-rt685-ext.cfg new file mode 100644 index 0000000000..03edb8d3c6 --- /dev/null +++ b/tcl/board/xtensa-rt685-ext.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP RT6XX Developemnt Platform with Xtensa HiFi DSP +# Can be used with various external adapters that support DAP, e.g. JLink +# + +adapter speed 10000 + +# RT6XX supports SWD only +transport select swd +set XTENSA_DAP enable + +# Create Xtensa target first +source [find target/xtensa.cfg] + +source [find target/xtensa-core-nxp_rt600.cfg] diff --git a/tcl/chip/atmel/at91/aic.tcl b/tcl/chip/atmel/at91/aic.tcl index 8b8a48f3b4..6657b601af 100644 --- a/tcl/chip/atmel/at91/aic.tcl +++ b/tcl/chip/atmel/at91/aic.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set AIC_SMR [expr {$AT91C_BASE_AIC + 0x00000000} ] global AIC_SMR set AIC_SVR [expr {$AT91C_BASE_AIC + 0x00000080} ] diff --git a/tcl/chip/atmel/at91/at91_pio.cfg b/tcl/chip/atmel/at91/at91_pio.cfg index 2373c19fe9..10a1d48c68 100644 --- a/tcl/chip/atmel/at91/at91_pio.cfg +++ b/tcl/chip/atmel/at91/at91_pio.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set PIO_PER 0x00 ;# Enable Register set PIO_PDR 0x04 ;# Disable Register set PIO_PSR 0x08 ;# Status Register diff --git a/tcl/chip/atmel/at91/at91_pmc.cfg b/tcl/chip/atmel/at91/at91_pmc.cfg index dd554ce81e..a75cecd6a1 100644 --- a/tcl/chip/atmel/at91/at91_pmc.cfg +++ b/tcl/chip/atmel/at91/at91_pmc.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set AT91_PMC_SCER [expr {$AT91_PMC + 0x00}] ;# System Clock Enable Register set AT91_PMC_SCDR [expr {$AT91_PMC + 0x04}] ;# System Clock Disable Register diff --git a/tcl/chip/atmel/at91/at91_rstc.cfg b/tcl/chip/atmel/at91/at91_rstc.cfg index 6673fe6452..fd174380a7 100644 --- a/tcl/chip/atmel/at91/at91_rstc.cfg +++ b/tcl/chip/atmel/at91/at91_rstc.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set AT91_RSTC_CR [expr {$AT91_RSTC + 0x00}] ;# Reset Controller Control Register set AT91_RSTC_PROCRST [expr {1 << 0}] ;# Processor Reset set AT91_RSTC_PERRST [expr {1 << 2}] ;# Peripheral Reset diff --git a/tcl/chip/atmel/at91/at91_wdt.cfg b/tcl/chip/atmel/at91/at91_wdt.cfg index 9b4e817e29..8bba62e16f 100644 --- a/tcl/chip/atmel/at91/at91_wdt.cfg +++ b/tcl/chip/atmel/at91/at91_wdt.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set AT91_WDT_CR [expr {$AT91_WDT + 0x00}] ;# Watchdog Control Register set AT91_WDT_WDRSTT [expr {1 << 0}] ;# Restart set AT91_WDT_KEY [expr {0xa5 << 24}] ;# KEY Password diff --git a/tcl/chip/atmel/at91/at91sam7x128.tcl b/tcl/chip/atmel/at91/at91sam7x128.tcl index ce33cf0093..8f468275b8 100644 --- a/tcl/chip/atmel/at91/at91sam7x128.tcl +++ b/tcl/chip/atmel/at91/at91sam7x128.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find bitsbytes.tcl] source [find cpu/arm/arm7tdmi.tcl] source [find memory.tcl] diff --git a/tcl/chip/atmel/at91/at91sam7x256.tcl b/tcl/chip/atmel/at91/at91sam7x256.tcl index dc4918ab17..49d5244cce 100644 --- a/tcl/chip/atmel/at91/at91sam7x256.tcl +++ b/tcl/chip/atmel/at91/at91sam7x256.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find bitsbytes.tcl] source [find cpu/arm/arm7tdmi.tcl] source [find memory.tcl] diff --git a/tcl/chip/atmel/at91/at91sam9261.cfg b/tcl/chip/atmel/at91/at91sam9261.cfg index 61b0c0bf3d..51e7101b5e 100644 --- a/tcl/chip/atmel/at91/at91sam9261.cfg +++ b/tcl/chip/atmel/at91/at91sam9261.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Peripheral identifiers/interrupts. # diff --git a/tcl/chip/atmel/at91/at91sam9261_matrix.cfg b/tcl/chip/atmel/at91/at91sam9261_matrix.cfg index 238e658414..c3656bd41d 100644 --- a/tcl/chip/atmel/at91/at91sam9261_matrix.cfg +++ b/tcl/chip/atmel/at91/at91sam9261_matrix.cfg @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later set AT91_MATRIX_MCFG [expr {$AT91_MATRIX + 0x00}] ;# Master Configuration Register # set AT91_MATRIX_RCB0 [expr {1 << 0}] ;# Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) diff --git a/tcl/chip/atmel/at91/at91sam9263.cfg b/tcl/chip/atmel/at91/at91sam9263.cfg index 8e22eb2db0..600c548616 100644 --- a/tcl/chip/atmel/at91/at91sam9263.cfg +++ b/tcl/chip/atmel/at91/at91sam9263.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Peripheral identifiers/interrupts. # diff --git a/tcl/chip/atmel/at91/at91sam9263_matrix.cfg b/tcl/chip/atmel/at91/at91sam9263_matrix.cfg index b4a07d32df..20a31079a0 100644 --- a/tcl/chip/atmel/at91/at91sam9263_matrix.cfg +++ b/tcl/chip/atmel/at91/at91sam9263_matrix.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set AT91_MATRIX_MCFG0 [expr {$AT91_MATRIX + 0x00}] ;# Master Configuration Register 0 set AT91_MATRIX_MCFG1 [expr {$AT91_MATRIX + 0x04}] ;# Master Configuration Register 1 set AT91_MATRIX_MCFG2 [expr {$AT91_MATRIX + 0x08}] ;# Master Configuration Register 2 diff --git a/tcl/chip/atmel/at91/at91sam9_init.cfg b/tcl/chip/atmel/at91/at91sam9_init.cfg index 27611eb5e6..a64d6eaef1 100644 --- a/tcl/chip/atmel/at91/at91sam9_init.cfg +++ b/tcl/chip/atmel/at91/at91sam9_init.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + uplevel #0 [list source [find chip/atmel/at91/at91sam9_sdramc.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91_pmc.cfg]] uplevel #0 [list source [find chip/atmel/at91/at91_pio.cfg]] diff --git a/tcl/chip/atmel/at91/at91sam9_sdramc.cfg b/tcl/chip/atmel/at91/at91sam9_sdramc.cfg index 7b09369de9..658b6c361a 100644 --- a/tcl/chip/atmel/at91/at91sam9_sdramc.cfg +++ b/tcl/chip/atmel/at91/at91sam9_sdramc.cfg @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later # SDRAM Controller (SDRAMC) registers set AT91_SDRAMC_MR [expr {$AT91_SDRAMC + 0x00}] ;# SDRAM Controller Mode Register diff --git a/tcl/chip/atmel/at91/at91sam9_smc.cfg b/tcl/chip/atmel/at91/at91sam9_smc.cfg index 3a76d147b7..c096c4a2cb 100644 --- a/tcl/chip/atmel/at91/at91sam9_smc.cfg +++ b/tcl/chip/atmel/at91/at91sam9_smc.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set AT91_SMC_READMODE [expr {1 << 0}] ;# Read Mode set AT91_SMC_WRITEMODE [expr {1 << 1}] ;# Write Mode set AT91_SMC_EXNWMODE [expr {3 << 4}] ;# NWAIT Mode diff --git a/tcl/chip/atmel/at91/hardware.cfg b/tcl/chip/atmel/at91/hardware.cfg index a25eab975b..069d4b78c9 100644 --- a/tcl/chip/atmel/at91/hardware.cfg +++ b/tcl/chip/atmel/at91/hardware.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # External Memory Map set AT91_CHIPSELECT_0 0x10000000 set AT91_CHIPSELECT_1 0x20000000 diff --git a/tcl/chip/atmel/at91/pmc.tcl b/tcl/chip/atmel/at91/pmc.tcl index 7cb1d093e3..0f997cad54 100644 --- a/tcl/chip/atmel/at91/pmc.tcl +++ b/tcl/chip/atmel/at91/pmc.tcl @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later if [info exists AT91C_MAINOSC_FREQ] { # user set this... let it be. diff --git a/tcl/chip/atmel/at91/rtt.tcl b/tcl/chip/atmel/at91/rtt.tcl index d49ce71148..1ef83733bb 100644 --- a/tcl/chip/atmel/at91/rtt.tcl +++ b/tcl/chip/atmel/at91/rtt.tcl @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later set RTTC_RTMR [expr {$AT91C_BASE_RTTC + 0x00}] set RTTC_RTAR [expr {$AT91C_BASE_RTTC + 0x04}] diff --git a/tcl/chip/atmel/at91/sam9_smc.cfg b/tcl/chip/atmel/at91/sam9_smc.cfg index 0628d4d18d..87880c7690 100644 --- a/tcl/chip/atmel/at91/sam9_smc.cfg +++ b/tcl/chip/atmel/at91/sam9_smc.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Setup register # # ncs_read_setup diff --git a/tcl/chip/atmel/at91/usarts.tcl b/tcl/chip/atmel/at91/usarts.tcl index 253b7fbfcc..62a651bbdc 100644 --- a/tcl/chip/atmel/at91/usarts.tcl +++ b/tcl/chip/atmel/at91/usarts.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # the DBGU and USARTs are 'almost' indentical' set DBGU_CR [expr {$AT91C_BASE_DBGU + 0x00000000}] set DBGU_MR [expr {$AT91C_BASE_DBGU + 0x00000004}] diff --git a/tcl/chip/st/spear/quirk_no_srst.tcl b/tcl/chip/st/spear/quirk_no_srst.tcl index 551df061d4..e8640f46b5 100644 --- a/tcl/chip/st/spear/quirk_no_srst.tcl +++ b/tcl/chip/st/spear/quirk_no_srst.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Quirks to bypass missing SRST on JTAG connector # EVALSPEAr310 Rev. 2.0 # http://www.st.com/spear diff --git a/tcl/chip/st/spear/spear3xx.tcl b/tcl/chip/st/spear/spear3xx.tcl index 86f2a1d245..474ebe316f 100644 --- a/tcl/chip/st/spear/spear3xx.tcl +++ b/tcl/chip/st/spear/spear3xx.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Generic init scripts for all ST SPEAr3xx family # http://www.st.com/spear # diff --git a/tcl/chip/st/spear/spear3xx_ddr.tcl b/tcl/chip/st/spear/spear3xx_ddr.tcl index 22fe06eaf7..59925672dc 100644 --- a/tcl/chip/st/spear/spear3xx_ddr.tcl +++ b/tcl/chip/st/spear/spear3xx_ddr.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Init scripts to configure DDR controller of SPEAr3xx # http://www.st.com/spear # Original values taken from XLoader source code diff --git a/tcl/chip/st/stm32/stm32.tcl b/tcl/chip/st/stm32/stm32.tcl index 94b1935dde..3826a57af5 100644 --- a/tcl/chip/st/stm32/stm32.tcl +++ b/tcl/chip/st/stm32/stm32.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find bitsbytes.tcl] source [find cpu/arm/cortex_m3.tcl] source [find memory.tcl] diff --git a/tcl/chip/st/stm32/stm32_rcc.tcl b/tcl/chip/st/stm32/stm32_rcc.tcl index fa652a2e65..afa4cbfd6a 100644 --- a/tcl/chip/st/stm32/stm32_rcc.tcl +++ b/tcl/chip/st/stm32/stm32_rcc.tcl @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later set RCC_CR [expr {$RCC_BASE + 0x00}] set RCC_CFGR [expr {$RCC_BASE + 0x04}] diff --git a/tcl/chip/st/stm32/stm32_regs.tcl b/tcl/chip/st/stm32/stm32_regs.tcl index 6ae2f63f6b..07ff1aa294 100644 --- a/tcl/chip/st/stm32/stm32_regs.tcl +++ b/tcl/chip/st/stm32/stm32_regs.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # /* Peripheral and SRAM base address in the alias region */ set PERIPH_BB_BASE 0x42000000 set SRAM_BB_BASE 0x22000000 diff --git a/tcl/chip/ti/lm3s/lm3s.tcl b/tcl/chip/ti/lm3s/lm3s.tcl index 42da8c668a..324aad0650 100644 --- a/tcl/chip/ti/lm3s/lm3s.tcl +++ b/tcl/chip/ti/lm3s/lm3s.tcl @@ -1 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find chip/ti/lm3s/lm3s_regs.tcl] diff --git a/tcl/chip/ti/lm3s/lm3s_regs.tcl b/tcl/chip/ti/lm3s/lm3s_regs.tcl index cb20812db8..1e86e29e82 100644 --- a/tcl/chip/ti/lm3s/lm3s_regs.tcl +++ b/tcl/chip/ti/lm3s/lm3s_regs.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #***************************************************************************** # # The following are defines for the System Control register addresses. diff --git a/tcl/cpld/altera-5m570z-cpld.cfg b/tcl/cpld/altera-5m570z-cpld.cfg index 22a422c48b..4504a80648 100644 --- a/tcl/cpld/altera-5m570z-cpld.cfg +++ b/tcl/cpld/altera-5m570z-cpld.cfg @@ -1,6 +1,9 @@ -# Altera MAXV 5M24OZ/5M570Z CPLD -# see MAX V Device Handbook -# Table 6-3: 32-Bit MAX V Device IDCODE -# Version Part Number Manuf. ID LSB -# 0000 0010 0000 1010 0111 000 0110 1110 1 -jtag newtap 5m570z tap -expected-id 0x020a60dd -irlen 10 +# SPDX-License-Identifier: GPL-2.0-or-later + +# file altera-5m570z-cpld.cfg replaced by altera-maxv.cfg +echo "DEPRECATED: use altera-maxv.cfg instead of deprecated altera-5m570z-cpld.cfg" + +#just to be backward compatible: +#tap will be 5m570z.tap instead of maxv.tap: +set CHIPNAME 5m570z +source [find cpld/altera-maxv.cfg] diff --git a/tcl/cpld/altera-epm240.cfg b/tcl/cpld/altera-epm240.cfg index ece02bbefc..185925a16f 100644 --- a/tcl/cpld/altera-epm240.cfg +++ b/tcl/cpld/altera-epm240.cfg @@ -1,22 +1,12 @@ -# Altera MAXII EPM240T100C CPLD +# SPDX-License-Identifier: GPL-2.0-or-later -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME epm240 -} +# file altera-epm240.cfg replaced by altera-maxii.cfg +echo "DEPRECATED: use altera-maxii.cfg instead of deprecated altera-epm240.cfg" -# see MAX II Device Handbook -# Table 3-3: 32-Bit MAX II Device IDCODE -# Version Part Number Manuf. ID LSB -# 0000 0010 0000 1010 0001 000 0110 1110 1 -jtag newtap $_CHIPNAME tap -irlen 10 \ - -expected-id 0x020a10dd \ - -expected-id 0x020a20dd \ - -expected-id 0x020a30dd \ - -expected-id 0x020a40dd \ - -expected-id 0x020a50dd \ - -expected-id 0x020a60dd +#just to be backward compatible: +#tap will be epm240.tap instead of maxii.tap: +set CHIPNAME epm240 +source [find cpld/altera-maxii.cfg] # 200ns seems like a good speed # c.f. Table 5-34: MAX II JTAG Timing Parameters diff --git a/tcl/cpld/altera-max10.cfg b/tcl/cpld/altera-max10.cfg new file mode 100644 index 0000000000..a2ed00ac84 --- /dev/null +++ b/tcl/cpld/altera-max10.cfg @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# see MAX 10 FPGA Device Architecture +# Table 3-1: IDCODE Information for MAX 10 Devices +# Intel MAX 10M02 0x31810dd +# Intel MAX 10M04 0x318a0dd +# Intel MAX 10M08 0x31820dd +# Intel MAX 10M16 0x31830dd +# Intel MAX 10M25 0x31840dd +# Intel MAX 10M40 0x318d0dd +# Intel MAX 10M50 0x31850dd +# Intel MAX 10M02 0x31010dd +# Intel MAX 10M04 0x310a0dd +# Intel MAX 10M08 0x31020dd +# Intel MAX 10M16 0x31030dd +# Intel MAX 10M25 0x31040dd +# Intel MAX 10M40 0x310d0dd +# Intel MAX 10M50 0x31050dd + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME max10 +} + +jtag newtap $_CHIPNAME tap -irlen 10 -expected-id 0x31810dd -expected-id 0x318a0dd \ + -expected-id 0x31820dd -expected-id 0x31830dd -expected-id 0x31840dd \ + -expected-id 0x318d0dd -expected-id 0x31850dd -expected-id 0x31010dd \ + -expected-id 0x310a0dd -expected-id 0x31020dd -expected-id 0x31030dd \ + -expected-id 0x31040dd -expected-id 0x310d0dd -expected-id 0x31050dd diff --git a/tcl/cpld/altera-maxii.cfg b/tcl/cpld/altera-maxii.cfg new file mode 100644 index 0000000000..2dee37f41c --- /dev/null +++ b/tcl/cpld/altera-maxii.cfg @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Altera MAXII CPLD + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME maxii +} + +# see MAX II Device Handbook +# Table 3-3: 32-Bit MAX II Device IDCODE +# Version Part Number Manuf. ID LSB +# 0000 0010 0000 1010 0001 000 0110 1110 1 +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x020a10dd \ + -expected-id 0x020a20dd \ + -expected-id 0x020a30dd \ + -expected-id 0x020a40dd \ + -expected-id 0x020a50dd \ + -expected-id 0x020a60dd diff --git a/tcl/cpld/altera-maxv.cfg b/tcl/cpld/altera-maxv.cfg new file mode 100644 index 0000000000..03fad076f1 --- /dev/null +++ b/tcl/cpld/altera-maxv.cfg @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Altera MAXV 5M24OZ/5M570Z CPLD +# see MAX V Device Handbook +# Table 6-3: 32-Bit MAX V Device IDCODE +# 5M40Z 5M80Z 5M160Z 5M240Z: 0x020A50DD +# 5M570Z: 0x020A60DD +# 5M1270Z: 0x020A30DD +# 5M1270Z 5M2210Z: 0x020A40DD + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME maxv +} + +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x020A50DD -expected-id 0x020A60DD \ + -expected-id 0x020A30DD -expected-id 0x020A40DD diff --git a/tcl/cpld/jtagspi.cfg b/tcl/cpld/jtagspi.cfg index e720c3959e..a7f02b9770 100644 --- a/tcl/cpld/jtagspi.cfg +++ b/tcl/cpld/jtagspi.cfg @@ -1,7 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set _USER1 0x02 if { [info exists JTAGSPI_IR] } { set _JTAGSPI_IR $JTAGSPI_IR +} elseif {[info exists JTAGSPI_CHAIN_ID]} { + set _JTAGSPI_CHAIN_ID $JTAGSPI_CHAIN_ID } else { set _JTAGSPI_IR $_USER1 } @@ -19,13 +23,29 @@ if { [info exists FLASHNAME] } { } target create $_TARGETNAME testee -chain-position $_CHIPNAME.tap -flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME $_JTAGSPI_IR +if { [info exists _JTAGSPI_IR] } { + flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME $_JTAGSPI_IR +} else { + flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME -pld $_JTAGSPI_CHAIN_ID +} + +# initialize jtagspi flash +# chain_id: identifier of pld (you can get a list with 'pld devices') +# proxy_bit: file with bitstream connecting JTAG and SPI interface in the PLD. +# release_from_pwr_down_cmd: optional, command sent to spi flash before probing. +# ex: 0xAB to release from power-dowm. +# Just omit it to not send a command. -proc jtagspi_init {chain_id proxy_bit} { +proc jtagspi_init {chain_id proxy_bit {release_from_pwr_down_cmd -1}} { # load proxy bitstream $proxy_bit and probe spi flash global _FLASHNAME - pld load $chain_id $proxy_bit + if { $proxy_bit ne "" } { + pld load $chain_id $proxy_bit + } reset halt + if {$release_from_pwr_down_cmd != -1} { + jtagspi cmd $_FLASHNAME 0 $release_from_pwr_down_cmd + } flash probe $_FLASHNAME } diff --git a/tcl/cpld/lattice-lc4032ze.cfg b/tcl/cpld/lattice-lc4032ze.cfg index d4a85eb794..479180f28f 100644 --- a/tcl/cpld/lattice-lc4032ze.cfg +++ b/tcl/cpld/lattice-lc4032ze.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Lattice ispMACH 4000ZE family, device LC4032ZE # just configure a tap jtag newtap LC4032ZE tap -irlen 8 -expected-id 0x01806043 diff --git a/tcl/cpld/xilinx-xc3s.cfg b/tcl/cpld/xilinx-xc3s.cfg new file mode 100644 index 0000000000..a8867395b1 --- /dev/null +++ b/tcl/cpld/xilinx-xc3s.cfg @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx spartan3 +# https://docs.xilinx.com/v/u/en-US/ug332 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc3s +} + +# the 4 top bits (28:31) are the die stepping. ignore it. +jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ + -expected-id 0x01414093 \ + -expected-id 0x0141C093 \ + -expected-id 0x01428093 \ + -expected-id 0x01434093 \ + -expected-id 0x01440093 \ + -expected-id 0x01448093 \ + -expected-id 0x01450093 \ + -expected-id 0x01C10093 \ + -expected-id 0x01C1A093 \ + -expected-id 0x01C22093 \ + -expected-id 0x01C2E093 \ + -expected-id 0x01C3A093 \ + -expected-id 0x0140C093 \ + -expected-id 0x02210093 \ + -expected-id 0x02218093 \ + -expected-id 0x02220093 \ + -expected-id 0x02228093 \ + -expected-id 0x02230093 \ + -expected-id 0x02610093 \ + -expected-id 0x02618093 \ + -expected-id 0x02620093 \ + -expected-id 0x02628093 \ + -expected-id 0x02630093 \ + -expected-id 0x03840093 \ + -expected-id 0x0384e093 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap diff --git a/tcl/cpld/xilinx-xc4v.cfg b/tcl/cpld/xilinx-xc4v.cfg new file mode 100644 index 0000000000..3eb46ebc44 --- /dev/null +++ b/tcl/cpld/xilinx-xc4v.cfg @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx virtex 4 +# https://docs.xilinx.com/v/u/en-US/ug071 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc4v +} + +# the 4 top bits (28:31) are the die stepping. ignore it. +jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version \ + -expected-id 0x01658093 \ + -expected-id 0x01E58093 \ + -expected-id 0x0167C093 \ + -expected-id 0x02068093 \ + -expected-id 0x01E64093 \ + -expected-id 0x016A4093 \ + -expected-id 0x02088093 \ + -expected-id 0x016B4093 \ + -expected-id 0x020B0093 \ + -expected-id 0x016D8093 \ + -expected-id 0x01700093 \ + -expected-id 0x01718093 \ + -expected-id 0x01734093 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap +# cfg_out cfg_in jprogb jstart jshutdown user1-4 +virtex2 set_instr_codes $_CHIPNAME.pld 0x3C4 0x3C5 0x3CB 0x3CC 0x3CD +virtex2 set_user_codes $_CHIPNAME.pld 0x3C2 0x3C3 0x3E2 0x3E3 diff --git a/tcl/cpld/xilinx-xc4vfx_40_60_100_140.cfg b/tcl/cpld/xilinx-xc4vfx_40_60_100_140.cfg new file mode 100644 index 0000000000..14dde02703 --- /dev/null +++ b/tcl/cpld/xilinx-xc4vfx_40_60_100_140.cfg @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx virtex 4 +# https://docs.xilinx.com/v/u/en-US/ug071 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc4vfx +} + +# the 4 top bits (28:31) are the die stepping. ignore it. +jtag newtap $_CHIPNAME tap -irlen 14 -ignore-version \ + -expected-id 0x01E8C093 \ + -expected-id 0x01EB4093 \ + -expected-id 0x01EE4093 \ + -expected-id 0x01F14093 \ + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap +# cfg_out cfg_in jprogb jstart jshutdown user1-4 +virtex2 set_instr_codes $_CHIPNAME.pld 0x3FC4 0x3FC5 0x3FCB 0x3FCC 0x3FCD +virtex2 set_user_codes $_CHIPNAME.pld 0x3FC2 0x3FC3 0x3FE2 0x3FE3 diff --git a/tcl/cpld/xilinx-xc5v.cfg b/tcl/cpld/xilinx-xc5v.cfg new file mode 100644 index 0000000000..f88bbc1e81 --- /dev/null +++ b/tcl/cpld/xilinx-xc5v.cfg @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx virtex 5 +# https://docs.xilinx.com/v/u/en-US/ug191 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc5v +} + +# the 4 top bits (28:31) are the die stepping. ignore it. +jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version \ + -expected-id 0x0286E093 \ + -expected-id 0x02896093 \ + -expected-id 0x028AE093 \ + -expected-id 0x028D6093 \ + -expected-id 0x028EC093 \ + -expected-id 0x0290C093 \ + -expected-id 0x0295C093 \ + -expected-id 0x02A56093 \ + -expected-id 0x02A6E093 \ + -expected-id 0x02A96093 \ + -expected-id 0x02AAE093 \ + -expected-id 0x02AD6093 \ + -expected-id 0x02AEC093 \ + -expected-id 0x02B0C093 \ + -expected-id 0x02B5C093 \ + -expected-id 0x02E72093 \ + -expected-id 0x02E9A093 \ + -expected-id 0x02ECE093 \ + -expected-id 0x02F3E093 \ + -expected-id 0x03276093 \ + -expected-id 0x032C6093 \ + -expected-id 0x04502093 \ + -expected-id 0x0453E093 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap +# cfg_out cfg_in jprogb jstart jshutdown user1-4 +virtex2 set_instr_codes $_CHIPNAME.pld 0x3C4 0x3C5 0x3CB 0x3CC 0x3CD +virtex2 set_user_codes $_CHIPNAME.pld 0x3C2 0x3C3 0x3E2 0x3E3 diff --git a/tcl/cpld/xilinx-xc5vfx_100_130_200.cfg b/tcl/cpld/xilinx-xc5vfx_100_130_200.cfg new file mode 100644 index 0000000000..7420233f48 --- /dev/null +++ b/tcl/cpld/xilinx-xc5vfx_100_130_200.cfg @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx virtex 5 +# https://docs.xilinx.com/v/u/en-US/ug191 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc5vfx +} + +# the 4 top bits (28:31) are the die stepping. ignore it. +jtag newtap $_CHIPNAME tap -irlen 14 -ignore-version \ + -expected-id 0x032D8093 \ + -expected-id 0x03300093 \ + -expected-id 0x03334093 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap +# cfg_out cfg_in jprogb jstart jshutdown user1-4 +virtex2 set_instr_codes $_CHIPNAME.pld 0x3FC4 0x3FC5 0x3FCB 0x3FCC 0x3FCD +virtex2 set_user_codes $_CHIPNAME.pld 0x3FC2 0x3FC3 0x3FE2 0x3FE3 diff --git a/tcl/cpld/xilinx-xc6s.cfg b/tcl/cpld/xilinx-xc6s.cfg index 9ce7ad4918..92b2605774 100644 --- a/tcl/cpld/xilinx-xc6s.cfg +++ b/tcl/cpld/xilinx-xc6s.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # xilinx spartan6 # http://www.xilinx.com/support/documentation/user_guides/ug380.pdf @@ -23,7 +25,8 @@ jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ -expected-id 0x0401D093 \ -expected-id 0x0403D093 -pld device virtex2 $_CHIPNAME.tap +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap +virtex2 set_user_codes $_CHIPNAME.pld 0x02 0x03 0x1A 0x1B set XC6S_CFG_IN 0x05 set XC6S_JSHUTDOWN 0x0d @@ -32,6 +35,7 @@ set XC6S_JSTART 0x0c set XC6S_BYPASS 0x3f proc xc6s_program {tap} { + echo "DEPRECATED! use 'virtex2 program ...' not 'xc6s_program'" global XC6S_JSHUTDOWN XC6S_JPROGRAM XC6S_JSTART XC6S_BYPASS irscan $tap $XC6S_JSHUTDOWN irscan $tap $XC6S_JPROGRAM @@ -41,6 +45,7 @@ proc xc6s_program {tap} { #xtp038 and xc3sprog approach proc xc6s_program_iprog {tap} { + echo "DEPRECATED! use 'virtex2 program ...' not 'xc6s_program_iprog'" global XC6S_JSHUTDOWN XC6S_JSTART XC6S_BYPASS XC6S_CFG_IN irscan $tap $XC6S_JSHUTDOWN runtest 16 diff --git a/tcl/cpld/xilinx-xc6v.cfg b/tcl/cpld/xilinx-xc6v.cfg new file mode 100644 index 0000000000..d37439c984 --- /dev/null +++ b/tcl/cpld/xilinx-xc6v.cfg @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx virtex 6 +# https://www.xilinx.com/support/documentation/user_guides/ug360.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc6v +} + +# the 4 top bits (28:31) are the die stepping. ignore it. +jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version \ + -expected-id 0x042A2093 \ + -expected-id 0x042A4093 \ + -expected-id 0x042A8093 \ + -expected-id 0x042AC093 \ + -expected-id 0x04244093 \ + -expected-id 0x0424A093 \ + -expected-id 0x0424C093 \ + -expected-id 0x04250093 \ + -expected-id 0x04252093 \ + -expected-id 0x04256093 \ + -expected-id 0x0423A093 \ + -expected-id 0x04286093 \ + -expected-id 0x04288093 \ + -expected-id 0x042C4093 \ + -expected-id 0x042CA093 \ + -expected-id 0x042CC093 \ + -expected-id 0x042D0093 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap +# cfg_out cfg_in jprogb jstart jshutdown user1-4 +virtex2 set_instr_codes $_CHIPNAME.pld 0x3C4 0x3C5 0x3CB 0x3CC 0x3CD +virtex2 set_user_codes $_CHIPNAME.pld 0x3C2 0x3C3 0x3E2 0x3E3 diff --git a/tcl/cpld/xilinx-xc7.cfg b/tcl/cpld/xilinx-xc7.cfg index 4c0502c5db..f5b0733749 100644 --- a/tcl/cpld/xilinx-xc7.cfg +++ b/tcl/cpld/xilinx-xc7.cfg @@ -1,4 +1,6 @@ -# xilinx series 7 (artix, kintex, virtex) +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx series 7 (spartan, artix, kintex, virtex) # http://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf if { [info exists CHIPNAME] } { @@ -31,21 +33,15 @@ jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ -expected-id 0x03752093 \ -expected-id 0x03751093 \ -expected-id 0x03671093 \ - -expected-id 0x036B3093 \ - -expected-id 0x036B7093 \ - -expected-id 0x036BB093 \ - -expected-id 0x036BF093 \ -expected-id 0x03667093 \ -expected-id 0x03682093 \ -expected-id 0x03687093 \ -expected-id 0x03692093 \ -expected-id 0x03691093 \ - -expected-id 0x03696093 \ - -expected-id 0x036D5093 \ - -expected-id 0x036D9093 \ - -expected-id 0x036DB093 + -expected-id 0x03696093 -pld device virtex2 $_CHIPNAME.tap 1 +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart +virtex2 set_user_codes $_CHIPNAME.pld 0x02 0x03 0x22 0x23 set XC7_JSHUTDOWN 0x0d set XC7_JPROGRAM 0x0b @@ -53,6 +49,7 @@ set XC7_JSTART 0x0c set XC7_BYPASS 0x3f proc xc7_program {tap} { + echo "DEPRECATED! use 'virtex2 program ...' not 'xc7_program'" global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS irscan $tap $XC7_JSHUTDOWN irscan $tap $XC7_JPROGRAM diff --git a/tcl/cpld/xilinx-xc7v.cfg b/tcl/cpld/xilinx-xc7v.cfg new file mode 100644 index 0000000000..8385948323 --- /dev/null +++ b/tcl/cpld/xilinx-xc7v.cfg @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx series 7 (artix, kintex, virtex) +# http://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf +# https://bsdl.info/view.htm?sid=08e275a0cd3ac38988ca59b002289d77 +# https://bsdl.info/view.htm?sid=44dae65d3cf9593188ca59b002289d77 +# +# this config file is for XC7VX1140T and XC7V2000T only. +# for other virtex-7 devices use xilinx-xc7vh580t.cfg or xilinx-xc7vh870t.cfg or xilinx-xc7.cfg + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc7v +} + +#0x036D5093: XC7VX1140T +#0x036By093: XC7V2000T +#y = xx11 = 3, 7, B or F + +jtag newtap $_CHIPNAME tap -irlen 24 -ignore-version \ + -expected-id 0x036B3093 -expected-id 0x036B7093 \ + -expected-id 0x036BB093 -expected-id 0x036BF093 \ + -expected-id 0x036D5093 + +#CFG_OUT_SLR0 0x124924 +#CFG_IN_SLR0 0x164924 +#CFG_OUT_SLR1 0x904924 +#CFG_IN_SLR1 0x905924 +#CFG_OUT_SLR2 0x924124 +#CFG_IN_SLR2 0x924164 +#CFG_OUT_SLR3 0x924904 +#CFG_IN_SLR3 0x924905 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart +# cfg_out cfg_in jprogb jstart jshutdown +virtex2 set_instr_codes $_CHIPNAME.pld 0x3FFFFF 0x3FFFFF 0x2CB2CB 0x30C30C 0x34D34D diff --git a/tcl/cpld/xilinx-xc7vh580t.cfg b/tcl/cpld/xilinx-xc7vh580t.cfg new file mode 100644 index 0000000000..3748049803 --- /dev/null +++ b/tcl/cpld/xilinx-xc7vh580t.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx series 7 (artix, kintex, virtex) +# http://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf +# https://bsdl.info/view.htm?sid=65c6b2cfe1467b4988ca59b002289d77 +# +# this config file is for xc7vh580t only. +# for other virtex-7 devices use xilinx-xc7vh870t.cfg or xilinx-xc7v.cfg or xilinx-xc7.cfg + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc7vh580t +} + +jtag newtap $_CHIPNAME tap -irlen 22 -ignore-version -expected-id 0x036D9093 + +#CFG_OUT_SLR0 0x0492A0 +#CFG_IN_SLR0 0x0592A0 +#CFG_OUT_SLR1 0x2412A0 +#CFG_IN_SLR1 0x2416A0 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart +# cfg_out cfg_in jprogb jstart jshutdown +virtex2 set_instr_codes $_CHIPNAME.pld 0x3FFFFF 0x3FFFFF 0x0B2EA0 0x0C32A0 0x0D36A0 diff --git a/tcl/cpld/xilinx-xc7vh870t.cfg b/tcl/cpld/xilinx-xc7vh870t.cfg new file mode 100644 index 0000000000..25e2e63615 --- /dev/null +++ b/tcl/cpld/xilinx-xc7vh870t.cfg @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# xilinx series 7 (artix, kintex, virtex) +# http://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf +# https://bsdl.info/view.htm?sid=d9ff0bb764df004588ca59b002289d77 +# +# this config file is for xc7vh870t only. +# for other virtex-7 devices use xilinx-xc7vh580t.cfg or xilinx-xc7v.cfg or xilinx-xc7.cfg +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc7vh870t +} + +jtag newtap $_CHIPNAME tap -irlen 38 -ignore-version -expected-id 0x036DB093 + +#CFG_OUT_SLR0 0x0492A092A0 +#CFG_IN_SLR0 0x0592A092A0 +#CFG_OUT_SLR1 0x2412A092A0 +#CFG_IN_SLR1 0x2416A092A0 +#CFG_OUT_SLR2 0x2492A012A0 +#CFG_IN_SLR2 0x2492A016A0 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart +# cfg_out cfg_in jprogb jstart jshutdown +virtex2 set_instr_codes $_CHIPNAME.pld 0x3FFFFFFFFF 0x3FFFFFFFFF 0x0B2EA02EA0 0x0C32A032A0 0x0D36A036A0 diff --git a/tcl/cpld/xilinx-xcf-p.cfg b/tcl/cpld/xilinx-xcf-p.cfg index 8e0a26c6f7..7b6d384a7c 100644 --- a/tcl/cpld/xilinx-xcf-p.cfg +++ b/tcl/cpld/xilinx-xcf-p.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { diff --git a/tcl/cpld/xilinx-xcf-s.cfg b/tcl/cpld/xilinx-xcf-s.cfg index a3c79a3854..417ecff690 100644 --- a/tcl/cpld/xilinx-xcf-s.cfg +++ b/tcl/cpld/xilinx-xcf-s.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { diff --git a/tcl/cpld/xilinx-xcr3256.cfg b/tcl/cpld/xilinx-xcr3256.cfg index e5611f1ec9..4668e54789 100644 --- a/tcl/cpld/xilinx-xcr3256.cfg +++ b/tcl/cpld/xilinx-xcr3256.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #xilinx coolrunner xcr3256 #simple device - just configure a tap jtag newtap xcr tap -irlen 5 -ircapture 0x01 -irmask 0x1f -expected-id 0x0494c093 diff --git a/tcl/cpld/xilinx-xcu.cfg b/tcl/cpld/xilinx-xcu.cfg index 3270597110..4d7f26c889 100644 --- a/tcl/cpld/xilinx-xcu.cfg +++ b/tcl/cpld/xilinx-xcu.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Xilinx Ultrascale (Kintex, Virtex, Zynq) # https://www.xilinx.com/support/documentation/user_guides/ug570-ultrascale-configuration.pdf @@ -7,35 +9,64 @@ if { [info exists CHIPNAME] } { set _CHIPNAME xcu } -# The cvarious chips in the Ultrascale family have different IR length. +# The various chips in the Ultrascale family have different IR length. # Set $CHIP before including this file to determine the device. array set _XCU_DATA { - XCKU025 {0x03824093 6} - XCKU035 {0x03823093 6} - XCKU040 {0x03822093 6} - XCKU060 {0x03919093 6} - XCKU095 {0x03844093 6} - XCKU3P {0x04A63093 6} - XCKU5P {0x04A62093 6} - XCKU9P {0x0484A093 6} - XCKU11P {0x04A4E093 6} - XCKU13P {0x04A52093 6} - XCKU15P {0x04A56093 6} - XCVU065 {0x03939093 6} - XCVU080 {0x03843093 6} - XCVU095 {0x03842093 6} - XCVU3P {0x04B39093 6} - XCKU085 {0x0380F093 12} - XCKU115 {0x0390D093 12} - XCVU125 {0x0392D093 12} - XCVU5P {0x04B2B093 12} - XCVU7P {0x04B29093 12} - XCVU160 {0x03933093 18} - XCVU190 {0x03931093 18} - XCVU440 {0x0396D093 18} - XCVU9P {0x04B31093 18} - XCVU11P {0x04B49093 18} - XCVU13P {0x04B51093 24} + XCKU025 {0x03824093 6} + XCKU035 {0x03823093 6} + XCKU040 {0x03822093 6} + XCKU060 {0x03919093 6} + XCKU060_CIV {0x0381b093 6} + XCKU095 {0x03844093 6} + XCKU095_CIV {0x03845093 6} + XCKU3P {0x04A63093 6} + XCKU5P {0x04A62093 6} + XCKU9P {0x0484A093 6} + XCKU11P {0x04A4E093 6} + XCKU11P_CIV {0x04A51093 6} + XCKU13P {0x04A52093 6} + XCKU15P {0x04A56093 6} + XCKU15P_CIV {0x04A59093 6} + XCVU065 {0x03939093 6} + XCVU065_CIV {0x0393b093 6} + XCVU080 {0x03843093 6} + XCVU080_CIV {0x03845093 6} + XCVU095 {0x03842093 6} + XCVU2P {0x04aea093 6} + XCVU3P {0x04B39093 6} + XCVU3P_CIV {0x04b3d093 6} + XCAU10P {0x04AC4033 6} + XCAU10P_FFVB676 {0x04AC4093 6} + XCAU15P {0x04AC2033 6} + XCAU15P_FFVB676 {0x04AC2093 6} + XCAU20P {0x04A65093 6} + XCAU25P {0x04A64093 6} + XCKU5P_CIV {0x04A64093 6} + XCKU19P {0x04ACF093 6} + XCKU19P_CIV {0x04AD3093 6} + XCKU085 {0x0380F093 12} + XCKU115 {0x0390D093 12} + XCVU125 {0x0392D093 12} + XCVU125_CIV {0x0392f093 12} + XCVU5P {0x04B2B093 12} + XCVU5P_CIV {0x04b2f093 12} + XCVU7P {0x04B29093 12} + XCVU7P_CIV {0x04b2d093 12} + XCVU160 {0x03933093 18} + XCVU190 {0x03931093 18} + XCVU440 {0x0396D093 18} + XCVU440_CIV {0x0396f093 18} + XCVU9P {0x04B31093 18} + XCVU9P_CIV {0x04b35093 18} + XCVU11P {0x04B49093 18} + XCVU11P_CIV {0x04b4f093 18} + XCU200_FSGD2104 {0x04b37093 18} + XCU250 {0x04b57093 24} + XCVU13P {0x04B51093 24} + XCVU13P_CIV {0x04b55093 24} + XCVU15P {0x04ba3093 24} + XCVU19P {0x04ba1093 24} + XCVU19P_CIV {0x04ba5093 24} } if { ![info exists CHIP] } { @@ -52,7 +83,25 @@ set _IRLEN [lindex $_XCU_DATA($CHIP) 1] # the 4 top bits (28:31) are the die stepping/revisions. ignore it. jtag newtap $_CHIPNAME tap -irlen $_IRLEN -ignore-version -expected-id $_EXPID -pld device virtex2 $_CHIPNAME.tap 1 +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap -no_jstart + +# set the correct instruction codes for jtag hub and +# at least the right code for jprogb, jstart and jshutdown for SSI devices +if { $_IRLEN == 6 } { + virtex2 set_user_codes $_CHIPNAME.pld 0x2 0x3 0x22 0x23 +} elseif {$_IRLEN == 12 } { + puts "loading bitstream through jtag will not work, but reprogram (refresh)" + virtex2 set_instr_codes $_CHIPNAME.pld 0x905 0x904 0x2cb 0x30c 0x34d + virtex2 set_user_codes $_CHIPNAME.pld 0x0a4 0x0e4 0x8a4 0x8e4 +} elseif {$_IRLEN == 18 } { + puts "loading bitstream through jtag will not work, but reprogram (refresh)" + virtex2 set_instr_codes $_CHIPNAME.pld 0x24905 0x24904 0x0b2cb 0x0c30c 0x0d34d + virtex2 set_user_codes $_CHIPNAME.pld 0x000a4 0x000e4 0x008a4 0x008e4 +} else { + puts "loading bitstream through jtag will not work, but reprogram (refresh)" + virtex2 set_instr_codes $_CHIPNAME.pld 0x924905 0x924904 0x2cb2cb 0x30c30c 0x34d34d + virtex2 set_user_codes $_CHIPNAME.pld 0x0a4924 0x0e4924 0x8a4924 0x8e4924 +} set XCU_JSHUTDOWN 0x0d set XCU_JPROGRAM 0x0b @@ -60,6 +109,7 @@ set XCU_JSTART 0x0c set XCU_BYPASS 0x3f proc xcu_program {tap} { + echo "DEPRECATED! use 'virtex2 program ...' not 'xcu_program'" global XCU_JSHUTDOWN XCU_JPROGRAM XCU_JSTART XCU_BYPASS irscan $tap $XCU_JSHUTDOWN irscan $tap $XCU_JPROGRAM diff --git a/tcl/cpu/arc/common.tcl b/tcl/cpu/arc/common.tcl index b31e31a34e..e0de70bc0b 100644 --- a/tcl/cpu/arc/common.tcl +++ b/tcl/cpu/arc/common.tcl @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (C) 2015, 2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> -# -# SPDX-License-Identifier: GPL-2.0-or-later # Things common to all ARCs diff --git a/tcl/cpu/arc/em.tcl b/tcl/cpu/arc/em.tcl index 595a351308..13c5b437c0 100644 --- a/tcl/cpu/arc/em.tcl +++ b/tcl/cpu/arc/em.tcl @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (C) 2015, 2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> -# -# SPDX-License-Identifier: GPL-2.0-or-later source [find cpu/arc/v2.tcl] diff --git a/tcl/cpu/arc/hs.tcl b/tcl/cpu/arc/hs.tcl index 181f993bf0..28e04f952e 100644 --- a/tcl/cpu/arc/hs.tcl +++ b/tcl/cpu/arc/hs.tcl @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (C) 2015, 2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> -# -# SPDX-License-Identifier: GPL-2.0-or-later source [find cpu/arc/v2.tcl] diff --git a/tcl/cpu/arc/v2.tcl b/tcl/cpu/arc/v2.tcl index 364e8af37e..b24a67d0bd 100644 --- a/tcl/cpu/arc/v2.tcl +++ b/tcl/cpu/arc/v2.tcl @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (C) 2015, 2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> -# -# SPDX-License-Identifier: GPL-2.0-or-later source [find cpu/arc/common.tcl] @@ -173,8 +173,8 @@ proc arc_v2_init_regs { } { r19 19 uint32 r20 20 uint32 r21 21 uint32 - r22 23 uint32 - r23 24 uint32 + r22 22 uint32 + r23 23 uint32 r24 24 uint32 r25 25 uint32 gp 26 data_ptr diff --git a/tcl/cpu/arm/arm7tdmi.tcl b/tcl/cpu/arm/arm7tdmi.tcl index a1d4a1f462..e407a2396c 100644 --- a/tcl/cpu/arm/arm7tdmi.tcl +++ b/tcl/cpu/arm/arm7tdmi.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set CPU_TYPE arm set CPU_NAME arm7tdmi set CPU_ARCH armv4t diff --git a/tcl/cpu/arm/arm920.tcl b/tcl/cpu/arm/arm920.tcl index c01f602f2c..1c5a8ad8aa 100644 --- a/tcl/cpu/arm/arm920.tcl +++ b/tcl/cpu/arm/arm920.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set CPU_TYPE arm set CPU_NAME arm920 set CPU_ARCH armv4t diff --git a/tcl/cpu/arm/arm946.tcl b/tcl/cpu/arm/arm946.tcl index a6110a53fd..602d4d700d 100644 --- a/tcl/cpu/arm/arm946.tcl +++ b/tcl/cpu/arm/arm946.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set CPU_TYPE arm set CPU_NAME arm946 set CPU_ARCH armv5te diff --git a/tcl/cpu/arm/arm966.tcl b/tcl/cpu/arm/arm966.tcl index 1fffbc0923..0e64312e0e 100644 --- a/tcl/cpu/arm/arm966.tcl +++ b/tcl/cpu/arm/arm966.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set CPU_TYPE arm set CPU_NAME arm966 set CPU_ARCH armv5te diff --git a/tcl/cpu/arm/cortex_m3.tcl b/tcl/cpu/arm/cortex_m3.tcl index c9950261fd..0791664bba 100644 --- a/tcl/cpu/arm/cortex_m3.tcl +++ b/tcl/cpu/arm/cortex_m3.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set CPU_TYPE arm set CPU_NAME cortex_m3 set CPU_ARCH armv7 diff --git a/tcl/fpga/altera-10m50.cfg b/tcl/fpga/altera-10m50.cfg index d5af710592..94228d26fd 100644 --- a/tcl/fpga/altera-10m50.cfg +++ b/tcl/fpga/altera-10m50.cfg @@ -1,22 +1,9 @@ -# see MAX 10 FPGA Device Architecture -# Table 3-1: IDCODE Information for MAX 10 Devices -# Intel MAX 10M02 0x31810dd -# Intel MAX 10M04 0x318a0dd -# Intel MAX 10M08 0x31820dd -# Intel MAX 10M16 0x31830dd -# Intel MAX 10M25 0x31840dd -# Intel MAX 10M40 0x318d0dd -# Intel MAX 10M50 0x31850dd -# Intel MAX 10M02 0x31010dd -# Intel MAX 10M04 0x310a0dd -# Intel MAX 10M08 0x31020dd -# Intel MAX 10M16 0x31030dd -# Intel MAX 10M25 0x31040dd -# Intel MAX 10M40 0x310d0dd -# Intel MAX 10M50 0x31050dd +# SPDX-License-Identifier: GPL-2.0-or-later -jtag newtap 10m50 tap -irlen 10 -expected-id 0x31810dd -expected-id 0x318a0dd \ - -expected-id 0x31820dd -expected-id 0x31830dd -expected-id 0x31840dd \ - -expected-id 0x318d0dd -expected-id 0x31850dd -expected-id 0x31010dd \ - -expected-id 0x310a0dd -expected-id 0x31020dd -expected-id 0x31030dd \ - -expected-id 0x31040dd -expected-id 0x310d0dd -expected-id 0x31050dd +# file altera-10m50.cfg replaced by altera-max10.cfg +echo "DEPRECATED: use altera-max10.cfg instead of deprecated altera-10m50.cfg" + +#just to be backward compatible: +#tap will be 10m50.tap instead of max10.tap: +set CHIPNAME 10m50 +source [find cpld/altera-max10.cfg] diff --git a/tcl/fpga/altera-arriaii.cfg b/tcl/fpga/altera-arriaii.cfg new file mode 100644 index 0000000000..d59c182070 --- /dev/null +++ b/tcl/fpga/altera-arriaii.cfg @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Intel Arria II FPGA +# Arria II Device Handbook +# Table 11–2. 32-Bit IDCODE for Arria II Devices + +#GX: +#EP2AGX45: 0x025120dd +#EP2AGX65: 0x025020dd +#EP2AGX95: 0x025130dd +#EP2AGX125: 0x025030dd +#EP2AGX190: 0x025140dd +#EP2AGX260: 0x025040dd +#EP2AGZ225: 0x024810dd +#EP2AGZ300: 0x0240a0dd +#EP2AGZ350: 0x024820dd + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME arriaii +} + +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x025120dd -expected-id 0x025040dd \ + -expected-id 0x025020dd -expected-id 0x024810dd \ + -expected-id 0x025130dd -expected-id 0x0240a0dd \ + -expected-id 0x025030dd -expected-id 0x024820dd \ + -expected-id 0x025140dd + +pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family arriaii diff --git a/tcl/fpga/altera-cyclone10.cfg b/tcl/fpga/altera-cyclone10.cfg new file mode 100644 index 0000000000..3a1bc1f65c --- /dev/null +++ b/tcl/fpga/altera-cyclone10.cfg @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Intel Cyclone 10 FPGA +# see: https://www.intel.com/content/www/us/en/docs/programmable/683777/current/bst-operation-control.html +# and: https://www.intel.cn/content/dam/support/us/en/programmable/kdb/pdfs/literature/hb/cyclone-10/c10gx-51003.pdf + +# GX085: 0x02e120dd +# GX105: 0x02e320dd +# GX150: 0x02e720dd +# GX220: 0x02ef20dd +# 10cl006: 0x020f10dd +# 10cl010: 0x020f10dd +# 10cl016: 0x020f20dd +# 10cl025: 0x020f30dd +# 10cl040: 0x020f40dd +# 10cl055: 0x020f50dd +# 10cl080: 0x020f60dd +# 10cl120: 0x020f70dd + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME cyclone10 +} + +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x02e720dd -expected-id 0x02e120dd \ + -expected-id 0x02ef20dd -expected-id 0x02e320dd \ + -expected-id 0x020f10dd -expected-id 0x020f20dd \ + -expected-id 0x020f30dd -expected-id 0x020f40dd \ + -expected-id 0x020f50dd -expected-id 0x020f60dd \ + -expected-id 0x020f70dd + +pld device intel $_CHIPNAME.tap cyclone10 diff --git a/tcl/fpga/altera-cycloneiii.cfg b/tcl/fpga/altera-cycloneiii.cfg new file mode 100644 index 0000000000..d9be6455df --- /dev/null +++ b/tcl/fpga/altera-cycloneiii.cfg @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Intel Cyclone III FPGA +# see Cyclone III Device Handbook +# Table 12-2: Device IDCODE for Cyclone III Device Family + +#EP3C5 0x020f10dd +#EP3C10 0x020f10dd +#EP3C16 0x020f20dd +#EP3C25 0x020f30dd +#EP3C40 0x020f40dd +#EP3C55 0x020f50dd +#EP3C80 0x020f60dd +#EP3C120 0x020f70dd +#Cyclone III LS +#EP3CLS70 0x027010dd +#EP3CLS100 0x027000dd +#EP3CLS150 0x027030dd +#EP3CLS200 0x027020dd + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME cycloneiii +} + +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x020f10dd -expected-id 0x020f20dd \ + -expected-id 0x020f30dd -expected-id 0x020f40dd \ + -expected-id 0x020f50dd -expected-id 0x020f60dd \ + -expected-id 0x020f70dd -expected-id 0x027010dd \ + -expected-id 0x027000dd -expected-id 0x027030dd \ + -expected-id 0x027020dd + +pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cycloneiii diff --git a/tcl/fpga/altera-cycloneiv.cfg b/tcl/fpga/altera-cycloneiv.cfg new file mode 100644 index 0000000000..6a908e8af5 --- /dev/null +++ b/tcl/fpga/altera-cycloneiv.cfg @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Intel Cyclone IV FPGA +# see Cyclone IV Device Handbook +# Table 10-2: IDCODE Information for 32-Bit Cyclone IV Devices + +#EP4CE6 0x020f10dd +#EP4CE10 0x020f10dd +#EP4CE15 0x020f20dd +#EP4CE22 0x020f30dd +#EP4CE30 0x020f40dd +#EP4CE40 0x020f40dd +#EP4CE55 0x020f50dd +#EP4CE75 0x020f60dd +#EP4CE115 0x020f70dd +#EP4CGX15 0x028010dd +#EP4CGX22 0x028120dd +#EP4CGX30 (3) 0x028020dd +#EP4CGX30 (4) 0x028230dd +#EP4CGX50 0x028130dd +#EP4CGX75 0x028030dd +#EP4CGX110 0x028140dd +#EP4CGX150 0x028040dd + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME cycloneiv +} + +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x020f10dd -expected-id 0x020f20dd \ + -expected-id 0x020f30dd -expected-id 0x020f40dd \ + -expected-id 0x020f50dd -expected-id 0x020f60dd \ + -expected-id 0x020f70dd -expected-id 0x028010dd \ + -expected-id 0x028120dd -expected-id 0x028020dd \ + -expected-id 0x028230dd -expected-id 0x028130dd \ + -expected-id 0x028030dd -expected-id 0x028140dd \ + -expected-id 0x028040dd + +pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cycloneiv diff --git a/tcl/fpga/altera-cyclonev.cfg b/tcl/fpga/altera-cyclonev.cfg new file mode 100644 index 0000000000..46532a556c --- /dev/null +++ b/tcl/fpga/altera-cyclonev.cfg @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Intel Cyclone 5 FPGA +# see Cyclone V Device Handbook +# Table 9-1: IDCODE Information for Cyclone V Devices + +#5CEA2 0x02b150dd +#5CEA4 0x02b050dd +#5CEA5 0x02b220dd +#5CEA7 0x02b130dd +#5CEA9 0x02b140dd +#5CGXC3 0x02b010dd +#5CGXC4 0x02b120dd +#5CGXC5 0x02b020dd +#5CGXC7 0x02b030dd +#5CGXC9 0x02b040dd +#5CGTD5 0x02b020dd +#5CGTD7 0x02b030dd +#5CGTD9 0x02b040dd +#5CSEA2 0x02d110dd +#5CSEA4 0x02d010dd +#5CSEA5 0x02d120dd +#5CSEA6 0x02d020dd +#5CSXC2 0x02d110dd +#5CSXC4 0x02d010dd +#5CSXC5 0x02d120dd +#5CSXC6 0x02d020dd +#5CSTD5 0x02d120dd +#5CSTD6 0x02d020dd + + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME cyclonev +} + +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x02b150dd -expected-id 0x02b050dd \ + -expected-id 0x02b220dd -expected-id 0x02b130dd \ + -expected-id 0x02b140dd -expected-id 0x02b010dd \ + -expected-id 0x02b120dd -expected-id 0x02b020dd \ + -expected-id 0x02b030dd -expected-id 0x02b040dd \ + -expected-id 0x02d110dd -expected-id 0x02d010dd \ + -expected-id 0x02d120dd -expected-id 0x02d020dd + +pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cyclonev diff --git a/tcl/fpga/altera-ep3c10.cfg b/tcl/fpga/altera-ep3c10.cfg index 6e8962a53c..d7a92d7484 100644 --- a/tcl/fpga/altera-ep3c10.cfg +++ b/tcl/fpga/altera-ep3c10.cfg @@ -1,4 +1,9 @@ -# Altera Cyclone III EP3C10 -# see Cyclone III Device Handbook, Volume 1; -# Table 14–5. 32-Bit Cyclone III Device IDCODE -jtag newtap ep3c10 tap -expected-id 0x020f10dd -irlen 10 +# SPDX-License-Identifier: GPL-2.0-or-later + +# file altera-ep3c10.cfg replaced by altera-cycloneiii.cfg +echo "DEPRECATED: use altera-cycloneiii.cfg instead of deprecated altera-ep3c10.cfg" + +#just to be backward compatible: +#tap will be ep3c10.tap instead of cycloneiii.tap: +set CHIPNAME ep3c10 +source [find fpga/altera-cycloneiii.cfg] diff --git a/tcl/fpga/efinix_titanium.cfg b/tcl/fpga/efinix_titanium.cfg new file mode 100644 index 0000000000..3c2cdd71f7 --- /dev/null +++ b/tcl/fpga/efinix_titanium.cfg @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# efinix titanium +# https://www.efinixinc.com/docs/an048-jtag-bst-titanium-v1.0.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME titanium +} + +jtag newtap $_CHIPNAME tap -irlen 5 -ignore-version \ + -expected-id 0x10661A79 \ + -expected-id 0x00360A79 \ + -expected-id 0x10660A79 \ + -expected-id 0x00681A79 \ + -expected-id 0x00688A79 \ + -expected-id 0x00682A79 \ + -expected-id 0x0068CA79 \ + -expected-id 0x00680A79 \ + -expected-id 0x00684A79 + +pld create $_CHIPNAME.pld efinix -chain-position $_CHIPNAME.tap -family titanium diff --git a/tcl/fpga/efinix_trion.cfg b/tcl/fpga/efinix_trion.cfg new file mode 100644 index 0000000000..1c789f5642 --- /dev/null +++ b/tcl/fpga/efinix_trion.cfg @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# efinix trion +# https://www.efinixinc.com/docs/an021-jtag-bst-trion-v1.0.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME trion +} + +jtag newtap $_CHIPNAME tap -irlen 4 -ignore-version \ + -expected-id 0x00210A79 \ + -expected-id 0x00240A79 \ + -expected-id 0x00220A79 + +pld create $_CHIPNAME.pld efinix -chain-position $_CHIPNAME.tap -family trion diff --git a/tcl/fpga/gatemate.cfg b/tcl/fpga/gatemate.cfg new file mode 100644 index 0000000000..e8f338236d --- /dev/null +++ b/tcl/fpga/gatemate.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# GateMateTM FPGA +# https://www.colognechip.com/programmable-logic/gatemate/ +# https://colognechip.com/docs/ds1001-gatemate1-datasheet-latest.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME gatemate +} + +jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ + -expected-id 0x20000001 + +pld create $_CHIPNAME.pld gatemate -chain-position $_CHIPNAME.tap diff --git a/tcl/fpga/gowin_gw1n.cfg b/tcl/fpga/gowin_gw1n.cfg new file mode 100644 index 0000000000..5e85066f99 --- /dev/null +++ b/tcl/fpga/gowin_gw1n.cfg @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Gowin FPGA IDCODEs +# from JTAG Programming and Configuration Guide +# http://cdn.gowinsemi.com.cn/TN653E.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME gw1n +} + +jtag newtap $_CHIPNAME tap -irlen 8 -ignore-version \ + -expected-id 0x0900281B \ + -expected-id 0x0900381B \ + -expected-id 0x0100681B \ + -expected-id 0x0300081B \ + -expected-id 0x0300181B \ + -expected-id 0x0120681B \ + -expected-id 0x0100381B \ + -expected-id 0x1100381B \ + -expected-id 0x0100981B \ + -expected-id 0x1100581B \ + -expected-id 0x1100481B \ + -expected-id 0x0100181B \ + -expected-id 0x1100181B \ + -expected-id 0x0100481B + +pld create $_CHIPNAME.pld gowin -chain-position $_CHIPNAME.tap diff --git a/tcl/fpga/lattice_certus.cfg b/tcl/fpga/lattice_certus.cfg new file mode 100644 index 0000000000..9ddb7d8431 --- /dev/null +++ b/tcl/fpga/lattice_certus.cfg @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if { [info exists CHIPNAME] } { + set _CHIPNAME $_CHIPNAME +} else { + set _CHIPNAME certus +} + +# Lattice Certus +# +# Certus NX LFD2NX-17 0x310f0043 +# Certus NX LFD2NX-40 0x310f1043 + + +jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ + -expected-id 0x310F1043 -expected-id 0x310F0043 + +pld create $_CHIPNAME.pld lattice -chain-position $_CHIPNAME.tap diff --git a/tcl/fpga/lattice_certuspro.cfg b/tcl/fpga/lattice_certuspro.cfg new file mode 100644 index 0000000000..acaaa57392 --- /dev/null +++ b/tcl/fpga/lattice_certuspro.cfg @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if { [info exists CHIPNAME] } { + set _CHIPNAME $_CHIPNAME +} else { + set _CHIPNAME certuspro +} + +# Lattice CertusPro +# +# 0x010f4043 - LFCPNX-100 +# 0x 043 - LFCPNX-50 + +jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ + -expected-id 0x010f4043 +# -expected-id 0x01112043 + +pld create $_CHIPNAME.pld lattice -chain-position $_CHIPNAME.tap diff --git a/tcl/fpga/lattice_ecp2.cfg b/tcl/fpga/lattice_ecp2.cfg new file mode 100644 index 0000000000..5b01787bdd --- /dev/null +++ b/tcl/fpga/lattice_ecp2.cfg @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if { [info exists CHIPNAME] } { + set _CHIPNAME $_CHIPNAME +} else { + set _CHIPNAME ecp2 +} + +# Lattice ECP2 family +# TAP IDs are extracted from BSDL files found on this page: +# https://www.latticesemi.com/Products/FPGAandCPLD/LatticeECP2M +# +# LFE2M20E: 0x01279043 +# LFE2M35E: 0x0127A043 +# LFE2M50E: 0x0127B043 +# LFE2M70E: 0x0127C043 +# LFE2M100E: 0x0127D043 +# LFEC2_6E: 0x01270043 +# LFEC2_12E: 0x01271043 +# LFEC2_20E: 0x01272043 +# LFEC2_35E: 0x01274043 +# LFEC2_50E: 0x01273043 +# LFEC2_70E: 0x01275043 + +jtag newtap $_CHIPNAME tap -irlen 8 \ + -expected-id 0x01279043 -expected-id 0x0127A043 -expected-id 0x0127B043 \ + -expected-id 0x0127C043 -expected-id 0x0127D043 -expected-id 0x01270043 \ + -expected-id 0x01271043 -expected-id 0x01272043 -expected-id 0x01274043 \ + -expected-id 0x01273043 -expected-id 0x01275043 + +pld create $_CHIPNAME.pld lattice -chain-position $_CHIPNAME.tap diff --git a/tcl/fpga/lattice_ecp3.cfg b/tcl/fpga/lattice_ecp3.cfg new file mode 100644 index 0000000000..21c8ffa842 --- /dev/null +++ b/tcl/fpga/lattice_ecp3.cfg @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if { [info exists CHIPNAME] } { + set _CHIPNAME $_CHIPNAME +} else { + set _CHIPNAME ecp3 +} + +# Lattice ECP3 family +# TAP IDs are extracted from BSDL files found on this page: +# https://www.latticesemi.com/Products/FPGAandCPLD/LatticeECP3 +# +# LFE3_17: 0x01010043 +# LFE3_35: 0x01012043 +# LFE3_95: 0x01014043 and LFE3_70 +# LFE3_150: 0x01015043 + +jtag newtap $_CHIPNAME tap -irlen 8 \ + -expected-id 0x01010043 -expected-id 0x01012043 \ + -expected-id 0x01014043 -expected-id 0x01015043 + +pld create $_CHIPNAME.pld lattice -chain-position $_CHIPNAME.tap diff --git a/tcl/fpga/lattice_ecp5.cfg b/tcl/fpga/lattice_ecp5.cfg index a94ada7404..cdc63f0c11 100644 --- a/tcl/fpga/lattice_ecp5.cfg +++ b/tcl/fpga/lattice_ecp5.cfg @@ -26,3 +26,5 @@ jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ -expected-id 0x21111043 -expected-id 0x41111043 -expected-id 0x41112043 \ -expected-id 0x41113043 -expected-id 0x81111043 -expected-id 0x81112043 \ -expected-id 0x81113043 + +pld create $_CHIPNAME.pld lattice -chain-position $_CHIPNAME.tap diff --git a/tcl/fpga/lattice_machxo3.cfg b/tcl/fpga/lattice_machxo3.cfg new file mode 100644 index 0000000000..37fa054300 --- /dev/null +++ b/tcl/fpga/lattice_machxo3.cfg @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME machxo3 +} + +# Lattice MachXO3 family +# TAP IDs are extracted from BSDL files found on this page: +# https://www.latticesemi.com/Products/FPGAandCPLD/MachXO3 +# +# 0x412b2043 - LCMXO3L_1300E_XXUWG36/XXMG121 +# 0x412b3043 - LCMXO3L_2100E_XXMG121/XXMG256/XXUWG49 +# 0x412b4043 - LCMXO3L_4300E_XXMG121/XXMG324/XXUWG81 +# 0x412b5043 - LCMXO3L_6900E_XXMG256/XXMG324 +# 0x412b6043 - LCMXO3L_9400E_XXBG256/XXMG256 +# 0x412bb043 - LCMXO3L_2100C_XXBG256 +# 0x412bc043 - LCMXO3L_4300C_XXBG256/XXBG324 +# 0x412bd043 - LCMXO3L_6900C_XXBG256/XXBG324/XXBG400 +# 0x412be043 - LCMXO3L_9400C_XXBG256/XXBG400/XXBG484 +# 0x612b2043 - LCMXO3LF_1300E_XXMG121/XXUWG36 +# 0x612b3043 - LCMXO3LF_2100E_XXMG121/XXMG256/XXUWG49 +# 0x612b4043 - LCMXO3LF_4300E_XXMG121/XXMG256/XXMG324/XXUWG81 +# 0x612b5043 - LCMXO3LF_6900E_XXMG256/XXMG324 +# 0x612b6043 - LCMXO3LF_9400E_XXBG256/XXMG256 +# 0x612bb043 - LCMXO3LF_2100C_XXBG256 +# 0x612bc043 - LCMXO3LF_4300C_XXBG256/XXBG324 +# 0x612bd043 - LCMXO3LF_6900C_XXBG256/XXBG324/XXBG400 +# 0x612be043 - LCMXO3LF_9400C_XXBG256/XXBG400/XXBG484 +# 0xc12b2043 - LCMXO3L_640E_XXMG121 +# 0xc12b4043 - LCMXO3L_2100E_XXMG324 +# 0xc12bb043 - LCMXO3L_1300C_XXBG256/XXMG256 +# 0xc12bc043 - LCMXO3L_2100C_XXBG324 +# 0xc12bd043 - LCMXO3L_4300C_XXBG400 +# 0xe12b2043 - LCMXO3LF_640E_XXMG121 +# 0xe12b3043 - LCMXO3LF_1300E_XXMG256 +# 0xe12b4043 - LCMXO3LF_2100E_XXMG324 +# 0xe12bb043 - LCMXO3LF_1300C_XXBG256 +# 0xe12bc043 - LCMXO3LF_2100C_XXBG324 +# 0xe12bd043 - LCMXO3LF_4300C_XXBG400 + +jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ + -expected-id 0x412b2043 -expected-id 0x412b3043 -expected-id 0x412b4043 \ + -expected-id 0x412b5043 -expected-id 0x412b6043 -expected-id 0x412bb043 \ + -expected-id 0x412bc043 -expected-id 0x412bd043 -expected-id 0x412be043 \ + -expected-id 0x612b2043 -expected-id 0x612b3043 -expected-id 0x612b4043 \ + -expected-id 0x612b5043 -expected-id 0x612b6043 -expected-id 0x612bb043 \ + -expected-id 0x612bc043 -expected-id 0x612bd043 -expected-id 0x612be043 \ + -expected-id 0xc12b2043 -expected-id 0xc12b4043 -expected-id 0xc12bb043 \ + -expected-id 0xc12bc043 -expected-id 0xc12bd043 -expected-id 0xe12b2043 \ + -expected-id 0xe12b3043 -expected-id 0xe12b4043 -expected-id 0xe12bb043 \ + -expected-id 0xe12bc043 -expected-id 0xe12bd043 diff --git a/tcl/fpga/xilinx-dna.cfg b/tcl/fpga/xilinx-dna.cfg index a8056735b1..56f8c14119 100644 --- a/tcl/fpga/xilinx-dna.cfg +++ b/tcl/fpga/xilinx-dna.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + proc xilinx_dna_addr {chip} { array set addrs { Spartan6 0x30 diff --git a/tcl/fpga/xilinx-xadc.cfg b/tcl/fpga/xilinx-xadc.cfg index 250879ec93..fdaf3a961b 100644 --- a/tcl/fpga/xilinx-xadc.cfg +++ b/tcl/fpga/xilinx-xadc.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Xilinx XADC support for 7 Series FPGAs # # The 7 Series FPGAs contain an on-chip 12 bit ADC that can probe die diff --git a/tcl/interface/altera-usb-blaster.cfg b/tcl/interface/altera-usb-blaster.cfg index cb4ca9a785..cc6057b510 100644 --- a/tcl/interface/altera-usb-blaster.cfg +++ b/tcl/interface/altera-usb-blaster.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Altera USB-Blaster # diff --git a/tcl/interface/altera-usb-blaster2.cfg b/tcl/interface/altera-usb-blaster2.cfg index 05b0519b80..93f9809b03 100644 --- a/tcl/interface/altera-usb-blaster2.cfg +++ b/tcl/interface/altera-usb-blaster2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Altera USB-Blaster II # diff --git a/tcl/interface/angie.cfg b/tcl/interface/angie.cfg new file mode 100644 index 0000000000..26cbe393b5 --- /dev/null +++ b/tcl/interface/angie.cfg @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (C) 2023 by NanoXplore, France - all rights reserved +# +# configuration file for ANGIE Adapter from NanoXplore. +# + +adapter driver angie +adapter speed 10000 +reset_config trst_and_srst trst_push_pull srst_open_drain diff --git a/tcl/interface/arm-jtag-ew.cfg b/tcl/interface/arm-jtag-ew.cfg index 797bb7121e..a064a428e6 100644 --- a/tcl/interface/arm-jtag-ew.cfg +++ b/tcl/interface/arm-jtag-ew.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Olimex ARM-JTAG-EW # diff --git a/tcl/interface/ast2600-gpiod.cfg b/tcl/interface/ast2600-gpiod.cfg new file mode 100644 index 0000000000..5cad02fbdf --- /dev/null +++ b/tcl/interface/ast2600-gpiod.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Use AST2600 GPIO through linuxgpiod +# +# +-----------+-------------+-------------+ +# | signal | GPIO name | gpio offset | +# +-----------+-------------+-------------+ +# | TCK/SWCLK | GPIOI2 | 66 | +# | TMS/SWDIO | GPIOI3 | 67 | +# | TDI | GPIOI1 | 65 | +# | TDO | GPIOI4 | 68 | +# | nTRST | GPIOI0 | 64 | +# +-----------+-------------+-------------+ + +adapter driver linuxgpiod + +adapter gpio trst 64 -chip 0 +adapter gpio tdi 65 -chip 0 +adapter gpio tck 66 -chip 0 +adapter gpio swclk 66 -chip 0 +adapter gpio tms 67 -chip 0 +adapter gpio swdio 67 -chip 0 +adapter gpio tdo 68 -chip 0 + +reset_config trst_only separate trst_push_pull diff --git a/tcl/interface/at91rm9200.cfg b/tcl/interface/at91rm9200.cfg index b66e060d15..caef9975db 100644 --- a/tcl/interface/at91rm9200.cfg +++ b/tcl/interface/at91rm9200.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Various Atmel AT91RM9200 boards # diff --git a/tcl/interface/beaglebone-jtag-native.cfg b/tcl/interface/beaglebone-jtag-native.cfg new file mode 100644 index 0000000000..0240e5d8b8 --- /dev/null +++ b/tcl/interface/beaglebone-jtag-native.cfg @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# BeagleBone native GPIO interface for JTAG +# +# This is best used with a fast buffer but it is also suitable for a direct +# connection if the target voltage matches the host's IO voltage (typically +# 3.3V) and the cable is short. +# +# DO NOT APPLY VOLTAGE TO THE GPIO PINS UNTIL SYS_RESETN IS HIGH. +# +# Do not forget the GND connection. + +adapter driver am335xgpio + +# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET +# These depend on the system clock, calibrated for stock 1 GHz BeagleBoneBlack +# am335xgpio speed SPEED_COEFF SPEED_OFFSET +am335xgpio speed_coeffs 600000 575 + +# BeagleBone pin P9_41 +adapter gpio tdo 20 -chip 0 + +# BeagleBone pin P9_12 +adapter gpio tdi 28 -chip 1 + +# BeagleBone pin P9_18 +adapter gpio tms 4 -chip 0 + +# BeagleBone pin P9_22 +adapter gpio tck 2 -chip 0 + +# BeagleBone pin P9_16 +adapter gpio led 19 -chip 1 + +# BeagleBone pin P8_18 +adapter gpio srst 1 -chip 2 +reset_config srst_only srst_push_pull diff --git a/tcl/interface/beaglebone-swd-native.cfg b/tcl/interface/beaglebone-swd-native.cfg new file mode 100644 index 0000000000..6c40849798 --- /dev/null +++ b/tcl/interface/beaglebone-swd-native.cfg @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# BeagleBone native GPIO interface for SWD +# +# This is best used with a fast buffer but it is also suitable for a direct +# connection if the target voltage matches the host's IO voltage (typically +# 3.3V) and the cable is short. +# +# DO NOT APPLY VOLTAGE TO THE GPIO PINS UNTIL SYS_RESETN IS HIGH. +# +# Do not forget the GND connection. + +adapter driver am335xgpio + +# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET +# These depend on the system clock, calibrated for stock 1 GHz BeagleBoneBlack +# am335xgpio speed SPEED_COEFF SPEED_OFFSET +am335xgpio speed_coeffs 600000 575 + +# BeagleBone pin P9_22 +adapter gpio swclk 2 -chip 0 + +# BeagleBone pin P9_18 +adapter gpio swdio 4 -chip 0 + +# BeagleBone pin P9_12 +adapter gpio swdio_dir 28 -chip 1 + +# USR0 LED +adapter gpio led 21 -chip 1 + +# BeagleBone pin P8_18 +adapter gpio srst 1 -chip 2 +reset_config srst_only srst_push_pull diff --git a/tcl/interface/buspirate.cfg b/tcl/interface/buspirate.cfg index 20761d1526..8f613a7645 100644 --- a/tcl/interface/buspirate.cfg +++ b/tcl/interface/buspirate.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Buspirate with OpenOCD support # diff --git a/tcl/interface/calao-usb-a9260.cfg b/tcl/interface/calao-usb-a9260.cfg deleted file mode 100644 index 01b426b890..0000000000 --- a/tcl/interface/calao-usb-a9260.cfg +++ /dev/null @@ -1,10 +0,0 @@ -# -# CALAO Systems USB-A9260 common -C01 -C02 setup -# -# http://www.calao-systems.com/ -# -# See calao-usb-a9260-c01.cfg and calao-usb-a9260-c02.cfg. -# - -adapter srst delay 200 -jtag_ntrst_delay 200 diff --git a/tcl/interface/chameleon.cfg b/tcl/interface/chameleon.cfg index 97bf98d279..b73d129f02 100644 --- a/tcl/interface/chameleon.cfg +++ b/tcl/interface/chameleon.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Amontec Chameleon POD # diff --git a/tcl/interface/cmsis-dap.cfg b/tcl/interface/cmsis-dap.cfg index 1bc91a5270..15efe8060a 100644 --- a/tcl/interface/cmsis-dap.cfg +++ b/tcl/interface/cmsis-dap.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # ARM CMSIS-DAP compliant adapter # diff --git a/tcl/interface/dln-2-gpiod.cfg b/tcl/interface/dln-2-gpiod.cfg index cd6061fd98..c9e33881f7 100644 --- a/tcl/interface/dln-2-gpiod.cfg +++ b/tcl/interface/dln-2-gpiod.cfg @@ -17,11 +17,14 @@ adapter driver linuxgpiod -linuxgpiod gpiochip 0 -linuxgpiod jtag_nums 2 3 4 1 -linuxgpiod trst_num 5 -linuxgpiod swd_nums 2 3 -linuxgpiod srst_num 0 -linuxgpiod led_num 6 +adapter gpio srst 0 -chip 0 +adapter gpio tdo 1 -chip 0 +adapter gpio tck 2 -chip 0 +adapter gpio swclk 2 -chip 0 +adapter gpio tms 3 -chip 0 +adapter gpio swdio 3 -chip 0 +adapter gpio tdi 4 -chip 0 +adapter gpio trst 5 -chip 0 +adapter gpio led 6 -chip 0 reset_config trst_and_srst separate srst_push_pull diff --git a/tcl/interface/dummy.cfg b/tcl/interface/dummy.cfg index 154c872cf0..34e6558cce 100644 --- a/tcl/interface/dummy.cfg +++ b/tcl/interface/dummy.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Dummy interface (for testing purposes) # diff --git a/tcl/interface/esp_usb_bridge.cfg b/tcl/interface/esp_usb_bridge.cfg new file mode 100644 index 0000000000..9342239e77 --- /dev/null +++ b/tcl/interface/esp_usb_bridge.cfg @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# ESP USB Bridge jtag adapter +# + +adapter driver esp_usb_jtag + +espusbjtag vid_pid 0x303a 0x1002 +espusbjtag caps_descriptor 0x030A # string descriptor index:10 diff --git a/tcl/interface/esp_usb_jtag.cfg b/tcl/interface/esp_usb_jtag.cfg new file mode 100644 index 0000000000..40427d0e3e --- /dev/null +++ b/tcl/interface/esp_usb_jtag.cfg @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Espressif builtin USB-JTAG adapter +# + +adapter driver esp_usb_jtag + +espusbjtag vid_pid 0x303a 0x1001 +espusbjtag caps_descriptor 0x2000 diff --git a/tcl/interface/estick.cfg b/tcl/interface/estick.cfg index 75e6ea8e53..1daaf7c2ee 100644 --- a/tcl/interface/estick.cfg +++ b/tcl/interface/estick.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # eStick # diff --git a/tcl/interface/flashlink.cfg b/tcl/interface/flashlink.cfg index b7ec0bb240..d552c50a6b 100644 --- a/tcl/interface/flashlink.cfg +++ b/tcl/interface/flashlink.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # ST FlashLINK JTAG parallel cable # diff --git a/tcl/interface/ft232r.cfg b/tcl/interface/ft232r.cfg index 2c705c3353..94eed0235e 100644 --- a/tcl/interface/ft232r.cfg +++ b/tcl/interface/ft232r.cfg @@ -1,2 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + adapter driver ft232r adapter speed 1000 diff --git a/tcl/interface/ft232r/radiona_ulx3s.cfg b/tcl/interface/ft232r/radiona_ulx3s.cfg index 424777e9e8..3fc3d7105e 100644 --- a/tcl/interface/ft232r/radiona_ulx3s.cfg +++ b/tcl/interface/ft232r/radiona_ulx3s.cfg @@ -7,10 +7,10 @@ adapter driver ft232r adapter speed 1000 -ft232r_vid_pid 0x0403 0x6015 -ft232r_tck_num DSR -ft232r_tms_num DCD -ft232r_tdi_num RI -ft232r_tdo_num CTS -ft232r_trst_num RTS -ft232r_srst_num DTR +ft232r vid_pid 0x0403 0x6015 +ft232r tck_num DSR +ft232r tms_num DCD +ft232r tdi_num RI +ft232r tdo_num CTS +ft232r trst_num RTS +ft232r srst_num DTR diff --git a/tcl/interface/ftdi/100ask-openjtag.cfg b/tcl/interface/ftdi/100ask-openjtag.cfg index a12df97af2..5ab9252c69 100644 --- a/tcl/interface/ftdi/100ask-openjtag.cfg +++ b/tcl/interface/ftdi/100ask-openjtag.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # www.100ask.org OpenJTAG # diff --git a/tcl/interface/ftdi/ashling-opella-ld-jtag.cfg b/tcl/interface/ftdi/ashling-opella-ld-jtag.cfg old mode 100755 new mode 100644 diff --git a/tcl/interface/ftdi/ashling-opella-ld-swd.cfg b/tcl/interface/ftdi/ashling-opella-ld-swd.cfg old mode 100755 new mode 100644 diff --git a/tcl/interface/ftdi/axm0432.cfg b/tcl/interface/ftdi/axm0432.cfg index 84b77a69ab..50083996c3 100644 --- a/tcl/interface/ftdi/axm0432.cfg +++ b/tcl/interface/ftdi/axm0432.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Axiom axm0432 # diff --git a/tcl/interface/ftdi/c232hm.cfg b/tcl/interface/ftdi/c232hm.cfg index 25fcae1b0b..23c8f3af23 100644 --- a/tcl/interface/ftdi/c232hm.cfg +++ b/tcl/interface/ftdi/c232hm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # FTDI USB Hi-Speed to MPSSE Cable # # http://www.ftdichip.com/Products/Cables/USBMPSSE.htm diff --git a/tcl/interface/ftdi/calao-usb-a9260-c01.cfg b/tcl/interface/ftdi/calao-usb-a9260-c01.cfg deleted file mode 100644 index 41e5973914..0000000000 --- a/tcl/interface/ftdi/calao-usb-a9260-c01.cfg +++ /dev/null @@ -1,22 +0,0 @@ -# -# CALAO Systems USB-A9260-C01 -# -# http://www.calao-systems.com/ -# - -echo "WARNING!" -echo "This file was not tested with real interface, but is assumed to work as this" -echo "interface uses the same layout as configs that were verified. Please report your" -echo "experience with this file to openocd-devel mailing list, so it could be marked" -echo "as working or fixed." - -adapter driver ftdi -ftdi device_desc "USB-A9260" -ftdi vid_pid 0x0403 0x6010 - -ftdi layout_init 0x0c08 0x0f1b -ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 -ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 - -script interface/calao-usb-a9260.cfg -script target/at91sam9260minimal.cfg diff --git a/tcl/interface/ftdi/calao-usb-a9260-c02.cfg b/tcl/interface/ftdi/calao-usb-a9260-c02.cfg deleted file mode 100644 index 001aef59cb..0000000000 --- a/tcl/interface/ftdi/calao-usb-a9260-c02.cfg +++ /dev/null @@ -1,22 +0,0 @@ -# -# CALAO Systems USB-A9260-C02 -# -# http://www.calao-systems.com/ -# - -echo "WARNING!" -echo "This file was not tested with real interface, but is assumed to work as this" -echo "interface uses the same layout as configs that were verified. Please report your" -echo "experience with this file to openocd-devel mailing list, so it could be marked" -echo "as working or fixed." - -adapter driver ftdi -ftdi device_desc "USB-A9260" -ftdi vid_pid 0x0403 0x6001 - -ftdi layout_init 0x0c08 0x0f1b -ftdi layout_signal nTRST -data 0x0100 -noe 0x0400 -ftdi layout_signal nSRST -data 0x0200 -noe 0x0800 - -script interface/calao-usb-a9260.cfg -script target/at91sam9260minimal.cfg diff --git a/tcl/interface/ftdi/cortino.cfg b/tcl/interface/ftdi/cortino.cfg index c0eae31052..8bc8d6e4cc 100644 --- a/tcl/interface/ftdi/cortino.cfg +++ b/tcl/interface/ftdi/cortino.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Hitex Cortino # diff --git a/tcl/interface/ftdi/digilent-hs1.cfg b/tcl/interface/ftdi/digilent-hs1.cfg index 55391b9d31..6a632ed268 100644 --- a/tcl/interface/ftdi/digilent-hs1.cfg +++ b/tcl/interface/ftdi/digilent-hs1.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # this supports JTAG-HS1 and JTAG-SMT1 # (the later being the OEM on-board version) diff --git a/tcl/interface/ftdi/digilent-hs2.cfg b/tcl/interface/ftdi/digilent-hs2.cfg index 269eca0f38..89c9e4b6c4 100644 --- a/tcl/interface/ftdi/digilent-hs2.cfg +++ b/tcl/interface/ftdi/digilent-hs2.cfg @@ -1,10 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # this supports JTAG-HS2 (and apparently Nexys4 as well) +# ADBUS5 controls TMS tri-state buffer enable +# ACBUS6=SEL_TMS controls mux to TMS output buffer: 0=TMS 1=TDI +# ACBUS5=SEL_TDO controls mux to TDO input: 0=TDO 1=TMS + adapter driver ftdi ftdi device_desc "Digilent Adept USB Device" ftdi vid_pid 0x0403 0x6014 ftdi channel 0 ftdi layout_init 0x00e8 0x60eb +ftdi layout_signal SWD_EN -data 0x6000 +ftdi layout_signal SWDIO_OE -data 0x20 reset_config none diff --git a/tcl/interface/ftdi/digilent_jtag_hs3.cfg b/tcl/interface/ftdi/digilent_jtag_hs3.cfg index ca2807f80c..78a233feb5 100644 --- a/tcl/interface/ftdi/digilent_jtag_hs3.cfg +++ b/tcl/interface/ftdi/digilent_jtag_hs3.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Digilent JTAG-HS3 # diff --git a/tcl/interface/ftdi/digilent_jtag_smt2.cfg b/tcl/interface/ftdi/digilent_jtag_smt2.cfg index f4ba27befe..ac623a796d 100644 --- a/tcl/interface/ftdi/digilent_jtag_smt2.cfg +++ b/tcl/interface/ftdi/digilent_jtag_smt2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Digilent JTAG-SMT2 # diff --git a/tcl/interface/ftdi/digilent_jtag_smt2_nc.cfg b/tcl/interface/ftdi/digilent_jtag_smt2_nc.cfg index a143cd7720..38236bc107 100644 --- a/tcl/interface/ftdi/digilent_jtag_smt2_nc.cfg +++ b/tcl/interface/ftdi/digilent_jtag_smt2_nc.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Digilent JTAG-SMT2-NC # diff --git a/tcl/interface/ftdi/dlp-usb1232h.cfg b/tcl/interface/ftdi/dlp-usb1232h.cfg index e9651dd994..67fee6b0f5 100644 --- a/tcl/interface/ftdi/dlp-usb1232h.cfg +++ b/tcl/interface/ftdi/dlp-usb1232h.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # DLP Design DLP-USB1232H USB-to-UART/FIFO interface module # diff --git a/tcl/interface/ftdi/dp_busblaster.cfg b/tcl/interface/ftdi/dp_busblaster.cfg index 420f788d2f..373e122c46 100644 --- a/tcl/interface/ftdi/dp_busblaster.cfg +++ b/tcl/interface/ftdi/dp_busblaster.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Dangerous Prototypes - Bus Blaster # diff --git a/tcl/interface/ftdi/dp_busblaster_kt-link.cfg b/tcl/interface/ftdi/dp_busblaster_kt-link.cfg index 4924d26192..222ca3810b 100644 --- a/tcl/interface/ftdi/dp_busblaster_kt-link.cfg +++ b/tcl/interface/ftdi/dp_busblaster_kt-link.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Dangerous Prototypes - Bus Blaster (with KT-Link buffer) # diff --git a/tcl/interface/ftdi/esp32_devkitj_v1.cfg b/tcl/interface/ftdi/esp32_devkitj_v1.cfg new file mode 100644 index 0000000000..1b455a9ac8 --- /dev/null +++ b/tcl/interface/ftdi/esp32_devkitj_v1.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Driver for the FT2232H JTAG chip on the Espressif DevkitJ board +# (and most other FT2232H and FT232H based boards) +# + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 0x0403 0x6014 + +# interface 1 is the uart +ftdi channel 0 + +# TCK, TDI, TDO, TMS: ADBUS0-3 +# LEDs: ACBUS4-7 + +ftdi layout_init 0x0008 0xf00b +ftdi layout_signal LED -data 0x1000 +ftdi layout_signal LED2 -data 0x2000 +ftdi layout_signal LED3 -data 0x4000 +ftdi layout_signal LED4 -data 0x8000 + +# ESP32 series chips do not have a TRST input, and the SRST line is connected to the EN pin. +# The target code doesn't handle SRST reset properly yet, so this is commented out: +# ftdi layout_signal nSRST -oe 0x0020 +# reset_config srst_only diff --git a/tcl/interface/ftdi/esp32s2_kaluga_v1.cfg b/tcl/interface/ftdi/esp32s2_kaluga_v1.cfg new file mode 100644 index 0000000000..1880bcbc5f --- /dev/null +++ b/tcl/interface/ftdi/esp32s2_kaluga_v1.cfg @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Driver for the FT2232H JTAG chip on the Espressif Kaluga-1 ESP32-S2 board +# (and most other FT2232H and FT232H based boards) +# +# JTAG DIP switch (labelled SW5 in the schematic) should be "ON" for lines +# labelled TCK, TDO, TDI and TWS, to connect the FT2232H to the ESP32-S2. +# + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 0x0403 0x6014 + +# interface 1 is the uart +ftdi channel 0 + +# TCK, TDI, TDO, TMS: ADBUS0-3 +# TRST/SRST: ADBUS5 (unused for now) +# LEDs: ACBUS3-4 (inverted) + +ftdi layout_init 0x0008 0x180b +ftdi layout_signal LED -ndata 0x0800 +ftdi layout_signal LED2 -ndata 0x1000 + +# ESP32* series chips do not have a TRST input, and the SRST line is connected +# to the EN pin. +# The target code doesn't handle SRST reset properly yet, so this is +# commented out: +# ftdi layout_signal nSRST -oe 0x0020 +# reset_config srst_only diff --git a/tcl/interface/ftdi/flossjtag-noeeprom.cfg b/tcl/interface/ftdi/flossjtag-noeeprom.cfg index 7083e63881..1008e1ae68 100644 --- a/tcl/interface/ftdi/flossjtag-noeeprom.cfg +++ b/tcl/interface/ftdi/flossjtag-noeeprom.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # FlossJTAG # diff --git a/tcl/interface/ftdi/flossjtag.cfg b/tcl/interface/ftdi/flossjtag.cfg index c1506a2e9b..90ba63a4cd 100644 --- a/tcl/interface/ftdi/flossjtag.cfg +++ b/tcl/interface/ftdi/flossjtag.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # FlossJTAG # diff --git a/tcl/interface/ftdi/flyswatter.cfg b/tcl/interface/ftdi/flyswatter.cfg index bfa015b2cc..8bce00dbbf 100644 --- a/tcl/interface/ftdi/flyswatter.cfg +++ b/tcl/interface/ftdi/flyswatter.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TinCanTools Flyswatter # diff --git a/tcl/interface/ftdi/flyswatter2.cfg b/tcl/interface/ftdi/flyswatter2.cfg index 0b4a8ef9f2..ebc00fe601 100644 --- a/tcl/interface/ftdi/flyswatter2.cfg +++ b/tcl/interface/ftdi/flyswatter2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TinCanTools Flyswatter2 # diff --git a/tcl/interface/ftdi/ft232h-module-swd.cfg b/tcl/interface/ftdi/ft232h-module-swd.cfg index 7fa4283596..d09ccf16d4 100644 --- a/tcl/interface/ftdi/ft232h-module-swd.cfg +++ b/tcl/interface/ftdi/ft232h-module-swd.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # ADAFRUIT FTDI FT232H as a SWD direct connect interface # Any FT232H based board may work diff --git a/tcl/interface/ftdi/gw16042.cfg b/tcl/interface/ftdi/gw16042.cfg index ef31829385..326a88fa02 100644 --- a/tcl/interface/ftdi/gw16042.cfg +++ b/tcl/interface/ftdi/gw16042.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Gateworks GW16042 JTAG Dongle # diff --git a/tcl/interface/ftdi/hilscher_nxhx10_etm.cfg b/tcl/interface/ftdi/hilscher_nxhx10_etm.cfg index d55f636deb..d5d24e5fc5 100644 --- a/tcl/interface/ftdi/hilscher_nxhx10_etm.cfg +++ b/tcl/interface/ftdi/hilscher_nxhx10_etm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Hilscher NXHX 10-ETM # diff --git a/tcl/interface/ftdi/hilscher_nxhx500_etm.cfg b/tcl/interface/ftdi/hilscher_nxhx500_etm.cfg index 8c79815617..003b9df6b3 100644 --- a/tcl/interface/ftdi/hilscher_nxhx500_etm.cfg +++ b/tcl/interface/ftdi/hilscher_nxhx500_etm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Hilscher NXHX 500-ETM # diff --git a/tcl/interface/ftdi/hilscher_nxhx500_re.cfg b/tcl/interface/ftdi/hilscher_nxhx500_re.cfg index 9aa2cd5167..97ad38075d 100644 --- a/tcl/interface/ftdi/hilscher_nxhx500_re.cfg +++ b/tcl/interface/ftdi/hilscher_nxhx500_re.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Hilscher NXHX 500-RE # diff --git a/tcl/interface/ftdi/hilscher_nxhx50_etm.cfg b/tcl/interface/ftdi/hilscher_nxhx50_etm.cfg index a64d0e8a48..06280c1ffd 100644 --- a/tcl/interface/ftdi/hilscher_nxhx50_etm.cfg +++ b/tcl/interface/ftdi/hilscher_nxhx50_etm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Hilscher NXHX 50-ETM # diff --git a/tcl/interface/ftdi/hilscher_nxhx50_re.cfg b/tcl/interface/ftdi/hilscher_nxhx50_re.cfg index 277883675a..f14be626b0 100644 --- a/tcl/interface/ftdi/hilscher_nxhx50_re.cfg +++ b/tcl/interface/ftdi/hilscher_nxhx50_re.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Hilscher NXHX 50-RE # diff --git a/tcl/interface/ftdi/hitex_lpc1768stick.cfg b/tcl/interface/ftdi/hitex_lpc1768stick.cfg index 87affe84ad..91bd5a8423 100644 --- a/tcl/interface/ftdi/hitex_lpc1768stick.cfg +++ b/tcl/interface/ftdi/hitex_lpc1768stick.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Hitex LPC1768-Stick # diff --git a/tcl/interface/ftdi/hitex_str9-comstick.cfg b/tcl/interface/ftdi/hitex_str9-comstick.cfg index 6490d65f48..f698677a63 100644 --- a/tcl/interface/ftdi/hitex_str9-comstick.cfg +++ b/tcl/interface/ftdi/hitex_str9-comstick.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Hitex STR9-comStick # diff --git a/tcl/interface/ftdi/icebear.cfg b/tcl/interface/ftdi/icebear.cfg index 76b2102a57..4a763994b5 100644 --- a/tcl/interface/ftdi/icebear.cfg +++ b/tcl/interface/ftdi/icebear.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Section5 ICEBear # diff --git a/tcl/interface/ftdi/imx8mp-evk.cfg b/tcl/interface/ftdi/imx8mp-evk.cfg index 64f3f3db0c..02564dc99e 100644 --- a/tcl/interface/ftdi/imx8mp-evk.cfg +++ b/tcl/interface/ftdi/imx8mp-evk.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Configuration file for NXP MC-IMX8MP-EVK on-board internal JTAG # diff --git a/tcl/interface/ftdi/incircuit-icprog.cfg b/tcl/interface/ftdi/incircuit-icprog.cfg index a200954469..81f2872205 100644 --- a/tcl/interface/ftdi/incircuit-icprog.cfg +++ b/tcl/interface/ftdi/incircuit-icprog.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # In-Circuit's ICprog OpenOCD JTAG Adapter # https://shop.in-circuit.de/product_info.php?products_id=112 diff --git a/tcl/interface/ftdi/iotlab-usb.cfg b/tcl/interface/ftdi/iotlab-usb.cfg index 92ffa840bd..b7a004e848 100644 --- a/tcl/interface/ftdi/iotlab-usb.cfg +++ b/tcl/interface/ftdi/iotlab-usb.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # This is the integrated adapter as found on the IoT-LAB boards # https://github.com/iot-lab/iot-lab/wiki diff --git a/tcl/interface/ftdi/isodebug.cfg b/tcl/interface/ftdi/isodebug.cfg index 018998963e..0a6e0807ec 100644 --- a/tcl/interface/ftdi/isodebug.cfg +++ b/tcl/interface/ftdi/isodebug.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # isodebug v1 # 5 kV isolated JTAG/SWD + UART adapter by Unjo AB diff --git a/tcl/interface/ftdi/jtag-lock-pick_tiny_2.cfg b/tcl/interface/ftdi/jtag-lock-pick_tiny_2.cfg index 3eefecf838..ea60dcfc39 100644 --- a/tcl/interface/ftdi/jtag-lock-pick_tiny_2.cfg +++ b/tcl/interface/ftdi/jtag-lock-pick_tiny_2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # DISTORTEC JTAG-lock-pick Tiny 2 # diff --git a/tcl/interface/ftdi/jtagkey.cfg b/tcl/interface/ftdi/jtagkey.cfg index 511244b3f2..1c1c09d3fd 100644 --- a/tcl/interface/ftdi/jtagkey.cfg +++ b/tcl/interface/ftdi/jtagkey.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Amontec JTAGkey # diff --git a/tcl/interface/ftdi/jtagkey2.cfg b/tcl/interface/ftdi/jtagkey2.cfg index aa33a75289..80df347c38 100644 --- a/tcl/interface/ftdi/jtagkey2.cfg +++ b/tcl/interface/ftdi/jtagkey2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Amontec JTAGkey2 # diff --git a/tcl/interface/ftdi/jtagkey2p.cfg b/tcl/interface/ftdi/jtagkey2p.cfg index dbfca66c49..3a76bd085a 100644 --- a/tcl/interface/ftdi/jtagkey2p.cfg +++ b/tcl/interface/ftdi/jtagkey2p.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Amontec JTAGkey2P # diff --git a/tcl/interface/ftdi/kt-link.cfg b/tcl/interface/ftdi/kt-link.cfg index 112ecf1549..61c6b831b7 100644 --- a/tcl/interface/ftdi/kt-link.cfg +++ b/tcl/interface/ftdi/kt-link.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Kristech KT-Link # diff --git a/tcl/interface/ftdi/lisa-l.cfg b/tcl/interface/ftdi/lisa-l.cfg index 3da64a00ed..75c5cbe7fd 100644 --- a/tcl/interface/ftdi/lisa-l.cfg +++ b/tcl/interface/ftdi/lisa-l.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Lisa/L # diff --git a/tcl/interface/ftdi/luminary-icdi.cfg b/tcl/interface/ftdi/luminary-icdi.cfg index 08676a3487..9142503dd0 100644 --- a/tcl/interface/ftdi/luminary-icdi.cfg +++ b/tcl/interface/ftdi/luminary-icdi.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Luminary Micro Stellaris LM3S9B9x Evaluation Kits # In-Circuit Debug Interface (ICDI) Board diff --git a/tcl/interface/ftdi/luminary-lm3s811.cfg b/tcl/interface/ftdi/luminary-lm3s811.cfg index 90f454ef08..98be166fd6 100644 --- a/tcl/interface/ftdi/luminary-lm3s811.cfg +++ b/tcl/interface/ftdi/luminary-lm3s811.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Luminary Micro Stellaris LM3S811 Evaluation Kit # diff --git a/tcl/interface/ftdi/luminary.cfg b/tcl/interface/ftdi/luminary.cfg index 3258b214c5..27d9a9da05 100644 --- a/tcl/interface/ftdi/luminary.cfg +++ b/tcl/interface/ftdi/luminary.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Luminary Micro Stellaris Evaluation Kits # diff --git a/tcl/interface/ftdi/m53evk.cfg b/tcl/interface/ftdi/m53evk.cfg index 2b7c43445a..2d9c30448b 100644 --- a/tcl/interface/ftdi/m53evk.cfg +++ b/tcl/interface/ftdi/m53evk.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # DENX M53EVK # diff --git a/tcl/interface/ftdi/mbftdi.cfg b/tcl/interface/ftdi/mbftdi.cfg index a34390ba7c..09cec9ffb3 100644 --- a/tcl/interface/ftdi/mbftdi.cfg +++ b/tcl/interface/ftdi/mbftdi.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # MBFTDI # diff --git a/tcl/interface/ftdi/minimodule-swd.cfg b/tcl/interface/ftdi/minimodule-swd.cfg index 15b007afbd..3eb2f53278 100644 --- a/tcl/interface/ftdi/minimodule-swd.cfg +++ b/tcl/interface/ftdi/minimodule-swd.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Supports SWD using the FT2232H or FT4232H minimodule. # Each can support 2 SWD interfaces. diff --git a/tcl/interface/ftdi/minimodule.cfg b/tcl/interface/ftdi/minimodule.cfg index 6b2d60c07c..825d7c1dc8 100644 --- a/tcl/interface/ftdi/minimodule.cfg +++ b/tcl/interface/ftdi/minimodule.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # FTDI MiniModule # diff --git a/tcl/interface/ftdi/minispartan6.cfg b/tcl/interface/ftdi/minispartan6.cfg index faf820d7af..f12bae621c 100644 --- a/tcl/interface/ftdi/minispartan6.cfg +++ b/tcl/interface/ftdi/minispartan6.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # https://www.scarabhardware.com/minispartan6/ # https://github.com/scarabhardware/miniSpartan6-plus/raw/master/miniSpartan6%2B_Rev_B.pdf adapter driver ftdi diff --git a/tcl/interface/ftdi/neodb.cfg b/tcl/interface/ftdi/neodb.cfg index 426f5c4c7e..d3b35412fb 100644 --- a/tcl/interface/ftdi/neodb.cfg +++ b/tcl/interface/ftdi/neodb.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Openmoko USB JTAG/RS232 adapter # diff --git a/tcl/interface/ftdi/ngxtech.cfg b/tcl/interface/ftdi/ngxtech.cfg index 962f25baae..635333fb97 100644 --- a/tcl/interface/ftdi/ngxtech.cfg +++ b/tcl/interface/ftdi/ngxtech.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # NGX ARM USB JTAG # diff --git a/tcl/interface/ftdi/olimex-arm-jtag-swd.cfg b/tcl/interface/ftdi/olimex-arm-jtag-swd.cfg index ace0df98d8..6aa13af74d 100644 --- a/tcl/interface/ftdi/olimex-arm-jtag-swd.cfg +++ b/tcl/interface/ftdi/olimex-arm-jtag-swd.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Olimex ARM JTAG SWD adapter # https://www.olimex.com/Products/ARM/JTAG/ARM-JTAG-SWD/ diff --git a/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg b/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg index ca014a4d47..cd11ad8e11 100644 --- a/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg +++ b/tcl/interface/ftdi/olimex-arm-usb-ocd-h.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Olimex ARM-USB-OCD-H # diff --git a/tcl/interface/ftdi/olimex-arm-usb-ocd.cfg b/tcl/interface/ftdi/olimex-arm-usb-ocd.cfg index 6b92575831..d2261e2b77 100644 --- a/tcl/interface/ftdi/olimex-arm-usb-ocd.cfg +++ b/tcl/interface/ftdi/olimex-arm-usb-ocd.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Olimex ARM-USB-OCD # diff --git a/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg b/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg index 98fe367847..a2b3e3edfc 100644 --- a/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg +++ b/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Olimex ARM-USB-TINY-H # diff --git a/tcl/interface/ftdi/olimex-jtag-tiny.cfg b/tcl/interface/ftdi/olimex-jtag-tiny.cfg index ebca496d2f..7d8e81da3c 100644 --- a/tcl/interface/ftdi/olimex-jtag-tiny.cfg +++ b/tcl/interface/ftdi/olimex-jtag-tiny.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Olimex ARM-USB-TINY # diff --git a/tcl/interface/ftdi/oocdlink.cfg b/tcl/interface/ftdi/oocdlink.cfg index 367112a6cb..0e99b67a4d 100644 --- a/tcl/interface/ftdi/oocdlink.cfg +++ b/tcl/interface/ftdi/oocdlink.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Joern Kaipf's OOCDLink # diff --git a/tcl/interface/ftdi/opendous_ftdi.cfg b/tcl/interface/ftdi/opendous_ftdi.cfg index f212bf561b..5d6f5aee1a 100644 --- a/tcl/interface/ftdi/opendous_ftdi.cfg +++ b/tcl/interface/ftdi/opendous_ftdi.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Opendous # diff --git a/tcl/interface/ftdi/openocd-usb-hs.cfg b/tcl/interface/ftdi/openocd-usb-hs.cfg index d1a3ff0a28..af1f61c33d 100644 --- a/tcl/interface/ftdi/openocd-usb-hs.cfg +++ b/tcl/interface/ftdi/openocd-usb-hs.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # embedded projects openocd usb adapter v3 # diff --git a/tcl/interface/ftdi/openocd-usb.cfg b/tcl/interface/ftdi/openocd-usb.cfg index 620d204369..c333d65ca9 100644 --- a/tcl/interface/ftdi/openocd-usb.cfg +++ b/tcl/interface/ftdi/openocd-usb.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Hubert Hoegl's USB to JTAG # diff --git a/tcl/interface/ftdi/openrd.cfg b/tcl/interface/ftdi/openrd.cfg index 88b2a6e511..b6b2d1d93e 100644 --- a/tcl/interface/ftdi/openrd.cfg +++ b/tcl/interface/ftdi/openrd.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Marvell OpenRD # diff --git a/tcl/interface/ftdi/pipistrello.cfg b/tcl/interface/ftdi/pipistrello.cfg index 11fcf077cf..29ecd12292 100644 --- a/tcl/interface/ftdi/pipistrello.cfg +++ b/tcl/interface/ftdi/pipistrello.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # http://pipistrello.saanlima.com/ # http://www.saanlima.com/download/pipistrello-v2.0/pipistrello_v2_schematic.pdf adapter driver ftdi diff --git a/tcl/interface/ftdi/redbee-econotag.cfg b/tcl/interface/ftdi/redbee-econotag.cfg index 35bedfa7e6..d0d3d833e1 100644 --- a/tcl/interface/ftdi/redbee-econotag.cfg +++ b/tcl/interface/ftdi/redbee-econotag.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Redwire Redbee-Econotag # diff --git a/tcl/interface/ftdi/redbee-usb.cfg b/tcl/interface/ftdi/redbee-usb.cfg index a571766109..98805536d2 100644 --- a/tcl/interface/ftdi/redbee-usb.cfg +++ b/tcl/interface/ftdi/redbee-usb.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Redwire Redbee-USB # diff --git a/tcl/interface/ftdi/rowley-cc-arm-swd.cfg b/tcl/interface/ftdi/rowley-cc-arm-swd.cfg index fb416db566..585d589c8d 100644 --- a/tcl/interface/ftdi/rowley-cc-arm-swd.cfg +++ b/tcl/interface/ftdi/rowley-cc-arm-swd.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Rowley ARM SWD Adapter # http://sites.fastspring.com/rowley/product/armswdadapter diff --git a/tcl/interface/ftdi/sheevaplug.cfg b/tcl/interface/ftdi/sheevaplug.cfg index 5929453c17..29c8688091 100644 --- a/tcl/interface/ftdi/sheevaplug.cfg +++ b/tcl/interface/ftdi/sheevaplug.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Marvel SheevaPlug Development Kit # diff --git a/tcl/interface/ftdi/signalyzer-lite.cfg b/tcl/interface/ftdi/signalyzer-lite.cfg index 9e010d3944..e6c3839c98 100644 --- a/tcl/interface/ftdi/signalyzer-lite.cfg +++ b/tcl/interface/ftdi/signalyzer-lite.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Xverve Signalyzer LITE (DT-USB-SLITE) # diff --git a/tcl/interface/ftdi/signalyzer.cfg b/tcl/interface/ftdi/signalyzer.cfg index d94c6bc7fa..fa7a7edc1e 100644 --- a/tcl/interface/ftdi/signalyzer.cfg +++ b/tcl/interface/ftdi/signalyzer.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Xverve Signalyzer Tool (DT-USB-ST) # diff --git a/tcl/interface/ftdi/sipeed-rv-debugger.cfg b/tcl/interface/ftdi/sipeed-rv-debugger.cfg new file mode 100644 index 0000000000..ca65398c6e --- /dev/null +++ b/tcl/interface/ftdi/sipeed-rv-debugger.cfg @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Interface file for BL702-based SIPEED RV Debugger +# + +adapter driver ftdi +adapter speed 6000 + +ftdi device_desc "JTAG Debugger" +ftdi vid_pid 0x0403 0x6010 +ftdi layout_init 0x0008 0x001b +ftdi layout_signal nSRST -oe 0x0020 -data 0x0020 diff --git a/tcl/interface/ftdi/snps_sdp.cfg b/tcl/interface/ftdi/snps_sdp.cfg index 7bd8387b7b..eb2aecc87a 100644 --- a/tcl/interface/ftdi/snps_sdp.cfg +++ b/tcl/interface/ftdi/snps_sdp.cfg @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (C) 2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> -# -# SPDX-License-Identifier: GPL-2.0-or-later # # Synopsys SDP Mainboard has embdded FT2232 chip, which is similar to Digilent diff --git a/tcl/interface/ftdi/stm32-stick.cfg b/tcl/interface/ftdi/stm32-stick.cfg index fd877ec77c..1d72d20e35 100644 --- a/tcl/interface/ftdi/stm32-stick.cfg +++ b/tcl/interface/ftdi/stm32-stick.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Hitex STM32-PerformanceStick # diff --git a/tcl/interface/ftdi/swd-resistor-hack.cfg b/tcl/interface/ftdi/swd-resistor-hack.cfg index 5bdb87c18c..d9e7158719 100644 --- a/tcl/interface/ftdi/swd-resistor-hack.cfg +++ b/tcl/interface/ftdi/swd-resistor-hack.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Connect TDI to SWDIO via a suitable series resistor (220-470 Ohm or # so depending on the drive capability of the target and adapter); diff --git a/tcl/interface/ftdi/ti-icdi.cfg b/tcl/interface/ftdi/ti-icdi.cfg index f6e16be846..964de76e6a 100644 --- a/tcl/interface/ftdi/ti-icdi.cfg +++ b/tcl/interface/ftdi/ti-icdi.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # This is an FTDI-based debugging solution as found on some TI boards, # e.g. CC3200 LaunchPad. diff --git a/tcl/interface/ftdi/tigard.cfg b/tcl/interface/ftdi/tigard.cfg new file mode 100644 index 0000000000..43ce0ad1d1 --- /dev/null +++ b/tcl/interface/ftdi/tigard.cfg @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Tigard: An FTDI FT2232H-based multi-protocol tool for hardware hacking. +# https://github.com/tigard-tools/tigard + +adapter driver ftdi + +ftdi device_desc "Tigard V1.1" +ftdi vid_pid 0x0403 0x6010 + +ftdi channel 1 + +ftdi layout_init 0x0038 0x003b +ftdi layout_signal nTRST -data 0x0010 +ftdi layout_signal nSRST -data 0x0020 + +# This board doesn't support open-drain reset modes since its output buffer is +# always enabled. +reset_config srst_push_pull trst_push_pull diff --git a/tcl/interface/ftdi/tumpa-lite.cfg b/tcl/interface/ftdi/tumpa-lite.cfg index 625db16b12..e3f12e3b12 100644 --- a/tcl/interface/ftdi/tumpa-lite.cfg +++ b/tcl/interface/ftdi/tumpa-lite.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TIAO USB Multi-Protocol Adapter (TUMPA) Lite # diff --git a/tcl/interface/ftdi/tumpa.cfg b/tcl/interface/ftdi/tumpa.cfg index 4491c40b73..db4311bfe1 100644 --- a/tcl/interface/ftdi/tumpa.cfg +++ b/tcl/interface/ftdi/tumpa.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TIAO USB Multi-Protocol Adapter (TUMPA) # diff --git a/tcl/interface/ftdi/turtelizer2-revB.cfg b/tcl/interface/ftdi/turtelizer2-revB.cfg index 593a545a8c..f90fc58c1b 100644 --- a/tcl/interface/ftdi/turtelizer2-revB.cfg +++ b/tcl/interface/ftdi/turtelizer2-revB.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # egnite Turtelizer 2 rev B (with SRST only) # diff --git a/tcl/interface/ftdi/turtelizer2-revC.cfg b/tcl/interface/ftdi/turtelizer2-revC.cfg index 6e19259b99..94617a1dd1 100644 --- a/tcl/interface/ftdi/turtelizer2-revC.cfg +++ b/tcl/interface/ftdi/turtelizer2-revC.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # egnite Turtelizer 2 revC (with TRST and SRST) # diff --git a/tcl/interface/ftdi/um232h.cfg b/tcl/interface/ftdi/um232h.cfg index 10f267dd0c..6be08b59cb 100644 --- a/tcl/interface/ftdi/um232h.cfg +++ b/tcl/interface/ftdi/um232h.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # FTDI UM232H as a JTAG interface # diff --git a/tcl/interface/ftdi/vpaclink.cfg b/tcl/interface/ftdi/vpaclink.cfg index 7e7f25702c..ff508f2dcd 100644 --- a/tcl/interface/ftdi/vpaclink.cfg +++ b/tcl/interface/ftdi/vpaclink.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Voipac VPACLink # diff --git a/tcl/interface/ftdi/xds100v2.cfg b/tcl/interface/ftdi/xds100v2.cfg index bda87811bb..373df4f49b 100644 --- a/tcl/interface/ftdi/xds100v2.cfg +++ b/tcl/interface/ftdi/xds100v2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Texas Instruments XDS100v2 # diff --git a/tcl/interface/ftdi/xds100v3.cfg b/tcl/interface/ftdi/xds100v3.cfg index 43a11bd354..dc722336f1 100644 --- a/tcl/interface/ftdi/xds100v3.cfg +++ b/tcl/interface/ftdi/xds100v3.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Texas Instruments XDS100 ver 3.0 # diff --git a/tcl/interface/ftdi/xt_kc705_ml605.cfg b/tcl/interface/ftdi/xt_kc705_ml605.cfg new file mode 100644 index 0000000000..dda8c0a2b6 --- /dev/null +++ b/tcl/interface/ftdi/xt_kc705_ml605.cfg @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Xilinx KC705 / ML605 with Xtensa daughtercard; onboard USB/FT2232 +# + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 +# Specify "adapter serial <identifier>" here as needed + +ftdi layout_init 0x0010 0x007b +ftdi layout_signal nTRST -data 0x0010 +ftdi layout_signal nSRST -ndata 0x0020 diff --git a/tcl/interface/imx-native.cfg b/tcl/interface/imx-native.cfg index 9e1f38d03a..01e42e34ad 100644 --- a/tcl/interface/imx-native.cfg +++ b/tcl/interface/imx-native.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Config for using NXP IMX CPU # diff --git a/tcl/interface/jlink.cfg b/tcl/interface/jlink.cfg index f9a18b05f4..181c2cc936 100644 --- a/tcl/interface/jlink.cfg +++ b/tcl/interface/jlink.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # SEGGER J-Link # diff --git a/tcl/interface/jtag_dpi.cfg b/tcl/interface/jtag_dpi.cfg index a92e131a9c..225d4d5451 100644 --- a/tcl/interface/jtag_dpi.cfg +++ b/tcl/interface/jtag_dpi.cfg @@ -1,22 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Provide support for the Cadence JTAG BFM # # Copyright (c) 2020, Ampere Computing LLC # -# 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; -# -# adapter driver jtag_dpi diff --git a/tcl/interface/jtag_hat_rpi2.cfg b/tcl/interface/jtag_hat_rpi2.cfg index 495ff0f042..cd1cbfb8af 100644 --- a/tcl/interface/jtag_hat_rpi2.cfg +++ b/tcl/interface/jtag_hat_rpi2.cfg @@ -7,31 +7,35 @@ adapter driver bcm2835gpio -bcm2835gpio_peripheral_base 0x3F000000 +bcm2835gpio peripheral_base 0x3F000000 # Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET # These depend on system clock, calibrated for stock 700MHz # bcm2835gpio_speed SPEED_COEFF SPEED_OFFSET -bcm2835gpio_speed_coeffs 146203 36 +bcm2835gpio speed_coeffs 146203 36 # Each of the JTAG lines need a gpio number set: tck tms tdi tdo # Header pin numbers: 23 22 19 21 -bcm2835gpio_jtag_nums 11 25 10 9 +adapter gpio tck -chip 0 11 +adapter gpio tms -chip 0 25 +adapter gpio tdi -chip 0 10 +adapter gpio tdo -chip 0 9 # Each of the SWD lines need a gpio number set: swclk swdio # Header pin numbers: 23 22 -bcm2835gpio_swd_nums 11 25 +adapter gpio swclk -chip 0 11 +adapter gpio swdio -chip 0 25 # Direction pin for SWDIO level shifting buffer -bcm2835gpio_swdio_dir_num 6 +adapter gpio swdio_dir -chip 0 6 # If you define trst or srst, use appropriate reset_config # Header pin numbers: TRST - 26, SRST - 18 -bcm2835gpio_trst_num 7 +adapter gpio trst -chip 0 7 #reset_config trst_only -bcm2835gpio_srst_num 24 +adapter gpio srst -chip 0 24 #reset_config srst_only # or if you have both connected diff --git a/tcl/interface/jtag_vpi.cfg b/tcl/interface/jtag_vpi.cfg index f2f90f7450..e8164abeb2 100644 --- a/tcl/interface/jtag_vpi.cfg +++ b/tcl/interface/jtag_vpi.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + adapter driver jtag_vpi # Set the VPI JTAG server port diff --git a/tcl/interface/kitprog.cfg b/tcl/interface/kitprog.cfg index 933a054088..eb9ad9804c 100644 --- a/tcl/interface/kitprog.cfg +++ b/tcl/interface/kitprog.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Cypress Semiconductor KitProg # diff --git a/tcl/interface/nds32-aice.cfg b/tcl/interface/nds32-aice.cfg deleted file mode 100644 index fcc33ec28f..0000000000 --- a/tcl/interface/nds32-aice.cfg +++ /dev/null @@ -1,15 +0,0 @@ -# -# Andes AICE -# -# http://www.andestech.com -# - -adapter driver aice -aice desc "Andes AICE adapter" -# adapter serial "C001-42163" -aice vid_pid 0x1CFC 0x0000 -aice port aice_usb -reset_config trst_and_srst -adapter speed 24000 -aice retry_times 50 -aice count_to_check_dbger 30 diff --git a/tcl/interface/nulink.cfg b/tcl/interface/nulink.cfg index e49b36cda1..2a4bc0b93b 100644 --- a/tcl/interface/nulink.cfg +++ b/tcl/interface/nulink.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Nuvoton Nu-Link in-circuit debugger/programmer # diff --git a/tcl/interface/opendous.cfg b/tcl/interface/opendous.cfg index 23fddc69cf..9c5a804c87 100644 --- a/tcl/interface/opendous.cfg +++ b/tcl/interface/opendous.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # opendous-jtag # diff --git a/tcl/interface/openjtag.cfg b/tcl/interface/openjtag.cfg index 8d015b7041..1602352db8 100644 --- a/tcl/interface/openjtag.cfg +++ b/tcl/interface/openjtag.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # OpenJTAG # diff --git a/tcl/interface/osbdm.cfg b/tcl/interface/osbdm.cfg index 6e88c0736b..e21848d893 100644 --- a/tcl/interface/osbdm.cfg +++ b/tcl/interface/osbdm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # P&E Micro OSBDM (aka OSJTAG) interface # diff --git a/tcl/interface/parport.cfg b/tcl/interface/parport.cfg index 05195f0273..b9fceeb852 100644 --- a/tcl/interface/parport.cfg +++ b/tcl/interface/parport.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Parallel port wiggler (many clones available) on port 0x378 # diff --git a/tcl/interface/parport_dlc5.cfg b/tcl/interface/parport_dlc5.cfg index 19e21ffdaf..24acea7a95 100644 --- a/tcl/interface/parport_dlc5.cfg +++ b/tcl/interface/parport_dlc5.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Xilinx Parallel Cable III 'DLC 5' (and various clones) # diff --git a/tcl/interface/raspberrypi-gpio-connector.cfg b/tcl/interface/raspberrypi-gpio-connector.cfg new file mode 100644 index 0000000000..eff73fc927 --- /dev/null +++ b/tcl/interface/raspberrypi-gpio-connector.cfg @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Config for Raspberry Pi GPIO header +# +# This is best used with a fast enough buffer but also +# is suitable for direct connection if the target voltage +# matches RPi's 3.3V and the cable is short enough. +# +# Do not forget the GND connection, e.g. pin 20 of the GPIO header. +# + +# GPIO 25 (pin 22) previously used for TMS/SWDIO is pulled-down by default. +# The JTAG/SWD specification requires pull-up at the target board +# for either signal. Connecting the signal pulled-up on the target +# to the pull-down on the adapter is not a good idea. +# GPIO 8 is pulled-up by default. +echo "Warn : TMS/SWDIO moved to GPIO 8 (pin 24). Check the wiring please!" + +# Each of the JTAG lines need a gpio number set: tck tms tdi tdo +# Header pin numbers: 23 24 19 21 +adapter gpio tck -chip 0 11 +adapter gpio tms -chip 0 8 +adapter gpio tdi -chip 0 10 +adapter gpio tdo -chip 0 9 + +# Each of the SWD lines need a gpio number set: swclk swdio +# Header pin numbers: 23 24 +adapter gpio swclk -chip 0 11 +adapter gpio swdio -chip 0 8 + +# If you define trst or srst, use appropriate reset_config +# Header pin numbers: TRST - 26, SRST - 18 + +# adapter gpio trst -chip 0 7 +# reset_config trst_only + +# adapter gpio srst -chip 0 24 +# reset_config srst_only srst_push_pull + +# or if you have both connected, +# reset_config trst_and_srst srst_push_pull diff --git a/tcl/interface/raspberrypi-native.cfg b/tcl/interface/raspberrypi-native.cfg index 634b8c95aa..7224723d63 100644 --- a/tcl/interface/raspberrypi-native.cfg +++ b/tcl/interface/raspberrypi-native.cfg @@ -1,38 +1,71 @@ -# -# Config for using Raspberry Pi's expansion header -# -# This is best used with a fast enough buffer but also -# is suitable for direct connection if the target voltage -# matches RPi's 3.3V and the cable is short enough. -# -# Do not forget the GND connection, pin 6 of the expansion header. -# +# SPDX-License-Identifier: GPL-2.0-or-later + +# Config for Raspberry Pi used as a bitbang adapter. +# https://www.raspberrypi.com/documentation/computers/raspberry-pi.html + +# Supports all models with 40-pin or 26-pin GPIO connector up to Raspberry Pi 4 B +# also supports Raspberry Pi Zero, Zero W and Zero 2 W. + +# Adapter speed calibration is computed from cpufreq/scaling_max_freq. +# Adjusts automatically if CPU is overclocked. adapter driver bcm2835gpio -bcm2835gpio peripheral_base 0x20000000 +proc read_file { name } { + if {[catch {open $name r} fd]} { + return "" + } + set result [read $fd] + close $fd + return $result +} -# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET -# These depend on system clock, calibrated for stock 700MHz -# bcm2835gpio speed SPEED_COEFF SPEED_OFFSET -bcm2835gpio speed_coeffs 113714 28 +proc measure_clock {} { + set result [exec vcgencmd measure_clock arm] + set clock_hz [lindex [split $result "="] 1] + expr { $clock_hz / 1000 } +} -# Each of the JTAG lines need a gpio number set: tck tms tdi tdo -# Header pin numbers: 23 22 19 21 -bcm2835gpio jtag_nums 11 25 10 9 +proc get_max_cpu_clock { default } { + set clock [read_file /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq] + if { $clock > 100000 } { + return $clock + } -# Each of the SWD lines need a gpio number set: swclk swdio -# Header pin numbers: 23 22 -bcm2835gpio swd_nums 11 25 + # cpufreq not available. As the last resort try Broadcom's proprietary utility + if {![catch measure_clock clock] && $clock > 100000} { + return $clock + } -# If you define trst or srst, use appropriate reset_config -# Header pin numbers: TRST - 26, SRST - 18 + echo "WARNING: Host CPU clock unknown." + echo "WARNING: Using the highest possible value $default kHz as a safe default." + echo "WARNING: Expect JTAG/SWD clock significantly slower than requested." -# bcm2835gpio trst_num 7 -# reset_config trst_only + return $default +} -# bcm2835gpio srst_num 24 -# reset_config srst_only srst_push_pull +set compat [read_file /proc/device-tree/compatible] +set clocks_per_timing_loop 4 + +if {[string match *bcm2711* $compat]} { + set speed_offset 52 +} elseif {[string match *bcm2837* $compat] || [string match *bcm2710* $compat]} { + set speed_offset 34 +} elseif {[string match *bcm2836* $compat] || [string match *bcm2709* $compat]} { + set speed_offset 36 +} elseif {[string match *bcm2835* $compat] || [string match *bcm2708* $compat]} { + set clocks_per_timing_loop 6 + set speed_offset 32 +} else { + set speed_offset 32 + echo "WARNING: Unknown type of the host SoC. Expect JTAG/SWD clock slower than requested." +} + +set clock [get_max_cpu_clock 2000000] +set speed_coeff [expr { $clock / $clocks_per_timing_loop }] + +# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET +# The coefficients depend on system clock and CPU frequency scaling. +bcm2835gpio speed_coeffs $speed_coeff $speed_offset -# or if you have both connected, -# reset_config trst_and_srst srst_push_pull +source [find interface/raspberrypi-gpio-connector.cfg] diff --git a/tcl/interface/raspberrypi2-native.cfg b/tcl/interface/raspberrypi2-native.cfg index 14c5771c46..fe9186f239 100644 --- a/tcl/interface/raspberrypi2-native.cfg +++ b/tcl/interface/raspberrypi2-native.cfg @@ -1,38 +1,6 @@ -# -# Config for using Raspberry Pi's expansion header -# -# This is best used with a fast enough buffer but also -# is suitable for direct connection if the target voltage -# matches RPi's 3.3V and the cable is short enough. -# -# Do not forget the GND connection, pin 6 of the expansion header. -# +# SPDX-License-Identifier: GPL-2.0-or-later -adapter driver bcm2835gpio +echo "WARNING: interface/raspberrypi2-native.cfg is deprecated." +echo "WARNING: Please use interface/raspberrypi-native.cfg for all Raspberry Pi models." -bcm2835gpio peripheral_base 0x3F000000 - -# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET -# These depend on system clock, calibrated for stock 700MHz -# bcm2835gpio speed SPEED_COEFF SPEED_OFFSET -bcm2835gpio speed_coeffs 146203 36 - -# Each of the JTAG lines need a gpio number set: tck tms tdi tdo -# Header pin numbers: 23 22 19 21 -bcm2835gpio jtag_nums 11 25 10 9 - -# Each of the SWD lines need a gpio number set: swclk swdio -# Header pin numbers: 23 22 -bcm2835gpio swd_nums 11 25 - -# If you define trst or srst, use appropriate reset_config -# Header pin numbers: TRST - 26, SRST - 18 - -# bcm2835gpio trst_num 7 -# reset_config trst_only - -# bcm2835gpio srst_num 24 -# reset_config srst_only srst_push_pull - -# or if you have both connected, -# reset_config trst_and_srst srst_push_pull +source [find interface/raspberrypi-native.cfg] diff --git a/tcl/interface/rlink.cfg b/tcl/interface/rlink.cfg index 29d3ce5993..7671a3b0c9 100644 --- a/tcl/interface/rlink.cfg +++ b/tcl/interface/rlink.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Raisonance RLink # diff --git a/tcl/interface/rshim.cfg b/tcl/interface/rshim.cfg index accabf534e..1d5da593e7 100644 --- a/tcl/interface/rshim.cfg +++ b/tcl/interface/rshim.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # BlueField SoC in-circuit debugger/programmer # diff --git a/tcl/interface/stlink-dap.cfg b/tcl/interface/stlink-dap.cfg index 5a7d2e9aea..99c81c180c 100644 --- a/tcl/interface/stlink-dap.cfg +++ b/tcl/interface/stlink-dap.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # STMicroelectronics ST-LINK/V1, ST-LINK/V2, ST-LINK/V2-1, STLINK-V3 in-circuit # debugger/programmer @@ -9,7 +11,7 @@ # adapter driver st-link -st-link vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 +st-link vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 0x0483 0x3755 0x0483 0x3757 # transport select dapdirect_jtag # transport select dapdirect_swd diff --git a/tcl/interface/stlink-v1.cfg b/tcl/interface/stlink-v1.cfg index 0004227251..96ed088d0c 100644 --- a/tcl/interface/stlink-v1.cfg +++ b/tcl/interface/stlink-v1.cfg @@ -1,2 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + echo "WARNING: interface/stlink-v1.cfg is deprecated, please switch to interface/stlink.cfg" source [find interface/stlink.cfg] diff --git a/tcl/interface/stlink-v2-1.cfg b/tcl/interface/stlink-v2-1.cfg index 62f37dc336..d2baad47d8 100644 --- a/tcl/interface/stlink-v2-1.cfg +++ b/tcl/interface/stlink-v2-1.cfg @@ -1,2 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + echo "WARNING: interface/stlink-v2-1.cfg is deprecated, please switch to interface/stlink.cfg" source [find interface/stlink.cfg] diff --git a/tcl/interface/stlink-v2.cfg b/tcl/interface/stlink-v2.cfg index 070e469584..400411e9cb 100644 --- a/tcl/interface/stlink-v2.cfg +++ b/tcl/interface/stlink-v2.cfg @@ -1,2 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + echo "WARNING: interface/stlink-v2.cfg is deprecated, please switch to interface/stlink.cfg" source [find interface/stlink.cfg] diff --git a/tcl/interface/stlink.cfg b/tcl/interface/stlink.cfg index 8ac9b579f7..8578bf2199 100644 --- a/tcl/interface/stlink.cfg +++ b/tcl/interface/stlink.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # STMicroelectronics ST-LINK/V1, ST-LINK/V2, ST-LINK/V2-1, STLINK-V3 in-circuit # debugger/programmer @@ -6,7 +8,7 @@ adapter driver hla hla_layout stlink hla_device_desc "ST-LINK" -hla_vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 +hla_vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 0x0483 0x3755 0x0483 0x3757 # Optionally specify the serial number of ST-LINK/V2 usb device. ST-LINK/V2 # devices seem to have serial numbers with unreadable characters. ST-LINK/V2 diff --git a/tcl/interface/sysfsgpio-raspberrypi.cfg b/tcl/interface/sysfsgpio-raspberrypi.cfg index 0030560ca9..d2095a9fe2 100644 --- a/tcl/interface/sysfsgpio-raspberrypi.cfg +++ b/tcl/interface/sysfsgpio-raspberrypi.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Config for using RaspberryPi's expansion header # diff --git a/tcl/interface/ti-icdi.cfg b/tcl/interface/ti-icdi.cfg index 5cf6e37be5..db4e1e0a04 100644 --- a/tcl/interface/ti-icdi.cfg +++ b/tcl/interface/ti-icdi.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI Stellaris In-Circuit Debug Interface (ICDI) Board # diff --git a/tcl/interface/ulink.cfg b/tcl/interface/ulink.cfg index 164b990a19..89a02e95e8 100644 --- a/tcl/interface/ulink.cfg +++ b/tcl/interface/ulink.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Keil ULINK running OpenULINK firmware. # diff --git a/tcl/interface/usb-jtag.cfg b/tcl/interface/usb-jtag.cfg index bbfb076d1b..039c748b37 100644 --- a/tcl/interface/usb-jtag.cfg +++ b/tcl/interface/usb-jtag.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # ixo-usb-jtag - Emulation of a Altera Bus Blaster I on a Cypress FX2 IC. # # The ixo-usb-jtag firmware can be loaded onto a bunch of different hardware diff --git a/tcl/interface/usbprog.cfg b/tcl/interface/usbprog.cfg index f65c1d473d..4f04b147e1 100644 --- a/tcl/interface/usbprog.cfg +++ b/tcl/interface/usbprog.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Embedded Projects USBprog # diff --git a/tcl/interface/vdebug.cfg b/tcl/interface/vdebug.cfg index 9cca6aaab4..7350bb9a91 100644 --- a/tcl/interface/vdebug.cfg +++ b/tcl/interface/vdebug.cfg @@ -30,4 +30,4 @@ tcl_port disabled vdebug batching 1 # Polling values -vdebug polling 100 1000 \ No newline at end of file +vdebug polling 100 1000 diff --git a/tcl/interface/vsllink.cfg b/tcl/interface/vsllink.cfg index d40dbb4293..f780c896a9 100644 --- a/tcl/interface/vsllink.cfg +++ b/tcl/interface/vsllink.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Versaloon Link -- VSLLink # diff --git a/tcl/interface/xds110.cfg b/tcl/interface/xds110.cfg index 74122c3e6f..aff0f38fc0 100644 --- a/tcl/interface/xds110.cfg +++ b/tcl/interface/xds110.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Texas Instruments XDS110 # diff --git a/tcl/mem_helper.tcl b/tcl/mem_helper.tcl index 1c860119a4..0229d54b78 100644 --- a/tcl/mem_helper.tcl +++ b/tcl/mem_helper.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Helper for common memory read/modify/write procedures # mrw: "memory read word", returns value of $reg diff --git a/tcl/memory.tcl b/tcl/memory.tcl index ac273451dc..b111749954 100644 --- a/tcl/memory.tcl +++ b/tcl/memory.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # MEMORY # # All Memory regions have two components. diff --git a/tcl/mmr_helpers.tcl b/tcl/mmr_helpers.tcl index d9b6e63834..5c37fcfdc1 100644 --- a/tcl/mmr_helpers.tcl +++ b/tcl/mmr_helpers.tcl @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later proc proc_exists { NAME } { set n [info commands $NAME] @@ -70,3 +71,22 @@ proc show_mmr_bitfield { MSB LSB VAL FIELDNAME FIELDVALUES } { } echo [format "%-15s: %d (0x%0*x) %s" $FIELDNAME $nval $width $nval $sval ] } + +# Give: ADDR - address of the register. +# BIT - bit's number. + +proc get_mmr_bit { ADDR BIT } { + set val [memread32 $ADDR] + set bit_val [expr {$val & [expr {1 << $BIT}]}] + return $bit_val +} + + +# Give: ADDR - address of the register. +# MSB - MSB bit's number. +# LSB - LSB bit's number. + +proc get_mmr_bitfield { ADDR MSB LSB } { + set rval [memread32 $ADDR] + return normalize_bitfield $rval $MSB $LSB +} diff --git a/tcl/target/1986Be1T.cfg b/tcl/target/1986Be1T.cfg index b7c9d63316..a3172ccab1 100644 --- a/tcl/target/1986Be1T.cfg +++ b/tcl/target/1986Be1T.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # 1986ВЕ1Т # http://milandr.ru/index.php?mact=Products,cntnt01,details,0&cntnt01productid=236&cntnt01returnid=68 diff --git a/tcl/target/K1879x61R.cfg b/tcl/target/K1879x61R.cfg index 0a8467f49b..8dd330d054 100644 --- a/tcl/target/K1879x61R.cfg +++ b/tcl/target/K1879x61R.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # СБИС К1879ХБ1Я # http://www.module.ru/catalog/micro/mikroshema_dekodera_cifrovogo_televizionnogo_signala_sbis_k1879hb1ya/ diff --git a/tcl/target/adsp-sc58x.cfg b/tcl/target/adsp-sc58x.cfg index 6073bb2129..3dcfc91f35 100644 --- a/tcl/target/adsp-sc58x.cfg +++ b/tcl/target/adsp-sc58x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Analog Devices ADSP-SC58x (ARM Cortex-A5 plus one or two SHARC+ DSPs) # diff --git a/tcl/target/aduc702x.cfg b/tcl/target/aduc702x.cfg index 9c756be3f8..c9037100fe 100644 --- a/tcl/target/aduc702x.cfg +++ b/tcl/target/aduc702x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { diff --git a/tcl/target/aducm360.cfg b/tcl/target/aducm360.cfg index b381728f1c..5cfb4830ca 100644 --- a/tcl/target/aducm360.cfg +++ b/tcl/target/aducm360.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # This file was created using as references the stm32f1x.cfg and aduc702x.cfg # diff --git a/tcl/target/allwinner_v3s.cfg b/tcl/target/allwinner_v3s.cfg index d8d78bdc7f..437bd956df 100644 --- a/tcl/target/allwinner_v3s.cfg +++ b/tcl/target/allwinner_v3s.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is the config for an Allwinner V3/V3s (sun8iw8). # # Notes: diff --git a/tcl/target/alphascale_asm9260t.cfg b/tcl/target/alphascale_asm9260t.cfg index 7892ea2655..735555e3e2 100644 --- a/tcl/target/alphascale_asm9260t.cfg +++ b/tcl/target/alphascale_asm9260t.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { diff --git a/tcl/target/altera_fpgasoc.cfg b/tcl/target/altera_fpgasoc.cfg index 0fc8d6735e..a98b346c6c 100644 --- a/tcl/target/altera_fpgasoc.cfg +++ b/tcl/target/altera_fpgasoc.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Altera cyclone V SoC family, 5Cxxx # diff --git a/tcl/target/altera_fpgasoc_arria10.cfg b/tcl/target/altera_fpgasoc_arria10.cfg index c9c5ab66f8..fe583799fe 100644 --- a/tcl/target/altera_fpgasoc_arria10.cfg +++ b/tcl/target/altera_fpgasoc_arria10.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Intel (Altera) Arria10 FPGA SoC if { [info exists CHIPNAME] } { diff --git a/tcl/target/am335x.cfg b/tcl/target/am335x.cfg index cb3e06c95d..208ebf5610 100644 --- a/tcl/target/am335x.cfg +++ b/tcl/target/am335x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/icepick.cfg] if { [info exists CHIPNAME] } { diff --git a/tcl/target/am437x.cfg b/tcl/target/am437x.cfg index e954fd23be..5350927583 100644 --- a/tcl/target/am437x.cfg +++ b/tcl/target/am437x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/icepick.cfg] source [find mem_helper.tcl] diff --git a/tcl/target/amdm37x.cfg b/tcl/target/amdm37x.cfg index 3db24b458b..d9adae9047 100644 --- a/tcl/target/amdm37x.cfg +++ b/tcl/target/amdm37x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Copyright (C) 2010-2011 by Karl Kurbjun # Copyright (C) 2009-2011 by Øyvind Harboe diff --git a/tcl/target/ampere_emag.cfg b/tcl/target/ampere_emag.cfg index 2e828de869..0b0bd9e88d 100644 --- a/tcl/target/ampere_emag.cfg +++ b/tcl/target/ampere_emag.cfg @@ -1,22 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # OpenOCD Target Configuration for eMAG ARMv8 Processor # # Copyright (c) 2019-2021, Ampere Computing LLC # -# 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; -# -# # # Configure defaults for target diff --git a/tcl/target/ampere_qs_mq.cfg b/tcl/target/ampere_qs_mq.cfg new file mode 100644 index 0000000000..0e83766bbb --- /dev/null +++ b/tcl/target/ampere_qs_mq.cfg @@ -0,0 +1,333 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# OpenOCD Target Configuration for Ampere Altra ("Quicksilver") and +# Ampere Altra Max ("Mystique") processors +# +# Copyright (c) 2019-2022, Ampere Computing LLC + +# Command Line Argument Description +# +# SPLITSMP +# Only used for dual socket systems. Do not use for a single socket setup. +# Option pertains to the ARMv8 target core naming in a dual socket setup. +# If specified, name all ARMv8 cores per socket as individual SMP sessions. +# If not specified, name ARMv8 cores from both sockets as one SMP session. +# This option is used in conjunction with the SMP_STR board file option. +# Syntax: -c "set SPLITSMP {}" +# +# PHYS_IDX +# Enable OpenOCD ARMv8 core target physical indexing. +# If not specified, defaults to OpenOCD ARMv8 core target logical indexing. +# Syntax: -c "set PHYS_IDX {}" +# +# CHIPNAME +# Specifies the name of the chip. +# Will typically be either qs, qs0, qs1, mq, mq0 or mq1. +# If not specified, defaults to qs. +# Syntax: -c "set CHIPNAME {qs}" +# +# SYSNAME +# Specifies the name of the system. +# Will typically be either qs or mq. +# If not specified, defaults to qs. +# Syntax: -c "set SYSNAME {qs}" +# +# Life-Cycle State (LCS) +# If not specified, defaults to "Secure LCS". +# LCS=0, "Secure LCS" +# LCS=1, "Chip Manufacturing LCS" +# Syntax: -c "set LCS {0}" +# Syntax: -c "set LCS {1}" +# +# CORELIST +# Specify available physical cores by number. +# Example syntax to connect to physical cores 16 and 17. +# Syntax: -c "set CORELIST {16 17}" +# +# COREMASK_LO +# Specify available physical cores 0-63 by mask. +# Example syntax to connect to physical cores 16 and 17. +# Syntax: -c "set COREMASK_LO {0x0000000000030000}" +# +# COREMASK_HI +# Specify available physical cores 64 and above by mask. +# Example syntax to connect to physical cores 94 and 95. +# Syntax: -c "set COREMASK_HI {0x00000000C0000000}" +# +# ARMV8_TAPID +# Can override the ARMV8 TAPID default value if necessary. +# Experimental Use. Most users will not use this option. +# Syntax: -c "set ARMV8_TAPID {0x3BA06477}" +# +# SMPMPRO_TAPID +# Can override the SMPMPRO TAPID default value if necessary. +# Experimental Use. Most users will not use this option. +# Syntax: -c "set SMPMPRO_TAPID {0x4BA00477}" +# +# +# Board File Argument Description +# These optional arguments are defined in the board file and +# referenced by the target file. See the corresponding board +# files for examples of their use. +# +# SMP_STR +# This option is used primarily for a dual socket system and it is not +# recommended for a single socket setup. This option configures whether +# the SMP ARMv8 core grouping is maintained at the board or target cfg level. +# Specify the option if the SMP core grouping is defined at the board level. +# Do not specify if the SMP core grouping is defined at the chip level. +# If not specified, defaults to SMP core grouping defined per socket. +# If specified, "SMP_STR=target smp", the SMP core grouping is maintained +# at the board cfg level. +# Used in conjunction with the SPLITSMP option to group two chips into +# a single SMP configuration or maintain as two separate SMP sessions. +# +# CORE_INDEX_OFFSET +# Specifies the starting logical core index value. +# Used for dual-socket systems. +# For socket #0, set to 0. +# For socket #1, set the starting logical core based from +# the last logical core on socket #0. +# If not specified, defaults to 0. +# + +# +# Configure defaults for target. +# Can be overridden in board configuration file. +# + +if { [info exists SMP_STR] } { + # SMP configured at the dual socket board level + set _SMP_STR $SMP_STR +} else { + # SMP configured at the single socket target level + set _SMP_STR "target smp" +} + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME qs +} + +if { [info exists SYSNAME] } { + set _SYSNAME $SYSNAME +} else { + set _SYSNAME qs +} + +if { [info exists CORE_INDEX_OFFSET] } { + set _CORE_INDEX_OFFSET $CORE_INDEX_OFFSET +} else { + set _CORE_INDEX_OFFSET 0 +} + +if { [info exists ENDIAN] } { + set _ENDIAN $ENDIAN +} else { + set _ENDIAN little +} + +if { [info exists ARMV8_TAPID] } { + set _ARMV8_TAPID $ARMV8_TAPID +} else { + if { [info exists MQ_ENABLE] } { + # Configure for Mystique + set _ARMV8_TAPID 0x3BA06477 + set _MAX_CORE 128 + } else { + # Configure for Quicksilver + set _ARMV8_TAPID 0x2BA06477 + set _MAX_CORE 80 + } +} + +if { [info exists SMPMPRO_TAPID] } { + set _SMPMPRO_TAPID $SMPMPRO_TAPID +} else { + set _SMPMPRO_TAPID 0x4BA00477 +} + +if { [info exists CORELIST] } { + set _CORELIST $CORELIST +} else { + if { [info exists COREMASK_LO] } { + set _COREMASK_LO $COREMASK_LO + } else { + set _COREMASK_LO 0x0 + } + + if { [info exists COREMASK_HI] } { + set _COREMASK_HI $COREMASK_HI + } else { + set _COREMASK_HI 0x0 + } + + set _CORELIST {} + + set _MASK 0x1 + for {set i 0} {$i < 64} {incr i} { + if { [expr {$_COREMASK_LO & $_MASK}] != 0x0 } { + set _CORELIST "$_CORELIST $i" + } + set _MASK [expr {$_MASK << 0x1}] + } + + set _MASK 0x1 + for {} {$i < $_MAX_CORE} {incr i} { + if { [expr {$_COREMASK_HI & $_MASK}] != 0x0 } { + set _CORELIST "$_CORELIST $i" + } + set _MASK [expr {$_MASK << 0x1}] + } +} + +# +# Definition of target names +# +set _TARGETNAME_PMPRO pmpro +set _TARGETNAME_SMPRO smpro +set _TARGETNAME_ARMV8 armv8 + +# +# Configure JTAG TAPs - TAP chain declaration order is important +# + +jtag newtap $_CHIPNAME pmpro.tap -irlen 4 -ircapture 0x1 -irmask 0x3 -expected-id $_SMPMPRO_TAPID +set _TAPNAME_PMPRO $_CHIPNAME.$_TARGETNAME_PMPRO.tap + +jtag newtap $_CHIPNAME smpro.tap -irlen 4 -ircapture 0x1 -irmask 0x3 -expected-id $_SMPMPRO_TAPID +set _TAPNAME_SMPRO $_CHIPNAME.$_TARGETNAME_SMPRO.tap + +jtag newtap $_CHIPNAME armv8.tap -irlen 4 -ircapture 0x1 -irmask 0x3 -expected-id $_ARMV8_TAPID +set _TAPNAME_ARMV8 $_CHIPNAME.$_TARGETNAME_ARMV8.tap + +set _DAPNAME_PMPRO $_CHIPNAME.$_TARGETNAME_PMPRO.dap +set _DAPNAME_SMPRO $_CHIPNAME.$_TARGETNAME_SMPRO.dap +set _DAPNAME_ARMV8 $_CHIPNAME.$_TARGETNAME_ARMV8.dap + +set _AP_PMPRO_AHB 0 +set _AP_SMPRO_AHB 0 +set _AP_ARMV8_APB 0x00010000 +set _AP_ARMV8_AXI 0x00020000 + +# +# Configure JTAG DAPs +# + +dap create $_DAPNAME_PMPRO -chain-position $_TAPNAME_PMPRO -adiv5 +dap create $_DAPNAME_SMPRO -chain-position $_TAPNAME_SMPRO -adiv5 +dap create $_DAPNAME_ARMV8 -chain-position $_TAPNAME_ARMV8 -adiv6 + +if { [info exists LCS] && [expr {"$LCS"!="0"}] } { + # + # Create the DAP AHB-AP MEM-AP target for the PMPRO CPU + # + + target create $_CHIPNAME.$_TARGETNAME_PMPRO.ahb mem_ap -endian $_ENDIAN -dap $_DAPNAME_PMPRO -ap-num $_AP_PMPRO_AHB + + # + # Configure target PMPRO CPU + # + + target create $_CHIPNAME.$_TARGETNAME_PMPRO cortex_m -endian $_ENDIAN -dap $_DAPNAME_PMPRO -ap-num $_AP_PMPRO_AHB + + # + # Create the DAP AHB-AP MEM-AP target for the SMPRO CPU + # + + target create $_CHIPNAME.$_TARGETNAME_SMPRO.ahb mem_ap -endian $_ENDIAN -dap $_DAPNAME_SMPRO -ap-num $_AP_SMPRO_AHB + + # + # Configure target SMPRO CPU + # + + target create $_CHIPNAME.$_TARGETNAME_SMPRO cortex_m -endian $_ENDIAN -dap $_DAPNAME_SMPRO -ap-num $_AP_SMPRO_AHB +} + +# Create the DAP APB-AP MEM-AP target for the ARMV8 cores +target create $_CHIPNAME.$_TARGETNAME_ARMV8.apb mem_ap -endian $_ENDIAN -dap $_DAPNAME_ARMV8 -ap-num $_AP_ARMV8_APB + +# Create the DAP AXI-AP MEM-AP target for the ARMV8 cores +target create $_CHIPNAME.$_TARGETNAME_ARMV8.axi mem_ap -endian $_ENDIAN -dap $_DAPNAME_ARMV8 -ap-num $_AP_ARMV8_AXI + +# Set CSW register value default correctly for AXI accessible device memory: +# Select the correct Access Port Number +$_DAPNAME_ARMV8 apsel $_AP_ARMV8_AXI +# First set the CSW to OpenOCD's internal default +$_DAPNAME_ARMV8 apcsw default +# Set Domain[1:0]=b'11 (CSW[14:13]=b'11) +# Set Cache[3:0]=b'0000 (CSW[27:24]=b'0000) +# Porter Cfg registers require secure access, AxPROT[1] (CSW[29]) must be b'0'. +# Set AxPROT[2:0]=b'000 (CSW[30:28]=b'000) for an Unpriveleged, Secure, Data access. +$_DAPNAME_ARMV8 apcsw 0x00006000 0x7F006000 + +# +# Configure target CPUs +# + +set logical_index $_CORE_INDEX_OFFSET + +foreach physical_index $_CORELIST { + if { [info exists PHYS_IDX] } { + set logical_index [expr {$physical_index + $_CORE_INDEX_OFFSET}] + } + + # Format a string to reference which CPU target to use + if { [info exists SPLITSMP] } { + eval "set _TARGETNAME $_CHIPNAME.${_TARGETNAME_ARMV8}_$logical_index" + } else { + eval "set _TARGETNAME $_SYSNAME.${_TARGETNAME_ARMV8}_$logical_index" + } + + # Create and configure Cross Trigger Interface (CTI) - required for halt and resume + set _CTINAME $_TARGETNAME.cti + set _offset [expr {(0x00100000 * $physical_index) + (0x00200000 * ($physical_index>>1))}] + cti create $_CTINAME -dap $_DAPNAME_ARMV8 -ap-num $_AP_ARMV8_APB -baseaddr [expr {0xA0220000 + $_offset}] + + # Create the target + target create $_TARGETNAME aarch64 -endian $_ENDIAN \ + -dap $_DAPNAME_ARMV8 -ap-num $_AP_ARMV8_APB -dbgbase [expr {0xA0210000 + $_offset}] \ + -rtos hwthread -cti $_CTINAME -coreid $logical_index + + # Build string used to enable SMP mode for the ARMv8 CPU cores + set _SMP_STR "$_SMP_STR $_TARGETNAME" + + # Clear CTI output/input enables that are not configured by OpenOCD for aarch64 + $_TARGETNAME configure -event reset-init [subst { + $_CTINAME write INEN0 0x00000000 + $_CTINAME write INEN1 0x00000000 + $_CTINAME write INEN2 0x00000000 + $_CTINAME write INEN3 0x00000000 + $_CTINAME write INEN4 0x00000000 + $_CTINAME write INEN5 0x00000000 + $_CTINAME write INEN6 0x00000000 + $_CTINAME write INEN7 0x00000000 + $_CTINAME write INEN8 0x00000000 + + $_CTINAME write OUTEN0 0x00000000 + $_CTINAME write OUTEN1 0x00000000 + $_CTINAME write OUTEN2 0x00000000 + $_CTINAME write OUTEN3 0x00000000 + $_CTINAME write OUTEN4 0x00000000 + $_CTINAME write OUTEN5 0x00000000 + $_CTINAME write OUTEN6 0x00000000 + $_CTINAME write OUTEN7 0x00000000 + $_CTINAME write OUTEN8 0x00000000 + }] + + incr logical_index +} + +if { [info exists SMP_STR] } { + # Return updated SMP configuration string back to board level + set SMP_STR $_SMP_STR +} else { + # For single socket per SMP configuration, evaluate the string + eval $_SMP_STR +} + +if { [info exists CORE_INDEX_OFFSET] } { + # For multi-socket, return total number of cores back to board level + set CORE_INDEX_OFFSET $logical_index +} diff --git a/tcl/target/ar71xx.cfg b/tcl/target/ar71xx.cfg index 57833f4185..792b68f3ab 100644 --- a/tcl/target/ar71xx.cfg +++ b/tcl/target/ar71xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Atheros AR71xx MIPS 24Kc SoC. # tested on PB44 refererence board diff --git a/tcl/target/arm_corelink_sse200.cfg b/tcl/target/arm_corelink_sse200.cfg index ca30649ced..7327d05a0e 100644 --- a/tcl/target/arm_corelink_sse200.cfg +++ b/tcl/target/arm_corelink_sse200.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Configuration script for Arm CoreLink SSE-200 Subsystem based IoT SoCs. # diff --git a/tcl/target/armada370.cfg b/tcl/target/armada370.cfg index 71652748f3..ccf4b3606a 100644 --- a/tcl/target/armada370.cfg +++ b/tcl/target/armada370.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # armada370 -- support for the Marvell Armada/370 CPU family # diff --git a/tcl/target/at32ap7000.cfg b/tcl/target/at32ap7000.cfg index 8573aa1c46..bbae247599 100644 --- a/tcl/target/at32ap7000.cfg +++ b/tcl/target/at32ap7000.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Atmel AT32AP7000 # # This is the only core in the now-inactive high end AVR32 product line, diff --git a/tcl/target/at91r40008.cfg b/tcl/target/at91r40008.cfg index 912bd0ea2f..66d32ae300 100644 --- a/tcl/target/at91r40008.cfg +++ b/tcl/target/at91r40008.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # AT91R40008 target configuration file # TRST is tied to SRST on the AT91X40 family. diff --git a/tcl/target/at91rm9200.cfg b/tcl/target/at91rm9200.cfg index 3d9a8d9b58..1bc1287c3b 100644 --- a/tcl/target/at91rm9200.cfg +++ b/tcl/target/at91rm9200.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Atmel AT91rm9200 # http://atmel.com/products/at91/ diff --git a/tcl/target/at91sam3XXX.cfg b/tcl/target/at91sam3XXX.cfg index 7d01ccdb0c..ba1c3c563e 100644 --- a/tcl/target/at91sam3XXX.cfg +++ b/tcl/target/at91sam3XXX.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for ATMEL sam3, a Cortex-M3 chip # # at91sam3u4e diff --git a/tcl/target/at91sam3ax_4x.cfg b/tcl/target/at91sam3ax_4x.cfg index 78ca79f694..4e0cf79a7e 100644 --- a/tcl/target/at91sam3ax_4x.cfg +++ b/tcl/target/at91sam3ax_4x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # common stuff source [find target/at91sam3ax_xx.cfg] diff --git a/tcl/target/at91sam3ax_8x.cfg b/tcl/target/at91sam3ax_8x.cfg index 2bb66fbc45..46d580d323 100644 --- a/tcl/target/at91sam3ax_8x.cfg +++ b/tcl/target/at91sam3ax_8x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # common stuff source [find target/at91sam3ax_xx.cfg] diff --git a/tcl/target/at91sam3ax_xx.cfg b/tcl/target/at91sam3ax_xx.cfg index 5e01d665d5..7837f69ef5 100644 --- a/tcl/target/at91sam3ax_xx.cfg +++ b/tcl/target/at91sam3ax_xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for ATMEL sam3, a Cortex-M3 chip # # at91sam3A4C diff --git a/tcl/target/at91sam3nXX.cfg b/tcl/target/at91sam3nXX.cfg index 3450c2626e..9b20373b6f 100644 --- a/tcl/target/at91sam3nXX.cfg +++ b/tcl/target/at91sam3nXX.cfg @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later # # Configuration for Atmel's SAM3N series diff --git a/tcl/target/at91sam3sXX.cfg b/tcl/target/at91sam3sXX.cfg index 09146bd0fe..a2afda2af2 100644 --- a/tcl/target/at91sam3sXX.cfg +++ b/tcl/target/at91sam3sXX.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for ATMEL sam3, a Cortex-M3 chip # # at91sam3s4c diff --git a/tcl/target/at91sam3u1c.cfg b/tcl/target/at91sam3u1c.cfg index dc5c82c078..b26662bd38 100644 --- a/tcl/target/at91sam3u1c.cfg +++ b/tcl/target/at91sam3u1c.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # common stuff source [find target/at91sam3uxx.cfg] diff --git a/tcl/target/at91sam3u1e.cfg b/tcl/target/at91sam3u1e.cfg index dc5c82c078..b26662bd38 100644 --- a/tcl/target/at91sam3u1e.cfg +++ b/tcl/target/at91sam3u1e.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # common stuff source [find target/at91sam3uxx.cfg] diff --git a/tcl/target/at91sam3u2c.cfg b/tcl/target/at91sam3u2c.cfg index dc5c82c078..b26662bd38 100644 --- a/tcl/target/at91sam3u2c.cfg +++ b/tcl/target/at91sam3u2c.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # common stuff source [find target/at91sam3uxx.cfg] diff --git a/tcl/target/at91sam3u2e.cfg b/tcl/target/at91sam3u2e.cfg index dc5c82c078..b26662bd38 100644 --- a/tcl/target/at91sam3u2e.cfg +++ b/tcl/target/at91sam3u2e.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # common stuff source [find target/at91sam3uxx.cfg] diff --git a/tcl/target/at91sam3u4c.cfg b/tcl/target/at91sam3u4c.cfg index 14af008b6c..fb1eeaa903 100644 --- a/tcl/target/at91sam3u4c.cfg +++ b/tcl/target/at91sam3u4c.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # common stuff source [find target/at91sam3uxx.cfg] diff --git a/tcl/target/at91sam3u4e.cfg b/tcl/target/at91sam3u4e.cfg index fbe2dd94be..1c75f82766 100644 --- a/tcl/target/at91sam3u4e.cfg +++ b/tcl/target/at91sam3u4e.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # common stuff source [find target/at91sam3uxx.cfg] diff --git a/tcl/target/at91sam3uxx.cfg b/tcl/target/at91sam3uxx.cfg index 5b1748ba4c..f084b9ba45 100644 --- a/tcl/target/at91sam3uxx.cfg +++ b/tcl/target/at91sam3uxx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for ATMEL sam3, a Cortex-M3 chip # # at91sam3u4e diff --git a/tcl/target/at91sam4XXX.cfg b/tcl/target/at91sam4XXX.cfg index ebb7eed3eb..9c30ddfbaf 100644 --- a/tcl/target/at91sam4XXX.cfg +++ b/tcl/target/at91sam4XXX.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # script for ATMEL sam4, a Cortex-M4 chip # diff --git a/tcl/target/at91sam4c32x.cfg b/tcl/target/at91sam4c32x.cfg index 5344e0c547..ddcdd12672 100644 --- a/tcl/target/at91sam4c32x.cfg +++ b/tcl/target/at91sam4c32x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for ATMEL sam4c32, a Cortex-M4 chip # diff --git a/tcl/target/at91sam4cXXX.cfg b/tcl/target/at91sam4cXXX.cfg index 3f10c61d0f..a0206ad6c2 100644 --- a/tcl/target/at91sam4cXXX.cfg +++ b/tcl/target/at91sam4cXXX.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for ATMEL sam4c, a Cortex-M4 chip # diff --git a/tcl/target/at91sam4lXX.cfg b/tcl/target/at91sam4lXX.cfg index b73babcbb1..0910e3080a 100644 --- a/tcl/target/at91sam4lXX.cfg +++ b/tcl/target/at91sam4lXX.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for ATMEL sam4l, a Cortex-M4 chip # diff --git a/tcl/target/at91sam4sXX.cfg b/tcl/target/at91sam4sXX.cfg index 8883e23ca5..2ceca00176 100644 --- a/tcl/target/at91sam4sXX.cfg +++ b/tcl/target/at91sam4sXX.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for ATMEL sam4, a Cortex-M4 chip # diff --git a/tcl/target/at91sam4sd32x.cfg b/tcl/target/at91sam4sd32x.cfg index 077b1f51f5..24e25e3a99 100644 --- a/tcl/target/at91sam4sd32x.cfg +++ b/tcl/target/at91sam4sd32x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for ATMEL sam4sd32, a Cortex-M4 chip # diff --git a/tcl/target/at91sam7a2.cfg b/tcl/target/at91sam7a2.cfg index f7a0de2d69..f8090c7555 100644 --- a/tcl/target/at91sam7a2.cfg +++ b/tcl/target/at91sam7a2.cfg @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/at91sam7se512.cfg b/tcl/target/at91sam7se512.cfg index 61b47816bf..29724944b7 100644 --- a/tcl/target/at91sam7se512.cfg +++ b/tcl/target/at91sam7se512.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # ATMEL sam7se512 # Example: the "Elektor Internet Radio" - EIR # http://www.ethernut.de/en/hardware/eir/index.html diff --git a/tcl/target/at91sam7sx.cfg b/tcl/target/at91sam7sx.cfg index a563ac0377..fee4e9ae40 100644 --- a/tcl/target/at91sam7sx.cfg +++ b/tcl/target/at91sam7sx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #use combined on interfaces or targets that can't set TRST/SRST separately reset_config srst_only srst_pulls_trst diff --git a/tcl/target/at91sam7x256.cfg b/tcl/target/at91sam7x256.cfg index e1a243523f..2ebbf22c13 100644 --- a/tcl/target/at91sam7x256.cfg +++ b/tcl/target/at91sam7x256.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #use combined on interfaces or targets that can't set TRST/SRST separately reset_config srst_only srst_pulls_trst diff --git a/tcl/target/at91sam7x512.cfg b/tcl/target/at91sam7x512.cfg index 6910e8559d..ccdcfa7995 100644 --- a/tcl/target/at91sam7x512.cfg +++ b/tcl/target/at91sam7x512.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #use combined on interfaces or targets that can't set TRST/SRST separately reset_config srst_only srst_pulls_trst diff --git a/tcl/target/at91sam9.cfg b/tcl/target/at91sam9.cfg index e0ea316173..bc90d378fa 100644 --- a/tcl/target/at91sam9.cfg +++ b/tcl/target/at91sam9.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: Atmel AT91SAM9 ###################################### diff --git a/tcl/target/at91sam9260.cfg b/tcl/target/at91sam9260.cfg index c5a07fdd99..3f74d96d84 100644 --- a/tcl/target/at91sam9260.cfg +++ b/tcl/target/at91sam9260.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: Atmel AT91SAM9260 ###################################### diff --git a/tcl/target/at91sam9260_ext_RAM_ext_flash.cfg b/tcl/target/at91sam9260_ext_RAM_ext_flash.cfg index 3e4b7d76b7..47117e91d9 100644 --- a/tcl/target/at91sam9260_ext_RAM_ext_flash.cfg +++ b/tcl/target/at91sam9260_ext_RAM_ext_flash.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: Atmel AT91SAM9260 ###################################### diff --git a/tcl/target/at91sam9261.cfg b/tcl/target/at91sam9261.cfg index 3ad141182a..07456b236c 100644 --- a/tcl/target/at91sam9261.cfg +++ b/tcl/target/at91sam9261.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: Atmel AT91SAM9261 ###################################### diff --git a/tcl/target/at91sam9263.cfg b/tcl/target/at91sam9263.cfg index d2ee113b2c..3e2585c7ff 100644 --- a/tcl/target/at91sam9263.cfg +++ b/tcl/target/at91sam9263.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: Atmel AT91SAM9263 ###################################### diff --git a/tcl/target/at91sam9g10.cfg b/tcl/target/at91sam9g10.cfg index b49f3d9d28..6836773495 100644 --- a/tcl/target/at91sam9g10.cfg +++ b/tcl/target/at91sam9g10.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: Atmel AT91SAM9G10 ###################################### diff --git a/tcl/target/at91sam9g20.cfg b/tcl/target/at91sam9g20.cfg index 6e45df20a8..4fc204850f 100644 --- a/tcl/target/at91sam9g20.cfg +++ b/tcl/target/at91sam9g20.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: Atmel AT91SAM9G20 ###################################### diff --git a/tcl/target/at91sam9g45.cfg b/tcl/target/at91sam9g45.cfg index 7323679b9e..5e6e8185d9 100644 --- a/tcl/target/at91sam9g45.cfg +++ b/tcl/target/at91sam9g45.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: Atmel AT91SAM9G45 ###################################### diff --git a/tcl/target/at91sam9rl.cfg b/tcl/target/at91sam9rl.cfg index db0522928b..b25342760a 100644 --- a/tcl/target/at91sam9rl.cfg +++ b/tcl/target/at91sam9rl.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: Atmel AT91SAM9RL ###################################### diff --git a/tcl/target/at91sama5d2.cfg b/tcl/target/at91sama5d2.cfg index 65e5217e1e..30ddc92a9d 100644 --- a/tcl/target/at91sama5d2.cfg +++ b/tcl/target/at91sama5d2.cfg @@ -1,5 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later # +# SAMA5D2 devices support both JTAG and SWD transports. +# # The JTAG connection is disabled at reset, and during the ROM Code execution. # It is re-enabled when the ROM code jumps in the boot file copied from an # external Flash memory into the internalSRAM, or when the ROM code launches @@ -12,14 +14,28 @@ # - if enabled, boundary Scan mode is activated. JTAG ID Code value is 0x05B3F03F. # - if disabled, ICE mode is activated. Debug Port JTAG IDCODE value is 0x5BA00477 # + +source [find target/swj-dp.tcl] + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x5ba00477 + } else { + # SWD IDCODE (single drop, arm) + set _CPUTAPID 0x5ba02477 + } +} + if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME at91sama5d2 } -jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ - -expected-id 0x5ba00477 +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # Cortex-A5 target set _TARGETNAME $_CHIPNAME.cpu_a5 diff --git a/tcl/target/at91samdXX.cfg b/tcl/target/at91samdXX.cfg index 9a396fa139..5132109ba8 100644 --- a/tcl/target/at91samdXX.cfg +++ b/tcl/target/at91samdXX.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # script for Atmel SAMD, SAMR, SAML or SAMC, a Cortex-M0 chip # diff --git a/tcl/target/at91samg5x.cfg b/tcl/target/at91samg5x.cfg index 57274c0c57..cbe25f698f 100644 --- a/tcl/target/at91samg5x.cfg +++ b/tcl/target/at91samg5x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for the ATMEL samg5x Cortex-M4F chip family # diff --git a/tcl/target/atheros_ar2313.cfg b/tcl/target/atheros_ar2313.cfg index 0966c6c7ec..aa962b439c 100644 --- a/tcl/target/atheros_ar2313.cfg +++ b/tcl/target/atheros_ar2313.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { diff --git a/tcl/target/atheros_ar2315.cfg b/tcl/target/atheros_ar2315.cfg index 92ad376000..383676350e 100644 --- a/tcl/target/atheros_ar2315.cfg +++ b/tcl/target/atheros_ar2315.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { diff --git a/tcl/target/atheros_ar9331.cfg b/tcl/target/atheros_ar9331.cfg index 6ab238c881..931ac10356 100644 --- a/tcl/target/atheros_ar9331.cfg +++ b/tcl/target/atheros_ar9331.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # The Atheros AR9331 is a highly integrated and cost effective # IEEE 802.11n 1x1 2.4 GHz System- on-a-Chip (SoC) for wireless # local area network (WLAN) AP and router platforms. diff --git a/tcl/target/atheros_ar9344.cfg b/tcl/target/atheros_ar9344.cfg index b698f25034..d22bb5fb93 100644 --- a/tcl/target/atheros_ar9344.cfg +++ b/tcl/target/atheros_ar9344.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + if { [info exists CHIPNAME] } { set _CHIPNAME $_CHIPNAME } else { diff --git a/tcl/target/atmega128.cfg b/tcl/target/atmega128.cfg index 07161d5727..c9469195ee 100644 --- a/tcl/target/atmega128.cfg +++ b/tcl/target/atmega128.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # for avr set _CHIPNAME avr diff --git a/tcl/target/atmega128rfa1.cfg b/tcl/target/atmega128rfa1.cfg index cda439d77e..96a83fe9b8 100644 --- a/tcl/target/atmega128rfa1.cfg +++ b/tcl/target/atmega128rfa1.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set _CHIPNAME avr set _ENDIAN little diff --git a/tcl/target/atmega32u4.cfg b/tcl/target/atmega32u4.cfg new file mode 100644 index 0000000000..9199c741e6 --- /dev/null +++ b/tcl/target/atmega32u4.cfg @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# ATmega32U4 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME avr +} + +if { [info exists ENDIAN] } { + set _ENDIAN $ENDIAN +} else { + set _ENDIAN little +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x4958703f +} + +adapter speed 4500 + +jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME avr -endian $_ENDIAN -chain-position $_TARGETNAME + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME avr 0 0 0 0 $_TARGETNAME diff --git a/tcl/target/atsame5x.cfg b/tcl/target/atsame5x.cfg index 351a2ca2c9..5093d41b09 100644 --- a/tcl/target/atsame5x.cfg +++ b/tcl/target/atsame5x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Microchip (former Atmel) SAM E54, E53, E51 and D51 devices # with a Cortex-M4 core diff --git a/tcl/target/atsaml1x.cfg b/tcl/target/atsaml1x.cfg index 3486746f77..5a1b8f8a2b 100644 --- a/tcl/target/atsaml1x.cfg +++ b/tcl/target/atsaml1x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Microchip (formerly Atmel) SAM L1x target # diff --git a/tcl/target/atsamv.cfg b/tcl/target/atsamv.cfg index fdd835473c..7e9f6c57ef 100644 --- a/tcl/target/atsamv.cfg +++ b/tcl/target/atsamv.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # ATMEL SAMV, SAMS, and SAME chips are Cortex-M7 parts # The chips are very similar; the SAMV series just has # more peripherals and seems like the "flagship" of the diff --git a/tcl/target/avr32.cfg b/tcl/target/avr32.cfg index 8295f5e68e..e16d11439c 100644 --- a/tcl/target/avr32.cfg +++ b/tcl/target/avr32.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set _CHIPNAME avr32 set _ENDIAN big diff --git a/tcl/target/bcm281xx.cfg b/tcl/target/bcm281xx.cfg index 0715d82d81..a70a9c5e7d 100644 --- a/tcl/target/bcm281xx.cfg +++ b/tcl/target/bcm281xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # BCM281xx if { [info exists CHIPNAME] } { diff --git a/tcl/target/bcm4706.cfg b/tcl/target/bcm4706.cfg index 10b32c77d4..e5d8d19bc6 100644 --- a/tcl/target/bcm4706.cfg +++ b/tcl/target/bcm4706.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set _CHIPNAME bcm4706 set _CPUID 0x1008c17f diff --git a/tcl/target/bcm4718.cfg b/tcl/target/bcm4718.cfg index 8193914a36..cc21a5e316 100644 --- a/tcl/target/bcm4718.cfg +++ b/tcl/target/bcm4718.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set _CHIPNAME bcm4718 set _LVTAPID 0x1471617f set _CPUID 0x0008c17f diff --git a/tcl/target/bcm47xx.cfg b/tcl/target/bcm47xx.cfg index 0132bb8024..b5365e0690 100644 --- a/tcl/target/bcm47xx.cfg +++ b/tcl/target/bcm47xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + echo "Forcing reset_config to none to prevent OpenOCD from pulling SRST after the switch from LV is already performed" reset_config none diff --git a/tcl/target/bcm5352e.cfg b/tcl/target/bcm5352e.cfg index 3f0495a3ea..084ce04a84 100644 --- a/tcl/target/bcm5352e.cfg +++ b/tcl/target/bcm5352e.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set _CHIPNAME bcm5352e set _CPUID 0x0535217f diff --git a/tcl/target/bcm6348.cfg b/tcl/target/bcm6348.cfg index a9be559135..b9d444808c 100644 --- a/tcl/target/bcm6348.cfg +++ b/tcl/target/bcm6348.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set _CHIPNAME bcm6348 set _CPUID 0x0634817f diff --git a/tcl/target/bluefield.cfg b/tcl/target/bluefield.cfg index dcebb2fb11..30ed527607 100644 --- a/tcl/target/bluefield.cfg +++ b/tcl/target/bluefield.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # BlueField SoC Target set _CHIPNAME bluefield diff --git a/tcl/target/bluenrg-x.cfg b/tcl/target/bluenrg-x.cfg index ea94be9628..afa1b513b2 100644 --- a/tcl/target/bluenrg-x.cfg +++ b/tcl/target/bluenrg-x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # bluenrg-1/2 and bluenrg-lp devices support only SWD transports. # @@ -47,11 +49,14 @@ if {![using_hla]} { cortex_m reset_config sysresetreq } +set JTAG_IDCODE_B2 0x0200A041 +set JTAG_IDCODE_B1 0x0 + $_TARGETNAME configure -event halted { global WDOG_VALUE global WDOG_VALUE_SET set _JTAG_IDCODE [mrw 0x40000004] - if {$_JTAG_IDCODE != 0x0201E041} { + if {$_JTAG_IDCODE == $JTAG_IDCODE_B2 || $_JTAG_IDCODE == $JTAG_IDCODE_B1} { # Stop watchdog during halt, if enabled. Only Bluenrg-1/2 set WDOG_VALUE [mrw 0x40700008] if [expr {$WDOG_VALUE & (1 << 1)}] { @@ -64,7 +69,7 @@ $_TARGETNAME configure -event resumed { global WDOG_VALUE global WDOG_VALUE_SET set _JTAG_IDCODE [mrw 0x40000004] - if {$_JTAG_IDCODE != 0x0201E041} { + if {$_JTAG_IDCODE == $JTAG_IDCODE_B2 || $_JTAG_IDCODE == $JTAG_IDCODE_B1} { if {$WDOG_VALUE_SET} { # Restore watchdog enable value after resume. Only Bluenrg-1/2 mww 0x40700008 $WDOG_VALUE diff --git a/tcl/target/c100.cfg b/tcl/target/c100.cfg index 5b4354e909..c268ba3ba2 100644 --- a/tcl/target/c100.cfg +++ b/tcl/target/c100.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # c100 config. # This is ARM1136 dual core # this script only configures one core (that is used to run Linux) diff --git a/tcl/target/c100config.tcl b/tcl/target/c100config.tcl index e9372195a4..2545fa790c 100644 --- a/tcl/target/c100config.tcl +++ b/tcl/target/c100config.tcl @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later # board(-config) specific parameters file. diff --git a/tcl/target/c100helper.tcl b/tcl/target/c100helper.tcl index ecd7edf117..d1d3f258bc 100644 --- a/tcl/target/c100helper.tcl +++ b/tcl/target/c100helper.tcl @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later proc helpC100 {} { echo "List of useful functions for C100 processor:" diff --git a/tcl/target/c100regs.tcl b/tcl/target/c100regs.tcl index 9304808240..7be89392f8 100644 --- a/tcl/target/c100regs.tcl +++ b/tcl/target/c100regs.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Note that I basically converted # u-boot/include/asm-arm/arch/comcerto_100.h # defines diff --git a/tcl/target/cavium_cn61xx.cfg b/tcl/target/cavium_cn61xx.cfg new file mode 100644 index 0000000000..60b56a5192 --- /dev/null +++ b/tcl/target/cavium_cn61xx.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Cavium Octeon II CN61xx (PrID 0x000D9301) + +jtag newtap cpu tap0 -irlen 5 +jtag newtap cpu tap1 -irlen 5 + +target create cpu.core0 mips_mips64 -chain-position cpu.tap0 -endian big -rtos hwthread -coreid 0 +target create cpu.core1 mips_mips64 -chain-position cpu.tap1 -endian big -rtos hwthread -coreid 1 +target smp cpu.core0 cpu.core1 + +cpu.core0 configure -work-area-phys 0xffffffffa2000000 -work-area-size 0x20000 +cpu.core1 configure -work-area-phys 0xffffffffa2000000 -work-area-size 0x20000 + +targets cpu.core0 diff --git a/tcl/target/cc2538.cfg b/tcl/target/cc2538.cfg index 8d232f41f4..e4fb02ad4d 100644 --- a/tcl/target/cc2538.cfg +++ b/tcl/target/cc2538.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Config for Texas Instruments low power RF SoC CC2538 # http://www.ti.com/lit/pdf/swru319 diff --git a/tcl/target/cs351x.cfg b/tcl/target/cs351x.cfg index 8fabda67fc..e67540a866 100644 --- a/tcl/target/cs351x.cfg +++ b/tcl/target/cs351x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { diff --git a/tcl/target/davinci.cfg b/tcl/target/davinci.cfg index 5ca54aed41..54afb64289 100644 --- a/tcl/target/davinci.cfg +++ b/tcl/target/davinci.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Utility code for DaVinci-family chips # diff --git a/tcl/target/dragonite.cfg b/tcl/target/dragonite.cfg index b9d73a2859..249de25381 100644 --- a/tcl/target/dragonite.cfg +++ b/tcl/target/dragonite.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: Marvell Dragonite CPU core ###################################### diff --git a/tcl/target/dsp56321.cfg b/tcl/target/dsp56321.cfg index 78ecb3bd24..fac0ccc44b 100644 --- a/tcl/target/dsp56321.cfg +++ b/tcl/target/dsp56321.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Script for freescale DSP56321 # diff --git a/tcl/target/dsp568013.cfg b/tcl/target/dsp568013.cfg index 67d44192ee..5cf5c02d08 100644 --- a/tcl/target/dsp568013.cfg +++ b/tcl/target/dsp568013.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Script for freescale DSP568013 if { [info exists CHIPNAME] } { diff --git a/tcl/target/dsp568037.cfg b/tcl/target/dsp568037.cfg index fc57bd4354..5d868111b4 100644 --- a/tcl/target/dsp568037.cfg +++ b/tcl/target/dsp568037.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Script for freescale DSP568037 if { [info exists CHIPNAME] } { diff --git a/tcl/target/efm32.cfg b/tcl/target/efm32.cfg index d2e4eb329c..2187c0aca4 100644 --- a/tcl/target/efm32.cfg +++ b/tcl/target/efm32.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Silicon Labs (formerly Energy Micro) EFM32 target # diff --git a/tcl/target/em357.cfg b/tcl/target/em357.cfg index f39f3f4280..ddefa28e01 100644 --- a/tcl/target/em357.cfg +++ b/tcl/target/em357.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Target configuration for the Silicon Labs EM357 chips # diff --git a/tcl/target/em358.cfg b/tcl/target/em358.cfg index 92e65a4c78..63f4088770 100644 --- a/tcl/target/em358.cfg +++ b/tcl/target/em358.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Target configuration for the Silicon Labs EM358 chips # diff --git a/tcl/target/epc9301.cfg b/tcl/target/epc9301.cfg index 252bbab11d..41021d522e 100644 --- a/tcl/target/epc9301.cfg +++ b/tcl/target/epc9301.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Cirrus Logic EP9301 processor on an Olimex CS-E9301 board. if { [info exists CHIPNAME] } { diff --git a/tcl/target/esi32xx.cfg b/tcl/target/esi32xx.cfg index 6be84ab07c..a8b0823dac 100644 --- a/tcl/target/esi32xx.cfg +++ b/tcl/target/esi32xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # EnSilica eSi-32xx SoC (eSi-RISC Family) # http://www.ensilica.com/risc-ip/ diff --git a/tcl/target/esp32.cfg b/tcl/target/esp32.cfg new file mode 100644 index 0000000000..b30a170247 --- /dev/null +++ b/tcl/target/esp32.cfg @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# + +# Source the ESP common configuration file. +source [find target/esp_common.cfg] + +# Target specific global variables +set _CHIPNAME "esp32" +set _CPUTAPID 0x120034e5 +set _ESP_ARCH "xtensa" +set _ONLYCPU 3 +set _FLASH_VOLTAGE 3.3 +set _ESP_SMP_TARGET 1 +set _ESP_SMP_BREAK 1 +set _ESP_EFUSE_MAC_ADDR_REG 0x3ff5A004 + +if { [info exists ESP32_ONLYCPU] } { + set _ONLYCPU $ESP32_ONLYCPU +} + +if { [info exists ESP32_FLASH_VOLTAGE] } { + set _FLASH_VOLTAGE $ESP32_FLASH_VOLTAGE +} + +proc esp32_memprot_is_enabled { } { + return 0 +} + +proc esp32_soc_reset { } { + soft_reset_halt +} + +create_esp_target $_ESP_ARCH + +source [find target/xtensa-core-esp32.cfg] diff --git a/tcl/target/esp32c2.cfg b/tcl/target/esp32c2.cfg index 2af6dd2922..42aeb0adea 100644 --- a/tcl/target/esp32c2.cfg +++ b/tcl/target/esp32c2.cfg @@ -1,30 +1,20 @@ # SPDX-License-Identifier: GPL-2.0-or-later # -# The ESP32-C2 only supports JTAG. -transport select jtag -# Source the ESP common configuration file +# Source the ESP common configuration file. source [find target/esp_common.cfg] -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME esp32c2 -} - -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - set _CPUTAPID 0x0000cc25 -} - -set _TARGETNAME $_CHIPNAME -set _CPUNAME cpu -set _TAPNAME $_CHIPNAME.$_CPUNAME - -jtag newtap $_CHIPNAME $_CPUNAME -irlen 5 -expected-id $_CPUTAPID +# Target specific global variables +set _CHIPNAME "riscv" +set _CPUTAPID 0x0000cc25 +set _ESP_ARCH "riscv" +set _ONLYCPU 1 +set _ESP_SMP_TARGET 0 +set _ESP_SMP_BREAK 0 +set _ESP_EFUSE_MAC_ADDR_REG 0x60008840 -proc esp32c2_wdt_disable { } { +# Target specific functions should be implemented for each riscv chips. +proc riscv_wdt_disable { } { # Halt event can occur during config phase (before "init" is done). # Ignore it since mww commands don't work at that time. if { [string compare [command mode] config] == 0 } { @@ -42,9 +32,9 @@ proc esp32c2_wdt_disable { } { mww 0x600080A0 0x84B00000 } -# This is almost identical with the esp32c3_soc_reset. -# Will be refactored with the other common settings. -proc esp32c2_soc_reset { } { +proc riscv_soc_reset { } { + global _RISCV_DMCONTROL + # This procedure does "digital system reset", i.e. resets # all the peripherals except for the RTC block. # It is called from reset-assert-post target event callback, @@ -52,7 +42,7 @@ proc esp32c2_soc_reset { } { # Since we need the hart to to execute a write to RTC_CNTL_SW_SYS_RST, # temporarily take it out of reset. Save the dmcontrol state before # doing so. - riscv dmi_write 0x10 0x80000001 + riscv dmi_write $_RISCV_DMCONTROL 0x80000001 # Trigger the reset mww 0x60008000 0x9c00a000 # Workaround for stuck in cpu start during calibration. @@ -62,50 +52,66 @@ proc esp32c2_soc_reset { } { sleep 10 poll # Disable the watchdogs again - esp32c2_wdt_disable + riscv_wdt_disable # Here debugger reads allresumeack and allhalted bits as set (0x330a2) # We will clean allhalted state by resuming the core. - riscv dmi_write 0x10 0x40000001 + riscv dmi_write $_RISCV_DMCONTROL 0x40000001 # Put the hart back into reset state. Note that we need to keep haltreq set. - riscv dmi_write 0x10 0x80000003 + riscv dmi_write $_RISCV_DMCONTROL 0x80000003 } -if { $_RTOS == "none" } { - target create $_TARGETNAME riscv -chain-position $_TAPNAME -} else { - target create $_TARGETNAME riscv -chain-position $_TAPNAME -rtos $_RTOS -} +proc riscv_memprot_is_enabled { } { + global _RISCV_ABS_CMD _RISCV_ABS_DATA0 -$_TARGETNAME configure -event reset-assert-post { esp32c2_soc_reset } -$_TARGETNAME configure -event halted { - esp32c2_wdt_disable -} -$_TARGETNAME configure -event examine-end { - # Need this to handle 'apptrace init' syscall correctly because semihosting is not enabled by default - arm semihosting enable - arm semihosting_resexit enable - if { [info exists _SEMIHOST_BASEDIR] } { - if { $_SEMIHOST_BASEDIR != "" } { - # TODO: cherry-pick from upstream - # https://review.openocd.org/c/openocd/+/6888 - # https://review.openocd.org/c/openocd/+/7005 - # arm semihosting_basedir $_SEMIHOST_BASEDIR - } - } -} -$_TARGETNAME configure -event gdb-attach { - halt 1000 - # by default mask interrupts while stepping - riscv set_maskisr steponly -} + # PMPADDR 0-1 covers entire valid IRAM range and PMPADDR 2-3 covers entire DRAM region + # pmpcfg0 holds the configuration for the PMP 0-3 address registers + + # read pmpcfg0 and extract into 8-bit variables. + riscv dmi_write $_RISCV_ABS_CMD 0x2203a0 + set pmpcfg0 [riscv dmi_read $_RISCV_ABS_DATA0] + + set pmp0cfg [expr {($pmpcfg0 >> (8 * 0)) & 0xFF}] + set pmp1cfg [expr {($pmpcfg0 >> (8 * 1)) & 0xFF}] + set pmp2cfg [expr {($pmpcfg0 >> (8 * 2)) & 0xFF}] + set pmp3cfg [expr {($pmpcfg0 >> (8 * 3)) & 0xFF}] + + # read PMPADDR 0-3 + riscv dmi_write $_RISCV_ABS_CMD 0x2203b0 + set pmpaddr0 [expr {[riscv dmi_read $_RISCV_ABS_DATA0] << 2}] + riscv dmi_write $_RISCV_ABS_CMD 0x2203b1 + set pmpaddr1 [expr {[riscv dmi_read $_RISCV_ABS_DATA0] << 2}] + riscv dmi_write $_RISCV_ABS_CMD 0x2203b2 + set pmpaddr2 [expr {[riscv dmi_read $_RISCV_ABS_DATA0] << 2}] + riscv dmi_write $_RISCV_ABS_CMD 0x2203b3 + set pmpaddr3 [expr {[riscv dmi_read $_RISCV_ABS_DATA0] << 2}] + + set IRAM_LOW 0x40380000 + set IRAM_HIGH 0x403C0000 + set DRAM_LOW 0x3FCA0000 + set DRAM_HIGH 0x3FCE0000 + set PMP_RWX 0x07 + set PMP_RW 0x03 -gdb_breakpoint_override hard + # The lock bit remains unset during the execution of the 2nd stage bootloader. + # Thus we do not perform a lock bit check for IRAM and DRAM regions. + + # Check OpenOCD can write and execute from IRAM. + if {$pmpaddr0 >= $IRAM_LOW && $pmpaddr1 <= $IRAM_HIGH} { + if {($pmp0cfg & $PMP_RWX) != 0 || ($pmp1cfg & $PMP_RWX) != $PMP_RWX} { + return 1 + } + } + + # Check OpenOCD can read/write entire DRAM region. + if {$pmpaddr2 >= $DRAM_LOW && $pmpaddr3 <= $DRAM_HIGH} { + if {($pmp2cfg & $PMP_RW) != 0 && ($pmp3cfg & $PMP_RW) != $PMP_RW} { + return 1 + } + } + + return 0 +} -riscv set_reset_timeout_sec 2 -riscv set_command_timeout_sec 5 -riscv set_mem_access sysbus progbuf abstract -riscv set_ebreakm on -riscv set_ebreaks on -riscv set_ebreaku on +create_esp_target $_ESP_ARCH diff --git a/tcl/target/esp32c3.cfg b/tcl/target/esp32c3.cfg index ecb9bdf534..d266ad58cd 100644 --- a/tcl/target/esp32c3.cfg +++ b/tcl/target/esp32c3.cfg @@ -1,30 +1,20 @@ # SPDX-License-Identifier: GPL-2.0-or-later # -# The ESP32-C3 only supports JTAG. -transport select jtag -# Source the ESP common configuration file +# Source the ESP common configuration file. source [find target/esp_common.cfg] -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME esp32c3 -} - -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - set _CPUTAPID 0x00005c25 -} +# Target specific global variables +set _CHIPNAME "riscv" +set _CPUTAPID 0x00005c25 +set _ESP_ARCH "riscv" +set _ONLYCPU 1 +set _ESP_SMP_TARGET 0 +set _ESP_SMP_BREAK 0 +set _ESP_EFUSE_MAC_ADDR_REG 0x60008844 -set _TARGETNAME $_CHIPNAME -set _CPUNAME cpu -set _TAPNAME $_CHIPNAME.$_CPUNAME - -jtag newtap $_CHIPNAME $_CPUNAME -irlen 5 -expected-id $_CPUTAPID - -proc esp32c3_wdt_disable { } { +# Target specific functions should be implemented for each riscv chips. +proc riscv_wdt_disable { } { # Halt event can occur during config phase (before "init" is done). # Ignore it since mww commands don't work at that time. if { [string compare [command mode] config] == 0 } { @@ -46,7 +36,9 @@ proc esp32c3_wdt_disable { } { # This is almost identical with the esp32c2_soc_reset. # Will be refactored with the other common settings. -proc esp32c3_soc_reset { } { +proc riscv_soc_reset { } { + global _RISCV_DMCONTROL + # This procedure does "digital system reset", i.e. resets # all the peripherals except for the RTC block. # It is called from reset-assert-post target event callback, @@ -54,7 +46,7 @@ proc esp32c3_soc_reset { } { # Since we need the hart to to execute a write to RTC_CNTL_SW_SYS_RST, # temporarily take it out of reset. Save the dmcontrol state before # doing so. - riscv dmi_write 0x10 0x80000001 + riscv dmi_write $_RISCV_DMCONTROL 0x80000001 # Trigger the reset mww 0x60008000 0x9c00a000 # Workaround for stuck in cpu start during calibration. @@ -64,50 +56,26 @@ proc esp32c3_soc_reset { } { sleep 10 poll # Disable the watchdogs again - esp32c3_wdt_disable + riscv_wdt_disable # Here debugger reads allresumeack and allhalted bits as set (0x330a2) # We will clean allhalted state by resuming the core. - riscv dmi_write 0x10 0x40000001 + riscv dmi_write $_RISCV_DMCONTROL 0x40000001 # Put the hart back into reset state. Note that we need to keep haltreq set. - riscv dmi_write 0x10 0x80000003 + riscv dmi_write $_RISCV_DMCONTROL 0x80000003 } -if { $_RTOS == "none" } { - target create $_TARGETNAME riscv -chain-position $_TAPNAME -} else { - target create $_TARGETNAME riscv -chain-position $_TAPNAME -rtos $_RTOS -} - -$_TARGETNAME configure -event reset-assert-post { esp32c3_soc_reset } -$_TARGETNAME configure -event halted { - esp32c3_wdt_disable -} -$_TARGETNAME configure -event examine-end { - # Need this to handle 'apptrace init' syscall correctly because semihosting is not enabled by default - arm semihosting enable - arm semihosting_resexit enable - if { [info exists _SEMIHOST_BASEDIR] } { - if { $_SEMIHOST_BASEDIR != "" } { - # TODO: cherry-pick from upstream - # https://review.openocd.org/c/openocd/+/6888 - # https://review.openocd.org/c/openocd/+/7005 - # arm semihosting_basedir $_SEMIHOST_BASEDIR - } +proc riscv_memprot_is_enabled { } { + # IRAM0 PMS lock, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_0_REG + if { [get_mmr_bit 0x600C10A8 0] != 0 } { + return 1 } + # DRAM0 PMS lock, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_0_REG + if { [get_mmr_bit 0x600C10C0 0] != 0 } { + return 1 + } + return 0 } -$_TARGETNAME configure -event gdb-attach { - halt 1000 - # by default mask interrupts while stepping - riscv set_maskisr steponly -} - -gdb_breakpoint_override hard -riscv set_reset_timeout_sec 2 -riscv set_command_timeout_sec 5 -riscv set_mem_access sysbus progbuf abstract -riscv set_ebreakm on -riscv set_ebreaks on -riscv set_ebreaku on +create_esp_target $_ESP_ARCH diff --git a/tcl/target/esp32c6.cfg b/tcl/target/esp32c6.cfg new file mode 100644 index 0000000000..e1ef10a852 --- /dev/null +++ b/tcl/target/esp32c6.cfg @@ -0,0 +1,142 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# + +# Source the ESP common configuration file. +source [find target/esp_common.cfg] + +# Target specific global variables +set _CHIPNAME "riscv" +set _CPUTAPID 0x0000dc25 +set _ESP_ARCH "riscv" +set _ONLYCPU 1 +set _ESP_SMP_TARGET 0 +set _ESP_SMP_BREAK 0 +set _ESP_EFUSE_MAC_ADDR_REG 0x600B0844 + +# Target specific functions should be implemented for each riscv chips. +proc riscv_wdt_disable { } { + # Halt event can occur during config phase (before "init" is done). + # Ignore it since mww commands don't work at that time. + if { [string compare [command mode] config] == 0 } { + return + } + + # Timer Group 0 & 1 WDTs + mww 0x60008064 0x50D83AA1 + mww 0x60008048 0 + mww 0x60009064 0x50D83AA1 + mww 0x60009048 0 + # LP_WDT_RTC + mww 0x600b1c18 0x50D83AA1 + mww 0x600B1C00 0 + # LP_WDT_SWD + mww 0x600b1c20 0x50D83AA1 + mww 0x600b1c1c 0x40000000 +} + +proc riscv_soc_reset { } { + global _RISCV_DMCONTROL _RISCV_SB_CS _RISCV_SB_ADDR0 _RISCV_SB_DATA0 + + riscv dmi_write $_RISCV_DMCONTROL 0x80000001 + riscv dmi_write $_RISCV_SB_CS 0x48000 + riscv dmi_write $_RISCV_SB_ADDR0 0x600b1034 + riscv dmi_write $_RISCV_SB_DATA0 0x80000000 + # clear dmactive to clear sbbusy otherwise debug module gets stuck + riscv dmi_write $_RISCV_DMCONTROL 0 + + riscv dmi_write $_RISCV_SB_CS 0x48000 + riscv dmi_write $_RISCV_SB_ADDR0 0x600b1038 + riscv dmi_write $_RISCV_SB_DATA0 0x10000000 + + # clear dmactive to clear sbbusy otherwise debug module gets stuck + riscv dmi_write $_RISCV_DMCONTROL 0 + riscv dmi_write $_RISCV_DMCONTROL 0x40000001 + # Here debugger reads dmstatus as 0xc03a2 + + # Wait for the reset to happen + sleep 10 + poll + # Here debugger reads dmstatus as 0x3a2 + + # Disable the watchdogs again + riscv_wdt_disable + + # Here debugger reads anyhalted and allhalted bits as set (0x3a2) + # We will clean allhalted state by resuming the core. + riscv dmi_write $_RISCV_DMCONTROL 0x40000001 + + # Put the hart back into reset state. Note that we need to keep haltreq set. + riscv dmi_write $_RISCV_DMCONTROL 0x80000003 +} + +proc riscv_memprot_is_enabled { } { + global _RISCV_ABS_CMD _RISCV_ABS_DATA0 + + # If IRAM/DRAM split is enabled TOR address match mode is used. + # If IRAM/DRAM split is disabled NAPOT mode is used. + # In order to determine if the IRAM/DRAM regions are protected against RWX/RW, + # it is necessary to first read the mode and then apply the appropriate method for checking. + # We can understand the mode reading pmp5cfg in pmpcfg1 register. + # If it is none we know that pmp6cfg and pmp7cfg is in TOR mode. + + # Read pmpcfg1 and extract into 8-bit variables. + riscv dmi_write $_RISCV_ABS_CMD 0x2203a1 + set pmpcfg1 [riscv dmi_read $_RISCV_ABS_DATA0] + + set pmp5cfg [expr {($pmpcfg1 >> (8 * 1)) & 0xFF}] + set pmp6cfg [expr {($pmpcfg1 >> (8 * 2)) & 0xFF}] + set pmp7cfg [expr {($pmpcfg1 >> (8 * 3)) & 0xFF}] + + set IRAM_LOW 0x40800000 + set IRAM_HIGH 0x40880000 + set DRAM_LOW 0x40800000 + set DRAM_HIGH 0x40880000 + set PMP_RWX 0x07 + set PMP_RW 0x03 + set PMP_A [expr {($pmp5cfg >> 3) & 0x03}] + + if {$PMP_A == 0} { + # TOR mode used to protect valid address space. + + # Read PMPADDR 5-7 + riscv dmi_write $_RISCV_ABS_CMD 0x2203b5 + set pmpaddr5 [expr {[riscv dmi_read $_RISCV_ABS_DATA0] << 2}] + riscv dmi_write $_RISCV_ABS_CMD 0x2203b6 + set pmpaddr6 [expr {[riscv dmi_read $_RISCV_ABS_DATA0] << 2}] + riscv dmi_write $_RISCV_ABS_CMD 0x2203b7 + set pmpaddr7 [expr {[riscv dmi_read $_RISCV_ABS_DATA0] << 2}] + + # The lock bit remains unset during the execution of the 2nd stage bootloader. + # Thus we do not perform a lock bit check for IRAM and DRAM regions. + + # Check OpenOCD can write and execute from IRAM. + if {$pmpaddr5 >= $IRAM_LOW && $pmpaddr6 <= $IRAM_HIGH} { + if {($pmp5cfg & $PMP_RWX) != 0 || ($pmp6cfg & $PMP_RWX) != $PMP_RWX} { + return 1 + } + } + + # Check OpenOCD can read/write entire DRAM region. + if {$pmpaddr7 >= $DRAM_LOW && $pmpaddr7 <= $DRAM_HIGH} { + if {($pmp7cfg & $PMP_RW) != $PMP_RW} { + return 1 + } + } + } elseif {$PMP_A == 3} { + # NAPOT mode used to protect valid address space. + + # Read PMPADDR 5 + riscv dmi_write $_RISCV_ABS_CMD 0x2203b5 + set pmpaddr5 [expr {[riscv dmi_read $_RISCV_ABS_DATA0]}] + + # Expected value written to the pmpaddr5 + set pmpaddr_napot [expr {($IRAM_LOW | (($IRAM_HIGH - $IRAM_LOW - 1) >> 1)) >> 2}] + if {($pmpaddr_napot != $pmpaddr5) || ($pmp5cfg & $PMP_RWX) != $PMP_RWX} { + return 1 + } + } + + return 0 +} + +create_esp_target $_ESP_ARCH diff --git a/tcl/target/esp32h2.cfg b/tcl/target/esp32h2.cfg new file mode 100644 index 0000000000..45f598f731 --- /dev/null +++ b/tcl/target/esp32h2.cfg @@ -0,0 +1,122 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# + +# Source the ESP common configuration file. +source [find target/esp_common.cfg] + +# Target specific global variables +set _CHIPNAME "riscv" +set _CPUTAPID 0x00010c25 +set _ESP_ARCH "riscv" +set _ONLYCPU 1 +set _ESP_SMP_TARGET 0 +set _ESP_SMP_BREAK 0 +set _ESP_EFUSE_MAC_ADDR_REG 0x600B0844 + +# Target specific functions should be implemented for each riscv chips. +proc riscv_wdt_disable { } { + # Halt event can occur during config phase (before "init" is done). + # Ignore it since mww commands don't work at that time. + if { [string compare [command mode] config] == 0 } { + return + } + + # Timer Group 0 & 1 WDTs + mww 0x60009064 0x50D83AA1 + mww 0x60009048 0 + mww 0x6000A064 0x50D83AA1 + mww 0x6000A048 0 + # WDT_RTC + #mww 0x600b1c18 0x50D83AA1 + #mww 0x600B1C00 0 + # WDT_SWD + #mww 0x600b1c20 0x8F1D312A + #mww 0x600b1c1c 0x84B00000 +} + +proc riscv_soc_reset { } { + global _RISCV_DMCONTROL _RISCV_SB_CS _RISCV_SB_ADDR0 _RISCV_SB_DATA0 + + riscv dmi_write $_RISCV_DMCONTROL 0x80000001 + riscv dmi_write $_RISCV_SB_CS 0x48000 + riscv dmi_write $_RISCV_SB_ADDR0 0x600b1034 + riscv dmi_write $_RISCV_SB_DATA0 0x80000000 + # clear dmactive to clear sbbusy otherwise debug module gets stuck + riscv dmi_write $_RISCV_DMCONTROL 0 + + riscv dmi_write $_RISCV_SB_CS 0x48000 + riscv dmi_write $_RISCV_SB_ADDR0 0x600b1038 + riscv dmi_write $_RISCV_SB_DATA0 0x10000000 + + # clear dmactive to clear sbbusy otherwise debug module gets stuck + riscv dmi_write $_RISCV_DMCONTROL 0 + riscv dmi_write $_RISCV_DMCONTROL 0x40000001 + # Here debugger reads dmstatus as 0xc03a2 + + # Wait for the reset to happen + sleep 10 + poll + # Here debugger reads dmstatus as 0x3a2 + + # Disable the watchdogs again + riscv_wdt_disable + + # Here debugger reads anyhalted and allhalted bits as set (0x3a2) + # We will clean allhalted state by resuming the core. + riscv dmi_write $_RISCV_DMCONTROL 0x40000001 + + # Put the hart back into reset state. Note that we need to keep haltreq set. + riscv dmi_write $_RISCV_DMCONTROL 0x80000003 +} + +proc riscv_memprot_is_enabled { } { + global _RISCV_ABS_CMD _RISCV_ABS_DATA0 + # If IRAM/DRAM split is enabled, PMPADDR 5-6 will cover valid IRAM region and PMPADDR 7 will cover valid DRAM region + # Only TOR mode is used for IRAM and DRAM protections. + + # Read pmpcfg1 and extract into 8-bit variables. + riscv dmi_write $_RISCV_ABS_CMD 0x2203a1 + set pmpcfg1 [riscv dmi_read $_RISCV_ABS_DATA0] + + set pmp5cfg [expr {($pmpcfg1 >> (8 * 1)) & 0xFF}] + set pmp6cfg [expr {($pmpcfg1 >> (8 * 2)) & 0xFF}] + set pmp7cfg [expr {($pmpcfg1 >> (8 * 3)) & 0xFF}] + + # Read PMPADDR 5-7 + riscv dmi_write $_RISCV_ABS_CMD 0x2203b5 + set pmpaddr5 [expr {[riscv dmi_read $_RISCV_ABS_DATA0] << 2}] + riscv dmi_write $_RISCV_ABS_CMD 0x2203b6 + set pmpaddr6 [expr {[riscv dmi_read $_RISCV_ABS_DATA0] << 2}] + riscv dmi_write $_RISCV_ABS_CMD 0x2203b7 + set pmpaddr7 [expr {[riscv dmi_read $_RISCV_ABS_DATA0] << 2}] + + set IRAM_LOW 0x40800000 + set IRAM_HIGH 0x40850000 + set DRAM_LOW 0x40800000 + set DRAM_HIGH 0x40850000 + + set PMP_RWX 0x07 + set PMP_RW 0x03 + + # The lock bit remains unset during the execution of the 2nd stage bootloader. + # Thus, we do not perform a lock bit check for IRAM and DRAM regions. + + # Check OpenOCD can write and execute from IRAM. + if {$pmpaddr5 >= $IRAM_LOW && $pmpaddr6 <= $IRAM_HIGH} { + if {($pmp5cfg & $PMP_RWX) != 0 || ($pmp6cfg & $PMP_RWX) != $PMP_RWX} { + return 1 + } + } + + # Check OpenOCD can read/write entire DRAM region. + # If IRAM/DRAM split is disabled, pmpaddr7 will be zero, checking only IRAM region is enough. + if {$pmpaddr7 != 0 && $pmpaddr7 >= $DRAM_LOW && $pmpaddr7 <= $DRAM_HIGH} { + if {($pmp7cfg & $PMP_RW) != $PMP_RW} { + return 1 + } + } + + return 0 +} + +create_esp_target $_ESP_ARCH diff --git a/tcl/target/esp32s2.cfg b/tcl/target/esp32s2.cfg new file mode 100644 index 0000000000..4c1362a346 --- /dev/null +++ b/tcl/target/esp32s2.cfg @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# + +# Source the ESP common configuration file. +source [find target/esp_common.cfg] + +# Target specific global variables +set _CHIPNAME "esp32s2" +set _CPUTAPID 0x120034e5 +set _ESP_ARCH "xtensa" +set _ONLYCPU 1 +set _ESP_SMP_TARGET 0 +set _ESP_SMP_BREAK 1 +set _ESP_EFUSE_MAC_ADDR_REG 0x3f41A004 + +proc esp32s2_memprot_is_enabled { } { + # IRAM0, DPORT_PMS_PRO_IRAM0_0_REG + if { [get_mmr_bit 0x3f4c1010 0] != 0 } { + return 1 + } + # DRAM0, DPORT_PMS_PRO_DRAM0_0_REG + if { [get_mmr_bit 0x3f4c1028 0] != 0 } { + return 1 + } + # PERI1, DPORT_PMS_PRO_DPORT_0_REG + if { [get_mmr_bit 0x3f4c103c 0] != 0 } { + return 1 + } + # PERI2, DPORT_PMS_PRO_AHB_0_REG + if { [get_mmr_bit 0x3f4c105c 0] != 0 } { + return 1 + } + return 0 +} + +proc esp32s2_soc_reset { } { + soft_reset_halt +} + +create_esp_target $_ESP_ARCH + +source [find target/xtensa-core-esp32s2.cfg] diff --git a/tcl/target/esp32s3.cfg b/tcl/target/esp32s3.cfg new file mode 100644 index 0000000000..12c166c463 --- /dev/null +++ b/tcl/target/esp32s3.cfg @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# + +# Source the ESP common configuration file. +source [find target/esp_common.cfg] + +# Target specific global variables +set _CHIPNAME "esp32s3" +set _CPUTAPID 0x120034e5 +set _ESP_ARCH "xtensa" +set _ONLYCPU 3 +set _ESP_SMP_TARGET 1 +set _ESP_SMP_BREAK 1 +set _ESP_EFUSE_MAC_ADDR_REG 0x60007044 + +if { [info exists ESP32_S3_ONLYCPU] } { + set _ONLYCPU $ESP32_S3_ONLYCPU +} + +proc esp32s3_memprot_is_enabled { } { + # SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_0_REG + if { [get_mmr_bit 0x600C10C0 0] != 0 } { + return 1 + } + # SENSITIVE_CORE_0_PIF_PMS_CONSTRAIN_0_REG + if { [get_mmr_bit 0x600C1124 0] != 0 } { + return 1 + } + # SENSITIVE_CORE_1_PIF_PMS_CONSTRAIN_0_REG + if { [get_mmr_bit 0x600C11D0 0] != 0 } { + return 1 + } + # IRAM0, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_0_REG + if { [get_mmr_bit 0x600C10D8 0] != 0 } { + return 1 + } + # DRAM0, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_0_REG + if { [get_mmr_bit 0x600C10FC 0] != 0 } { + return 1 + } + # SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_0_REG + if { [get_mmr_bit 0x600C10E4 0] != 0 } { + return 1 + } + # SENSITIVE_CORE_1_IRAM0_PMS_MONITOR_0_REG + if { [get_mmr_bit 0x600C10F0 0] != 0 } { + return 1 + } + # SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_0_REG + if { [get_mmr_bit 0x600C1104 0] != 0 } { + return 1 + } + # SENSITIVE_CORE_1_DRAM0_PMS_MONITOR_0_REG + if { [get_mmr_bit 0x600C1114 0] != 0 } { + return 1 + } + # SENSITIVE_CORE_0_PIF_PMS_MONITOR_0_REG + if { [get_mmr_bit 0x600C119C 0] != 0 } { + return 1 + } + # SENSITIVE_CORE_1_PIF_PMS_MONITOR_0_REG + if { [get_mmr_bit 0x600C1248 0] != 0 } { + return 1 + } + return 0 +} + +proc esp32s3_soc_reset { } { + soft_reset_halt +} + +create_esp_target $_ESP_ARCH + +source [find target/xtensa-core-esp32s3.cfg] diff --git a/tcl/target/esp_common.cfg b/tcl/target/esp_common.cfg index c02bcb2b7b..af2f6ad2ca 100644 --- a/tcl/target/esp_common.cfg +++ b/tcl/target/esp_common.cfg @@ -1,16 +1,208 @@ # SPDX-License-Identifier: GPL-2.0-or-later # + +set CPU_MAX_ADDRESS 0xFFFFFFFF +source [find bitsbytes.tcl] +source [find memory.tcl] +source [find mmr_helpers.tcl] + +# Riscv Debug Module Registers which are used around esp configuration files. +set _RISCV_ABS_DATA0 0x04 +set _RISCV_DMCONTROL 0x10 +set _RISCV_ABS_CMD 0x17 +set _RISCV_SB_CS 0x38 +set _RISCV_SB_ADDR0 0x39 +set _RISCV_SB_DATA0 0x3C + # Common ESP chips definitions +# Espressif supports only NuttX in the upstream. +# FreeRTOS support is not upstreamed yet. +set _RTOS "hwthread" if { [info exists ESP_RTOS] } { set _RTOS "$ESP_RTOS" -} else { - set _RTOS "FreeRTOS" } +# by default current dir (when OOCD has been started) +set _SEMIHOST_BASEDIR "." if { [info exists ESP_SEMIHOST_BASEDIR] } { set _SEMIHOST_BASEDIR $ESP_SEMIHOST_BASEDIR -} else { - # by default current dir (when OOCD has been started) - set _SEMIHOST_BASEDIR "." +} + +proc set_esp_common_variables { } { + global _CHIPNAME _ONLYCPU _ESP_SMP_TARGET + global _CPUNAME_0 _CPUNAME_1 _TARGETNAME_0 _TARGETNAME_1 _TAPNAME_0 _TAPNAME_1 + global _ESP_WDT_DISABLE _ESP_SOC_RESET _ESP_MEMPROT_IS_ENABLED + + # For now we support dual core at most. + if { $_ONLYCPU == 1 && $_ESP_SMP_TARGET == 0} { + set _TARGETNAME_0 $_CHIPNAME + set _CPUNAME_0 cpu + set _TAPNAME_0 $_CHIPNAME.$_CPUNAME_0 + } else { + set _CPUNAME_0 cpu0 + set _CPUNAME_1 cpu1 + set _TARGETNAME_0 $_CHIPNAME.$_CPUNAME_0 + set _TARGETNAME_1 $_CHIPNAME.$_CPUNAME_1 + set _TAPNAME_0 $_TARGETNAME_0 + set _TAPNAME_1 $_TARGETNAME_1 + } + + set _ESP_WDT_DISABLE "${_CHIPNAME}_wdt_disable" + set _ESP_SOC_RESET "${_CHIPNAME}_soc_reset" + set _ESP_MEMPROT_IS_ENABLED "${_CHIPNAME}_memprot_is_enabled" +} + +proc create_esp_jtag { } { + global _CHIPNAME _CPUNAME_0 _CPUNAME_1 _CPUTAPID _ONLYCPU + jtag newtap $_CHIPNAME $_CPUNAME_0 -irlen 5 -expected-id $_CPUTAPID + if { $_ONLYCPU != 1 } { + jtag newtap $_CHIPNAME $_CPUNAME_1 -irlen 5 -expected-id $_CPUTAPID + } elseif [info exists _CPUNAME_1] { + jtag newtap $_CHIPNAME $_CPUNAME_1 -irlen 5 -disable -expected-id $_CPUTAPID + } +} + +proc create_openocd_targets { } { + global _TARGETNAME_0 _TARGETNAME_1 _TAPNAME_0 _TAPNAME_1 _RTOS _CHIPNAME _ONLYCPU + + target create $_TARGETNAME_0 $_CHIPNAME -chain-position $_TAPNAME_0 -coreid 0 -rtos $_RTOS + if { $_ONLYCPU != 1 } { + target create $_TARGETNAME_1 $_CHIPNAME -chain-position $_TAPNAME_1 -coreid 1 -rtos $_RTOS + target smp $_TARGETNAME_0 $_TARGETNAME_1 + } +} + +proc create_esp_target { ARCH } { + set_esp_common_variables + create_esp_jtag + create_openocd_targets + configure_openocd_events $ARCH + + if { $ARCH == "xtensa"} { + configure_esp_xtensa_default_settings + } else { + configure_esp_riscv_default_settings + } +} + +#################### Set event handlers and default settings #################### + +proc configure_event_examine_end { } { + global _TARGETNAME_0 _TARGETNAME_1 _ONLYCPU + + $_TARGETNAME_0 configure -event examine-end { + # Need to enable to set 'semihosting_basedir' + arm semihosting enable + arm semihosting_resexit enable + if { [info exists _SEMIHOST_BASEDIR] } { + if { $_SEMIHOST_BASEDIR != "" } { + arm semihosting_basedir $_SEMIHOST_BASEDIR + } + } + } + + if { $_ONLYCPU != 1 } { + $_TARGETNAME_1 configure -event examine-end { + # Need to enable to set 'semihosting_basedir' + arm semihosting enable + arm semihosting_resexit enable + if { [info exists _SEMIHOST_BASEDIR] } { + if { $_SEMIHOST_BASEDIR != "" } { + arm semihosting_basedir $_SEMIHOST_BASEDIR + } + } + } + } +} + +proc configure_event_reset_assert_post { } { + global _TARGETNAME_0 _TARGETNAME_1 _ONLYCPU + + $_TARGETNAME_0 configure -event reset-assert-post { + global _ESP_SOC_RESET + $_ESP_SOC_RESET + } + + if { $_ONLYCPU != 1 } { + $_TARGETNAME_1 configure -event reset-assert-post { + global _ESP_SOC_RESET + $_ESP_SOC_RESET + } + } +} + +proc configure_event_halted { } { + global _TARGETNAME_0 + + $_TARGETNAME_0 configure -event halted { + global _ESP_WDT_DISABLE + $_ESP_WDT_DISABLE + } +} + +proc configure_event_gdb_attach { } { + global _TARGETNAME_0 _TARGETNAME_1 _ONLYCPU + + $_TARGETNAME_0 configure -event gdb-attach { + if { $_ESP_SMP_BREAK != 0 } { + $_TARGETNAME_0 xtensa smpbreak BreakIn BreakOut + } + # necessary to auto-probe flash bank when GDB is connected and generate proper memory map + halt 1000 + if { [$_ESP_MEMPROT_IS_ENABLED] } { + # 'reset halt' to disable memory protection and allow flasher to work correctly + echo "Memory protection is enabled. Reset target to disable it..." + reset halt + } + } + + if { $_ONLYCPU != 1 } { + $_TARGETNAME_1 configure -event gdb-attach { + if { $_ESP_SMP_BREAK != 0 } { + $_TARGETNAME_1 xtensa smpbreak BreakIn BreakOut + } + # necessary to auto-probe flash bank when GDB is connected + halt 1000 + if { [$_ESP_MEMPROT_IS_ENABLED] } { + # 'reset halt' to disable memory protection and allow flasher to work correctly + echo "Memory protection is enabled. Reset target to disable it..." + reset halt + } + } + } +} + +proc configure_openocd_events { ARCH } { + if { $ARCH == "riscv" } { + configure_event_halted + } + configure_event_examine_end + configure_event_reset_assert_post + configure_event_gdb_attach +} + +proc configure_esp_riscv_default_settings { } { + gdb_breakpoint_override hard + riscv set_reset_timeout_sec 2 + riscv set_command_timeout_sec 5 + riscv set_mem_access sysbus progbuf abstract + riscv set_ebreakm on + riscv set_ebreaks on + riscv set_ebreaku on +} + +proc configure_esp_xtensa_default_settings { } { + global _TARGETNAME_0 _ESP_SMP_BREAK _FLASH_VOLTAGE _CHIPNAME + + $_TARGETNAME_0 xtensa maskisr on + if { $_ESP_SMP_BREAK != 0 } { + $_TARGETNAME_0 xtensa smpbreak BreakIn BreakOut + } + + gdb_breakpoint_override hard + + if { [info exists _FLASH_VOLTAGE] } { + $_TARGETNAME_0 $_CHIPNAME flashbootstrap $_FLASH_VOLTAGE + } } diff --git a/tcl/target/exynos5250.cfg b/tcl/target/exynos5250.cfg index d3aaa986d5..a5650225a3 100644 --- a/tcl/target/exynos5250.cfg +++ b/tcl/target/exynos5250.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Samsung Exynos 5250 - dual-core ARM Cortex-A15 # diff --git a/tcl/target/faux.cfg b/tcl/target/faux.cfg index d3891cded9..71cb8b70b9 100644 --- a/tcl/target/faux.cfg +++ b/tcl/target/faux.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #Script for faux target - used for testing if { [info exists CHIPNAME] } { diff --git a/tcl/target/feroceon.cfg b/tcl/target/feroceon.cfg index d4f710e008..593569d1dd 100644 --- a/tcl/target/feroceon.cfg +++ b/tcl/target/feroceon.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: Marvell Feroceon CPU core ###################################### diff --git a/tcl/target/fm3.cfg b/tcl/target/fm3.cfg index 544cff9d6a..0caf629da4 100644 --- a/tcl/target/fm3.cfg +++ b/tcl/target/fm3.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # MB9BF506 # Fujitsu Cortex-M3 with 512kB Flash and 64kB RAM diff --git a/tcl/target/fm4.cfg b/tcl/target/fm4.cfg index bfe7115ca7..4318f2e569 100644 --- a/tcl/target/fm4.cfg +++ b/tcl/target/fm4.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Spansion FM4 (ARM Cortex-M4) # diff --git a/tcl/target/fm4_mb9bf.cfg b/tcl/target/fm4_mb9bf.cfg index ca4e5f92ee..4bc579cfa7 100644 --- a/tcl/target/fm4_mb9bf.cfg +++ b/tcl/target/fm4_mb9bf.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Spansion FM4 MB9BFxxx (ARM Cortex-M4) # diff --git a/tcl/target/fm4_s6e2cc.cfg b/tcl/target/fm4_s6e2cc.cfg index c6f835daec..7417d386f4 100644 --- a/tcl/target/fm4_s6e2cc.cfg +++ b/tcl/target/fm4_s6e2cc.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Spansion FM4 S6E2CC (ARM Cortex-M4) # diff --git a/tcl/target/gd32vf103.cfg b/tcl/target/gd32vf103.cfg index b00e5e9b7a..77fdff7a23 100644 --- a/tcl/target/gd32vf103.cfg +++ b/tcl/target/gd32vf103.cfg @@ -1,8 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# GigaDevice GD32VF103 target +# +# https://www.gigadevice.com/products/microcontrollers/gd32/risc-v/ +# + adapter speed 1000 +source [find mem_helper.tcl] + transport select jtag reset_config srst_nogate +# The smallest RAM size 6kB (GD32VF103C4/T4/R4) +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x1800 +} + set _CHIPNAME gd32vf103 # The vendor's configuration expects an ID of 0x1e200a6d, but this one is what # I have on my board (Sipeed Longan Nano, GD32VF103CBT6). @@ -19,7 +36,7 @@ proc default_mem_access {} { default_mem_access -$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 0x1000 -work-area-backup 1 +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32f1x 0x08000000 0 0 0 $_TARGETNAME @@ -97,3 +114,74 @@ proc init_reset { mode } { jtag arp_init-reset } } + +# On this chip, ndmreset (the debug module bit that triggers a software reset) +# doesn't work. So for JTAG connections without an SRST, we need to trigger a +# reset manually. This is an undocumented reset sequence that's used by the +# JTAG flashing script in the vendor-supplied GD32VF103 PlatformIO plugin: +# +# https://github.com/sipeed/platform-gd32v/commit/f9cbb44819bc05dd2010cc815c32be0486800cc2 +# +$_TARGETNAME configure -event reset-assert { + set dmcontrol 0x10 + set dmcontrol_dmactive [expr {1 << 0}] + set dmcontrol_ackhavereset [expr {1 << 28}] + set dmcontrol_haltreq [expr {1 << 31}] + + global _RESETMODE + + # If hardware NRST signal is connected and configured (reset_config srst_only) + # the device has been recently reset in 'jtag arp_init-reset', therefore + # DM_DMSTATUS_ANYHAVERESET reads 1. + # The following 'halt' command checks this status bit + # and shows 'Hart 0 unexpectedly reset!' if set. + # Prevent this message by sending an acknowledge first. + set val [expr {$dmcontrol_dmactive | $dmcontrol_ackhavereset}] + riscv dmi_write $dmcontrol $val + + # Halt the core so that we can write to memory. We do this first so + # that it doesn't clobber our dmcontrol configuration. + halt + + # Set haltreq appropriately for the type of reset we're doing. This + # replicates what the generic RISC-V reset_assert() function would + # do if we weren't overriding it. The $_RESETMODE hack sucks, but + # it's the least invasive way to determine whether we need to halt. + # + # If we didn't override the generic handler, we'd actually still have + # to do this: the default handler sets ndmreset, which prevents memory + # access even though it doesn't actually trigger a reset on this chip. + # So we'd need to unset it here, which involves a write to dmcontrol, + # Since haltreq is write-only and there's no way to leave it unchanged, + # we'd have to figure out its proper value anyway. + set val $dmcontrol_dmactive + if {$_RESETMODE ne "run"} { + set val [expr {$val | $dmcontrol_haltreq}] + } + riscv dmi_write $dmcontrol $val + + # Unlock 0xe0042008 so that the next write triggers a reset + mww 0xe004200c 0x4b5a6978 + + # We need to trigger the reset using abstract memory access, since + # progbuf access tries to read a status code out of a core register + # after the write happens, which fails when the core is in reset. + riscv set_mem_access abstract + + # Go! + mww 0xe0042008 0x1 + + # Put the memory access mode back to what it was. + default_mem_access +} + +# Capture the mode of a given reset so that we can use it later in the +# reset-assert handler. +proc init_reset { mode } { + global _RESETMODE + set _RESETMODE $mode + + if {[using_jtag]} { + jtag arp_init-reset + } +} diff --git a/tcl/target/geehy/apm32f0x.cfg b/tcl/target/geehy/apm32f0x.cfg new file mode 100644 index 0000000000..502c092751 --- /dev/null +++ b/tcl/target/geehy/apm32f0x.cfg @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Geehy APM32F0x target +# +# https://global.geehy.com/MCU +# + +# +# APM32F0x devices support SWD transport only. +# +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME apm32f0x +} + +# Work-area is a space in RAM used for flash programming, by default use 1 KiB. +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x400 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x0bc11477 +} + +swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32f1x 0x08000000 0 0 0 $_TARGETNAME + +adapter speed 1000 + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to perform a soft reset. + cortex_m reset_config sysresetreq +} diff --git a/tcl/target/geehy/apm32f1x.cfg b/tcl/target/geehy/apm32f1x.cfg new file mode 100644 index 0000000000..dc42e060a6 --- /dev/null +++ b/tcl/target/geehy/apm32f1x.cfg @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Geehy APM32F1x target +# +# https://global.geehy.com/MCU +# + +# +# APM32F1x devices support JTAG and SWD transport. +# +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME apm32f1x +} + +# Work-area is a space in RAM used for flash programming, by default use 4 KiB. +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x1000 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x4ba00477 + } { + set _CPUTAPID 0x2ba01477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +if {[using_jtag]} { + jtag newtap $_CHIPNAME bs -irlen 5 +} + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32f1x 0 0 0 0 $_TARGETNAME + +adapter speed 1000 + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to perform a soft reset. + cortex_m reset_config sysresetreq +} diff --git a/tcl/target/geehy/apm32f4x.cfg b/tcl/target/geehy/apm32f4x.cfg new file mode 100644 index 0000000000..3ed58d15b5 --- /dev/null +++ b/tcl/target/geehy/apm32f4x.cfg @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Geehy APM32F4x target +# +# https://global.geehy.com/MCU +# + +# +# APM32F4x devices support JTAG and SWD transport. +# +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME apm32f4x +} + +# Work-area is a space in RAM used for flash programming, by default use 4 KiB. +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x1000 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x4ba00477 + } else { + set _CPUTAPID 0x2ba01477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +if { [using_jtag] } { + jtag newtap $_CHIPNAME bs -irlen 5 +} + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME + +adapter speed 1000 + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to perform a soft reset. + cortex_m reset_config sysresetreq +} diff --git a/tcl/target/gp326xxxa.cfg b/tcl/target/gp326xxxa.cfg index df42c44854..447460bf82 100644 --- a/tcl/target/gp326xxxa.cfg +++ b/tcl/target/gp326xxxa.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Support for General Plus GP326XXXA chips # diff --git a/tcl/target/hi3798.cfg b/tcl/target/hi3798.cfg index 7b1921895e..722305dcf4 100644 --- a/tcl/target/hi3798.cfg +++ b/tcl/target/hi3798.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Hisilicon Hi3798 Target if { [info exists CHIPNAME] } { @@ -40,8 +42,7 @@ for { set _core 0 } { $_core < $_cores } { incr _core 1 } { #set _command "$_command -defer-examine" set _smp_command "$_smp_command ${_TARGETNAME}$_core" } else { - # uncomment when "hawt" rtos is merged - # set _command "$_command -rtos hawt" + set _command "$_command -rtos hwthread" set _smp_command "target smp ${_TARGETNAME}$_core" } diff --git a/tcl/target/hi6220.cfg b/tcl/target/hi6220.cfg index ddeeaad7cd..5b03899256 100644 --- a/tcl/target/hi6220.cfg +++ b/tcl/target/hi6220.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Hisilicon Hi6220 Target if { [info exists CHIPNAME] } { @@ -47,8 +49,7 @@ for { set _core 0 } { $_core < $_cores } { incr _core 1 } { set _command "$_command -defer-examine" set _smp_command "$_smp_command ${_TARGETNAME}$_core" } else { - # uncomment when "hawt" rtos is merged - # set _command "$_command -rtos hawt" + set _command "$_command -rtos hwthread" set _smp_command "target smp ${_TARGETNAME}$_core" } diff --git a/tcl/target/hilscher_netx10.cfg b/tcl/target/hilscher_netx10.cfg index 668de8fee9..054cac8bab 100644 --- a/tcl/target/hilscher_netx10.cfg +++ b/tcl/target/hilscher_netx10.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ diff --git a/tcl/target/hilscher_netx50.cfg b/tcl/target/hilscher_netx50.cfg index c6510c6138..e8ba01563b 100644 --- a/tcl/target/hilscher_netx50.cfg +++ b/tcl/target/hilscher_netx50.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ################################################################################ # Author: Michael Trensch (MTrensch@googlemail.com) ################################################################################ diff --git a/tcl/target/hilscher_netx500.cfg b/tcl/target/hilscher_netx500.cfg index 131bef2217..d838a6be99 100644 --- a/tcl/target/hilscher_netx500.cfg +++ b/tcl/target/hilscher_netx500.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #Hilscher netX 500 CPU if { [info exists CHIPNAME] } { diff --git a/tcl/target/icepick.cfg b/tcl/target/icepick.cfg index cc824ad0e9..5509532111 100644 --- a/tcl/target/icepick.cfg +++ b/tcl/target/icepick.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Copyright (C) 2011 by Karl Kurbjun # Copyright (C) 2009 by David Brownell diff --git a/tcl/target/imx.cfg b/tcl/target/imx.cfg index e2bee7a7a7..d76f60e1c6 100644 --- a/tcl/target/imx.cfg +++ b/tcl/target/imx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # utility fn's for Freescale i.MX series global TARGETNAME diff --git a/tcl/target/imx21.cfg b/tcl/target/imx21.cfg index 2d9ce39c61..7c9cca35d4 100644 --- a/tcl/target/imx21.cfg +++ b/tcl/target/imx21.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #use combined on interfaces or targets that can't set TRST/SRST separately # # Hmmm.... should srst_pulls_trst be used here like i.MX27??? diff --git a/tcl/target/imx25.cfg b/tcl/target/imx25.cfg index bc91278c4e..ed94cc0674 100644 --- a/tcl/target/imx25.cfg +++ b/tcl/target/imx25.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # imx25 config # diff --git a/tcl/target/imx27.cfg b/tcl/target/imx27.cfg index e5a5035d4f..c79d85e778 100644 --- a/tcl/target/imx27.cfg +++ b/tcl/target/imx27.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # page 3-34 of "MCIMC27 Multimedia Applications Processor Reference Manual, Rev 0.3" # SRST pulls TRST # diff --git a/tcl/target/imx28.cfg b/tcl/target/imx28.cfg index 1fea3fa372..d52fc4eafb 100644 --- a/tcl/target/imx28.cfg +++ b/tcl/target/imx28.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # i.MX28 config file. # based off of the imx21.cfg file. diff --git a/tcl/target/imx31.cfg b/tcl/target/imx31.cfg index d850657dae..10e9fefc01 100644 --- a/tcl/target/imx31.cfg +++ b/tcl/target/imx31.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # imx31 config # diff --git a/tcl/target/imx35.cfg b/tcl/target/imx35.cfg index 21495c23cc..fa173bb892 100644 --- a/tcl/target/imx35.cfg +++ b/tcl/target/imx35.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # imx35 config # diff --git a/tcl/target/imx51.cfg b/tcl/target/imx51.cfg index 22af2843ee..fc3dfa91d6 100644 --- a/tcl/target/imx51.cfg +++ b/tcl/target/imx51.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Freescale i.MX51 if { [info exists CHIPNAME] } { diff --git a/tcl/target/imx53.cfg b/tcl/target/imx53.cfg index 84a85babbd..855a6aeaab 100644 --- a/tcl/target/imx53.cfg +++ b/tcl/target/imx53.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Freescale i.MX53 if { [info exists CHIPNAME] } { diff --git a/tcl/target/imx6.cfg b/tcl/target/imx6.cfg index 29453346a4..c9b6acf79d 100644 --- a/tcl/target/imx6.cfg +++ b/tcl/target/imx6.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Freescale i.MX6 series # diff --git a/tcl/target/imx6sx.cfg b/tcl/target/imx6sx.cfg index d3fae8a9b0..3d4240ab04 100644 --- a/tcl/target/imx6sx.cfg +++ b/tcl/target/imx6sx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Freescale i.MX6SoloX # diff --git a/tcl/target/imx6ul.cfg b/tcl/target/imx6ul.cfg index f42aa636e4..354745e791 100644 --- a/tcl/target/imx6ul.cfg +++ b/tcl/target/imx6ul.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Freescale i.MX6UltraLite series: 6UL 6ULL 6ULZ # diff --git a/tcl/target/imx7.cfg b/tcl/target/imx7.cfg index ea23deb0f1..bd9e3ddc02 100644 --- a/tcl/target/imx7.cfg +++ b/tcl/target/imx7.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { diff --git a/tcl/target/imx7ulp.cfg b/tcl/target/imx7ulp.cfg index 879fcf8cc2..1467f7cc10 100644 --- a/tcl/target/imx7ulp.cfg +++ b/tcl/target/imx7ulp.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # NXP i.MX7ULP: Cortex-A7 + Cortex-M4 # diff --git a/tcl/target/imx8m.cfg b/tcl/target/imx8m.cfg index 9a8bfecb1c..69380903c3 100644 --- a/tcl/target/imx8m.cfg +++ b/tcl/target/imx8m.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # configuration file for NXP i.MX8M family of SoCs # @@ -38,13 +40,14 @@ for { set _core 0 } { $_core < $_cores } { incr _core } { -baseaddr [lindex $CTIBASE $_core] set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ - -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core" + -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core -coreid $_core" if { $_core != 0 } { # non-boot core examination may fail set _command "$_command -defer-examine" set _smp_command "$_smp_command $_TARGETNAME.$_core" } else { + set _command "$_command -rtos hwthread" set _smp_command "target smp $_TARGETNAME.$_core" } diff --git a/tcl/target/imx8qm.cfg b/tcl/target/imx8qm.cfg index 08cb8137d1..33f9ca16d8 100644 --- a/tcl/target/imx8qm.cfg +++ b/tcl/target/imx8qm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # NXP i.MX8QuadMax # diff --git a/tcl/target/infineon/tle987x.cfg b/tcl/target/infineon/tle987x.cfg index 84cc2380bd..ac3db6c296 100644 --- a/tcl/target/infineon/tle987x.cfg +++ b/tcl/target/infineon/tle987x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Infineon TLE987x family (Arm Cortex-M3 @ up to 40 MHz) # diff --git a/tcl/target/is5114.cfg b/tcl/target/is5114.cfg index 1a06b091f1..d0b1d92f79 100644 --- a/tcl/target/is5114.cfg +++ b/tcl/target/is5114.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for Insilica IS-5114 # AKA: Atmel AT76C114 - an ARM946 chip # ATMEL sold his product line to Insilica... diff --git a/tcl/target/ixp42x.cfg b/tcl/target/ixp42x.cfg index ee10b2157c..5c8e903215 100644 --- a/tcl/target/ixp42x.cfg +++ b/tcl/target/ixp42x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #xscale ixp42x CPU if { [info exists CHIPNAME] } { diff --git a/tcl/target/k1921vk01t.cfg b/tcl/target/k1921vk01t.cfg index 926f3c726e..a9500ef063 100644 --- a/tcl/target/k1921vk01t.cfg +++ b/tcl/target/k1921vk01t.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # K1921VK01T # http://niiet.ru/chips/nis?id=354 diff --git a/tcl/target/k40.cfg b/tcl/target/k40.cfg index 981161156b..33e8235460 100644 --- a/tcl/target/k40.cfg +++ b/tcl/target/k40.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Freescale Kinetis K40 devices # diff --git a/tcl/target/k60.cfg b/tcl/target/k60.cfg index b9c5e3a1e6..3b89102bab 100644 --- a/tcl/target/k60.cfg +++ b/tcl/target/k60.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Freescale Kinetis K60 devices # diff --git a/tcl/target/ke0x.cfg b/tcl/target/ke0x.cfg index b92721f4c5..b357767191 100644 --- a/tcl/target/ke0x.cfg +++ b/tcl/target/ke0x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Freescale Kinetis KE0x and KEAx series devices # diff --git a/tcl/target/ke1xf.cfg b/tcl/target/ke1xf.cfg index b1200cec2b..86a1f3b2ba 100644 --- a/tcl/target/ke1xf.cfg +++ b/tcl/target/ke1xf.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # NXP (Freescale) Kinetis KE1xF devices # diff --git a/tcl/target/ke1xz.cfg b/tcl/target/ke1xz.cfg index 6a3f509ed2..9e915423d5 100644 --- a/tcl/target/ke1xz.cfg +++ b/tcl/target/ke1xz.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # NXP (Freescale) Kinetis KE1xZ devices # diff --git a/tcl/target/kl25.cfg b/tcl/target/kl25.cfg index 0e716e3ae2..916edf6853 100644 --- a/tcl/target/kl25.cfg +++ b/tcl/target/kl25.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Freescale Kinetis KL25 devices # diff --git a/tcl/target/kl46.cfg b/tcl/target/kl46.cfg index 70ea273ee3..bf6b244d87 100644 --- a/tcl/target/kl46.cfg +++ b/tcl/target/kl46.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Freescale Kinetis KL46 devices # diff --git a/tcl/target/klx.cfg b/tcl/target/klx.cfg index 84f6535e35..cd236b3395 100644 --- a/tcl/target/klx.cfg +++ b/tcl/target/klx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # NXP (former Freescale) Kinetis KL series devices # Also used for Cortex-M0+ equipped members of KVx and KE1xZ series diff --git a/tcl/target/ks869x.cfg b/tcl/target/ks869x.cfg index 78cc402b49..06e710b6e8 100644 --- a/tcl/target/ks869x.cfg +++ b/tcl/target/ks869x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # ARM920T CPU if { [info exists CHIPNAME] } { diff --git a/tcl/target/kx.cfg b/tcl/target/kx.cfg index 9fda4edf4a..c87116b728 100644 --- a/tcl/target/kx.cfg +++ b/tcl/target/kx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # NXP (former Freescale) Kinetis Kx series devices # Also used for Cortex-M4 equipped members of KVx and KE1xF series diff --git a/tcl/target/lpc11xx.cfg b/tcl/target/lpc11xx.cfg index 7a65c1f479..d288e2a32b 100644 --- a/tcl/target/lpc11xx.cfg +++ b/tcl/target/lpc11xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC11xx Cortex-M0 with at least 1kB SRAM set CHIPNAME lpc11xx set CHIPSERIES lpc1100 diff --git a/tcl/target/lpc12xx.cfg b/tcl/target/lpc12xx.cfg index a37c6febca..ace5e0676c 100644 --- a/tcl/target/lpc12xx.cfg +++ b/tcl/target/lpc12xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC12xx Cortex-M0 with at least 4kB SRAM set CHIPNAME lpc12xx set CHIPSERIES lpc1200 diff --git a/tcl/target/lpc13xx.cfg b/tcl/target/lpc13xx.cfg index 3d128c9637..5ac29d3bf1 100644 --- a/tcl/target/lpc13xx.cfg +++ b/tcl/target/lpc13xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC13xx Cortex-M3 with at least 4kB SRAM set CHIPNAME lpc13xx set CHIPSERIES lpc1300 diff --git a/tcl/target/lpc17xx.cfg b/tcl/target/lpc17xx.cfg index dccf880da8..35d8badea4 100644 --- a/tcl/target/lpc17xx.cfg +++ b/tcl/target/lpc17xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC17xx Cortex-M3 with at least 8kB SRAM set CHIPNAME lpc17xx set CHIPSERIES lpc1700 diff --git a/tcl/target/lpc1850.cfg b/tcl/target/lpc1850.cfg index 481dc8aaf0..6dd1ab7538 100644 --- a/tcl/target/lpc1850.cfg +++ b/tcl/target/lpc1850.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/swj-dp.tcl] adapter speed 500 diff --git a/tcl/target/lpc1xxx.cfg b/tcl/target/lpc1xxx.cfg index 946d1ce166..70d26d2673 100644 --- a/tcl/target/lpc1xxx.cfg +++ b/tcl/target/lpc1xxx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Main file for NXP LPC1xxx/LPC40xx series Cortex-M0/0+/3/4F parts # # !!!!!! diff --git a/tcl/target/lpc2103.cfg b/tcl/target/lpc2103.cfg index 131b9ef89e..c49b0e5d55 100644 --- a/tcl/target/lpc2103.cfg +++ b/tcl/target/lpc2103.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC2103 ARM7TDMI-S with 32kB flash and 8kB SRAM, clocked with 12MHz crystal source [find target/lpc2xxx.cfg] diff --git a/tcl/target/lpc2124.cfg b/tcl/target/lpc2124.cfg index ddbde22a5a..053ebeb701 100644 --- a/tcl/target/lpc2124.cfg +++ b/tcl/target/lpc2124.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC2124 ARM7TDMI-S with 256kB flash and 16kB SRAM, clocked with 12MHz crystal source [find target/lpc2xxx.cfg] diff --git a/tcl/target/lpc2129.cfg b/tcl/target/lpc2129.cfg index a1c3fe7bbc..88ee20f171 100644 --- a/tcl/target/lpc2129.cfg +++ b/tcl/target/lpc2129.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC2129 ARM7TDMI-S with 256kB flash and 16kB SRAM, clocked with 12MHz crystal source [find target/lpc2xxx.cfg] diff --git a/tcl/target/lpc2148.cfg b/tcl/target/lpc2148.cfg index 503a682649..fda622f11d 100644 --- a/tcl/target/lpc2148.cfg +++ b/tcl/target/lpc2148.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC2148 ARM7TDMI-S with 512kB flash (12kB used by bootloader) and 40kB SRAM (8kB for USB DMA), clocked with 12MHz crystal source [find target/lpc2xxx.cfg] diff --git a/tcl/target/lpc2294.cfg b/tcl/target/lpc2294.cfg index 1320cda3ee..7537a6541c 100644 --- a/tcl/target/lpc2294.cfg +++ b/tcl/target/lpc2294.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC2294 ARM7TDMI-S with 256kB flash and 16kB SRAM, clocked with 12MHz crystal source [find target/lpc2xxx.cfg] diff --git a/tcl/target/lpc2378.cfg b/tcl/target/lpc2378.cfg index 235456a074..59e41c9a10 100644 --- a/tcl/target/lpc2378.cfg +++ b/tcl/target/lpc2378.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC2378 ARM7TDMI-S with 512kB flash (8kB used by bootloader) and 56kB SRAM (16kB for ETH, 8kB for DMA), clocked with 4MHz internal oscillator source [find target/lpc2xxx.cfg] diff --git a/tcl/target/lpc2460.cfg b/tcl/target/lpc2460.cfg index c229f6dd6e..59b646631c 100644 --- a/tcl/target/lpc2460.cfg +++ b/tcl/target/lpc2460.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC2460 ARM7TDMI-S with 98kB SRAM (16kB for ETH, 16kB for DMA, 2kB for RTC), clocked with 4MHz internal oscillator source [find target/lpc2xxx.cfg] diff --git a/tcl/target/lpc2478.cfg b/tcl/target/lpc2478.cfg index 36b5c46936..e4fd49d43b 100644 --- a/tcl/target/lpc2478.cfg +++ b/tcl/target/lpc2478.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC2478 ARM7TDMI-S with 512kB flash (8kB used by bootloader) and 98kB SRAM (16kB for ETH, 16kB for DMA, 2kB for RTC), clocked with 4MHz internal oscillator source [find target/lpc2xxx.cfg] diff --git a/tcl/target/lpc2900.cfg b/tcl/target/lpc2900.cfg index 523bc211f6..67e3c92249 100644 --- a/tcl/target/lpc2900.cfg +++ b/tcl/target/lpc2900.cfg @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/lpc2xxx.cfg b/tcl/target/lpc2xxx.cfg index f947c1b053..bc5e6009f8 100644 --- a/tcl/target/lpc2xxx.cfg +++ b/tcl/target/lpc2xxx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Common setup for the LPC2xxx parts # parameters: diff --git a/tcl/target/lpc3131.cfg b/tcl/target/lpc3131.cfg index 89bbf0265f..09d698ac6c 100644 --- a/tcl/target/lpc3131.cfg +++ b/tcl/target/lpc3131.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: NXP lpc3131 ###################################### diff --git a/tcl/target/lpc3250.cfg b/tcl/target/lpc3250.cfg index 14bb0f61ba..244d9814c5 100644 --- a/tcl/target/lpc3250.cfg +++ b/tcl/target/lpc3250.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # lpc3250 config # diff --git a/tcl/target/lpc40xx.cfg b/tcl/target/lpc40xx.cfg index 606cda5c17..f0be5a1e40 100644 --- a/tcl/target/lpc40xx.cfg +++ b/tcl/target/lpc40xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC40xx Cortex-M4F with at least 16kB SRAM set CHIPNAME lpc40xx set CHIPSERIES lpc4000 diff --git a/tcl/target/lpc4350.cfg b/tcl/target/lpc4350.cfg index 0c6d0ffdf0..453306aeeb 100644 --- a/tcl/target/lpc4350.cfg +++ b/tcl/target/lpc4350.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/swj-dp.tcl] adapter speed 500 diff --git a/tcl/target/lpc4357.cfg b/tcl/target/lpc4357.cfg index 1a15ad6233..f7835057fe 100644 --- a/tcl/target/lpc4357.cfg +++ b/tcl/target/lpc4357.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # NXP LPC4357 # diff --git a/tcl/target/lpc4370.cfg b/tcl/target/lpc4370.cfg index 9db2b9e925..fe9e76b7a1 100644 --- a/tcl/target/lpc4370.cfg +++ b/tcl/target/lpc4370.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # NXP LPC4370 - 1x ARM Cortex-M4 + 2x ARM Cortex-M0 @ up to 204 MHz each # diff --git a/tcl/target/lpc84x.cfg b/tcl/target/lpc84x.cfg index cb36698bc6..af26f2757f 100644 --- a/tcl/target/lpc84x.cfg +++ b/tcl/target/lpc84x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC84x Cortex-M0+ with at least 8kB SRAM if { ![info exists CHIPNAME] } { set CHIPNAME lpc84x diff --git a/tcl/target/lpc8nxx.cfg b/tcl/target/lpc8nxx.cfg index 4db78cbfcb..859e99b6a3 100644 --- a/tcl/target/lpc8nxx.cfg +++ b/tcl/target/lpc8nxx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC8Nxx NHS31xx Cortex-M0+ with 8kB SRAM # Copyright (C) 2018 by Jean-Christian de Rivaz # Based on NXP proposal https://community.nxp.com/message/1011149 diff --git a/tcl/target/lpc8xx.cfg b/tcl/target/lpc8xx.cfg index e0e210b967..4c54a2a667 100644 --- a/tcl/target/lpc8xx.cfg +++ b/tcl/target/lpc8xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP LPC8xx Cortex-M0+ with at least 1kB SRAM if { ![info exists CHIPNAME] } { set CHIPNAME lpc8xx diff --git a/tcl/target/ls1012a.cfg b/tcl/target/ls1012a.cfg index e1bd168445..7333ea8093 100644 --- a/tcl/target/ls1012a.cfg +++ b/tcl/target/ls1012a.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # NXP LS1012A # diff --git a/tcl/target/ls1028a.cfg b/tcl/target/ls1028a.cfg new file mode 100644 index 0000000000..463ec7ddac --- /dev/null +++ b/tcl/target/ls1028a.cfg @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP LS1028A + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME ls1028a +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x6ba00477 +} + +set _CPUS 2 + +source [find target/lsch3_common.cfg] diff --git a/tcl/target/ls1088a.cfg b/tcl/target/ls1088a.cfg index f9ae9a134a..193d6ddc77 100644 --- a/tcl/target/ls1088a.cfg +++ b/tcl/target/ls1088a.cfg @@ -13,62 +13,9 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x5ba00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID -dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap +set _CPUS 8 -target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 1 - -set _CPU_BASE 0x81000000 -set _CPU_STRIDE 0x100000 -set _CPU_DBGOFF 0x10000 -set _CPU_CTIOFF 0x20000 - -set _TARGETS {} -for {set i 0} {$i < 8} {incr i} { - set _BASE [expr {$_CPU_BASE + $_CPU_STRIDE * $i}] - cti create $_CHIPNAME.cti$i -dap $_CHIPNAME.dap -ap-num 0 \ - -baseaddr [expr {$_BASE + $_CPU_CTIOFF}] - target create $_CHIPNAME.cpu$i aarch64 -dap $_CHIPNAME.dap \ - -cti $_CHIPNAME.cti$i -dbgbase [expr {$_BASE + $_CPU_DBGOFF}] \ - {*}[expr {$i ? "-coreid $i" : "-rtos hwthread" }] - lappend _TARGETS $_CHIPNAME.cpu$i -} - -target smp {*}$_TARGETS - -# Service processor -target create $_CHIPNAME.sp cortex_a -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80138000 - -# Normally you will not need to call this, but if you are using the hard-coded -# Reset Configuration Word (RCW) you will need to call this manually. The CPU's -# reset vector is 0, and the boot ROM at that location contains ARMv7-A 32-bit -# instructions. This will cause the CPU to almost immediately execute an -# illegal instruction. -# -# This code is idempotent; releasing a released CPU has no effect, although it -# will halt/resume the service processor. -add_help_text release_cpu "Release a cpu which is held off" -proc release_cpu {cpu} { - set RST_BRRL 0x1e60060 - - set old [target current] - targets $::_CHIPNAME.sp - set not_halted [string compare halted [$::_CHIPNAME.sp curstate]] - if {$not_halted} { - halt - } - - # Release the cpu; it will start executing something bogus - mem2array regs 32 $RST_BRRL 1 - mww $RST_BRRL [expr {$regs(0) | 1 << $cpu}] - - if {$not_halted} { - resume - } - targets $old -} - -targets $_CHIPNAME.cpu0 +source [find target/lsch3_common.cfg] # Seems to work OK in testing adapter speed 10000 diff --git a/tcl/target/lsch3_common.cfg b/tcl/target/lsch3_common.cfg new file mode 100644 index 0000000000..f48d59b9d8 --- /dev/null +++ b/tcl/target/lsch3_common.cfg @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# This contains common configuration for NXP Layerscape chassis generation 3 + +if { ![info exists _CPUS] } { + error "_CPUS must be set to the number of cores" +} + +jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap + +target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 1 + +set _CPU_BASE 0x81000000 +set _CPU_STRIDE 0x100000 +set _CPU_DBGOFF 0x10000 +set _CPU_CTIOFF 0x20000 + +set _TARGETS {} +for {set i 0} {$i < $_CPUS} {incr i} { + set _BASE [expr {$_CPU_BASE + $_CPU_STRIDE * $i}] + cti create $_CHIPNAME.cti$i -dap $_CHIPNAME.dap -ap-num 0 \ + -baseaddr [expr {$_BASE + $_CPU_CTIOFF}] + target create $_CHIPNAME.cpu$i aarch64 -dap $_CHIPNAME.dap \ + -cti $_CHIPNAME.cti$i -dbgbase [expr {$_BASE + $_CPU_DBGOFF}] \ + {*}[expr {$i ? "-coreid $i" : "-rtos hwthread" }] + lappend _TARGETS $_CHIPNAME.cpu$i +} + +target smp {*}$_TARGETS + +# Service processor +target create $_CHIPNAME.sp cortex_a -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80138000 + +# Normally you will not need to call this, but if you are using the hard-coded +# Reset Configuration Word (RCW) you will need to call this manually. The CPU's +# reset vector is 0, and the boot ROM at that location contains ARMv7-A 32-bit +# instructions. This will cause the CPU to almost immediately execute an +# illegal instruction. +# +# This code is idempotent; releasing a released CPU has no effect, although it +# will halt/resume the service processor. +add_help_text release_cpu "Release a cpu which is held off" +proc release_cpu {cpu} { + set RST_BRRL 0x1e60060 + + set old [target current] + targets $::_CHIPNAME.sp + set not_halted [string compare halted [$::_CHIPNAME.sp curstate]] + if {$not_halted} { + halt + } + + # Release the cpu; it will start executing something bogus + mem2array regs 32 $RST_BRRL 1 + mww $RST_BRRL [expr {$regs(0) | 1 << $cpu}] + + if {$not_halted} { + resume + } + targets $old +} + +targets $_CHIPNAME.cpu0 diff --git a/tcl/target/marvell/88f3710.cfg b/tcl/target/marvell/88f3710.cfg index 6e35f293d9..dcc4516366 100644 --- a/tcl/target/marvell/88f3710.cfg +++ b/tcl/target/marvell/88f3710.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Marvell Armada 3710 set CORES 1 diff --git a/tcl/target/marvell/88f3720.cfg b/tcl/target/marvell/88f3720.cfg index 799d614ba4..7c29378a1d 100644 --- a/tcl/target/marvell/88f3720.cfg +++ b/tcl/target/marvell/88f3720.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Marvell Armada 3720 set CORES 2 diff --git a/tcl/target/marvell/88f37x0.cfg b/tcl/target/marvell/88f37x0.cfg index 5c3dd737e3..738d22110c 100644 --- a/tcl/target/marvell/88f37x0.cfg +++ b/tcl/target/marvell/88f37x0.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Main file for Marvell Armada 3700 series targets # # !!!!!! @@ -55,8 +57,7 @@ for { set _core 0 } { $_core < $_cores } { incr _core 1 } { set _command "$_command -defer-examine" set _smp_command "$_smp_command ${_TARGETNAME}$_core" } else { - # uncomment when "hawt" rtos is merged - # set _command "$_command -rtos hawt" + set _command "$_command -rtos hwthread" set _smp_command "target smp ${_TARGETNAME}$_core" } diff --git a/tcl/target/marvell/cn9130.cfg b/tcl/target/marvell/cn9130.cfg new file mode 100644 index 0000000000..23e472f284 --- /dev/null +++ b/tcl/target/marvell/cn9130.cfg @@ -0,0 +1,178 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# cn9130 -- support for the Marvell Octeon TX2 / CN9130 CPU family +# +# henrik.nordstorm@addiva.se, Nov 2023 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME cn9130 +} + +if { [info exists MASTERTAPID] } { + set _MASTERTAPID $MASTERTAPID +} else { + set _MASTERTAPID 0x07025357 +} + +if { [info exists APTAPID] } { + set _APTAPID $APTAPID +} else { + set _APTAPID 0x4ba00477 +} + +if { [info exists SBTAPID] } { + set _SBTAPID $SBTAPID +} else { + set _SBTAPID 0x4ba00477 +} + +if { [info exists CORES] } { + set _CORES $CORES +} else { + set _CORES 4 +} + +# CTI base address should be possible to read from the CoreSight +# ROM table like how the DBG base address is when not specified. +if { [info exists CTIBASE] } { + set _CTIBASE $CTIBASE +} else { + set _CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} +} + +# CN9130 is a multi-die chip and has a multi level hierarchical +# JTAG TAP, where all the DAPs are disabled at reset, requiring +# both configuration to enable access to the chip DAPs, and a +# vendor specific bypass IR instruction to access the slave TAPs +# via the master TAP. In addition there is a number of sample +# bits that should be ignored. +# +# The default BYPASS instruction in the master TAP bypasses the +# whole chip and not only the master TAP. And similarly on +# IDCODE the master TAP only responds with it's own ID and +# bypasses the other TAPs on the chip, while OpenOCD expects +# ID from all enabled TAPs in the chain. + +# Bootstrap with the default boundary scan oriented TAP configuration +# where the master,ap,sb TAPs are seen as one big fat TAP, which matches +# what OpenOCD expects from IDCODE and BYPASS. + +jtag newtap $_CHIPNAME bs -irlen 19 -enable -expected-id $_MASTERTAPID + +# Declare the full JTAG chain, but in disabled state during setup + +jtag newtap $_CHIPNAME sample4 -irlen 1 -disable +jtag newtap $_CHIPNAME sample3 -irlen 1 -disable +jtag newtap $_CHIPNAME sample2 -irlen 1 -disable +jtag newtap $_CHIPNAME ap.cpu -irlen 4 -disable -expected-id $_APTAPID +jtag newtap $_CHIPNAME ap -irlen 5 -disable +jtag newtap $_CHIPNAME sample1 -irlen 1 -disable +jtag newtap $_CHIPNAME sb.cpu -irlen 4 -disable -expected-id $_SBTAPID +jtag newtap $_CHIPNAME sb -irlen 5 -disable +jtag newtap $_CHIPNAME master -irlen 5 -disable -ir-bypass 0x11 -expected-id $_MASTERTAPID + +# Once the iniial IDCODE scan has completed switch to more detailed +# scan chain giving access to the individual chip TAPs. + +jtag configure $_CHIPNAME.bs -event setup "cn9130_enable_full_chain $_CHIPNAME" + +proc cn9130_enable_full_chain { _CHIPNAME } { + # Switch to detailed TAP declaration + jtag tapdisable $_CHIPNAME.bs + jtag tapenable $_CHIPNAME.master + jtag tapenable $_CHIPNAME.sb + jtag tapenable $_CHIPNAME.sample1 + jtag tapenable $_CHIPNAME.ap + jtag tapenable $_CHIPNAME.sample2 + jtag tapenable $_CHIPNAME.sample3 + jtag tapenable $_CHIPNAME.sample4 +} + +# AP & SB TAPs have a config register to enable/disable access to +# the auxilary DAP TAP. Default off which hides the DAP TAP from +# the scan chain. +proc cn9130_dap_config { chip tap state } { + irscan $chip.$tap 0x12 + drscan $chip.$tap 32 $state +} + +jtag configure $_CHIPNAME.bs -event tap-disable "" +jtag configure $_CHIPNAME.bs -event tap-enable "" +jtag configure $_CHIPNAME.sample4 -event tap-enable "" +jtag configure $_CHIPNAME.sample3 -event tap-enable "" +jtag configure $_CHIPNAME.sample2 -event tap-enable "" +jtag configure $_CHIPNAME.ap.cpu -event tap-disable "cn9130_dap_config $_CHIPNAME ap 0" +jtag configure cn9130.ap.cpu -event tap-enable "cn9130_dap_config $_CHIPNAME ap 1" +jtag configure $_CHIPNAME.ap -event tap-enable "" +jtag configure $_CHIPNAME.sample1 -event tap-enable "" +jtag configure $_CHIPNAME.sb.cpu -event tap-disable "cn9130_dap_config $_CHIPNAME sb 0" +jtag configure cn9130.sb.cpu -event tap-enable "cn9130_dap_config $_CHIPNAME sb 1" +jtag configure $_CHIPNAME.sb -event tap-enable "" +jtag configure $_CHIPNAME.master -event tap-enable "" + +dap create $_CHIPNAME.ap.dap -chain-position $_CHIPNAME.ap.cpu + +# Main bus +target create $_CHIPNAME.ap.axi mem_ap \ + -dap $_CHIPNAME.ap.dap \ + -ap-num 0 + +# Periperials bus +target create $_CHIPNAME.ap.apb mem_ap \ + -dap $_CHIPNAME.ap.dap \ + -ap-num 1 + +# MSS bus +target create $_CHIPNAME.ap.ahb mem_ap \ + -dap $_CHIPNAME.ap.dap \ + -ap-num 2 + +# AP A72 CPU cores +set _smp_command "" +for { set _core 0 } { $_core < $_CORES } { incr _core 1 } { + cti create $_CHIPNAME.ap.cti.$_core \ + -dap $_CHIPNAME.ap.dap \ + -baseaddr [ lindex $_CTIBASE $_core ] \ + -ap-num 1 + + if { $_core == 0 } { + target create $_CHIPNAME.ap.a72.$_core aarch64 \ + -dap $_CHIPNAME.ap.dap \ + -ap-num 1 \ + -cti $_CHIPNAME.ap.cti.$_core \ + -coreid $_core \ + -rtos hwthread + set _smp_command "target smp $_CHIPNAME.ap.a72.$_core" + } else { + # Defer non-boot cores. Held hard in reset until + # SMP is activated. + target create $_CHIPNAME.ap.a72.$_core aarch64 \ + -dap $_CHIPNAME.ap.dap \ + -ap-num 1 \ + -cti $_CHIPNAME.ap.cti.$_core \ + -coreid $_core \ + -defer-examine + set _smp_command "$_smp_command $_CHIPNAME.ap.a72.$_core" + } + +} + +# Set up the A72 cluster as SMP +# Note: Only the boot core is active by default. The other core DAPs can +# be enabled by arp_examine after they have been released from hard reset. +eval $_smp_command + +# AP MSS M3 CPU core. Defer as it is held in reset until firmware is loaded. +target create $_CHIPNAME.ap.mss cortex_m -dap $_CHIPNAME.ap.dap -ap-num 2 -defer-examine + +# Why is this needed? reset fails with "Debug regions are unpowered" otherwise +$_CHIPNAME.ap.axi configure -event examine-start "dap init" + +# Automate enabling the AP A72 DAP once the full scan chain is enabled +proc cn9130_ap_setup { _CHIPNAME } { + jtag tapenable $_CHIPNAME.ap.cpu + targets $_CHIPNAME.ap.a72.0 +} +jtag configure $_CHIPNAME.ap -event setup "cn9130_ap_setup $_CHIPNAME" diff --git a/tcl/target/max32620.cfg b/tcl/target/max32620.cfg index 6187bb9968..f3a9f84c88 100644 --- a/tcl/target/max32620.cfg +++ b/tcl/target/max32620.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Maxim Integrated MAX32620 OpenOCD target configuration file # www.maximintegrated.com @@ -14,8 +16,10 @@ if {[using_jtag]} { swd newdap max32620 cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version } +dap create max32620.dap -chain-position max32620.cpu + # target configuration -target create max32620.cpu cortex_m -chain-position max32620.cpu +target create max32620.cpu cortex_m -dap max32620.dap max32620.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 # Config Command: flash bank name driver base size chip_width bus_width target [driver_options] diff --git a/tcl/target/max32625.cfg b/tcl/target/max32625.cfg index 159b360947..90eb392668 100644 --- a/tcl/target/max32625.cfg +++ b/tcl/target/max32625.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Maxim Integrated MAX32625 OpenOCD target configuration file # www.maximintegrated.com @@ -14,8 +16,10 @@ if {[using_jtag]} { swd newdap max32625 cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version } +dap create max32625.dap -chain-position max32625.cpu + # target configuration -target create max32625.cpu cortex_m -chain-position max32625.cpu +target create max32625.cpu cortex_m -dap max32625.dap max32625.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 # Config Command: flash bank name driver base size chip_width bus_width target [driver_options] diff --git a/tcl/target/max3263x.cfg b/tcl/target/max3263x.cfg index fc7d11f5ca..852e04af1e 100644 --- a/tcl/target/max3263x.cfg +++ b/tcl/target/max3263x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Maxim Integrated MAX3263X OpenOCD target configuration file # www.maximintegrated.com @@ -14,8 +16,10 @@ if {[using_jtag]} { swd newdap max3263x cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version } +dap create max3263x.dap -chain-position max3263x.cpu + # target configuration -target create max3263x.cpu cortex_m -chain-position max3263x.cpu +target create max3263x.cpu cortex_m -dap max3263x.dap max3263x.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 # Config Command: flash bank name driver base size chip_width bus_width target [driver_options] diff --git a/tcl/target/mc13224v.cfg b/tcl/target/mc13224v.cfg index f756dd9634..29e4d9da94 100644 --- a/tcl/target/mc13224v.cfg +++ b/tcl/target/mc13224v.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find bitsbytes.tcl] source [find cpu/arm/arm7tdmi.tcl] source [find memory.tcl] diff --git a/tcl/target/mdr32f9q2i.cfg b/tcl/target/mdr32f9q2i.cfg index 820d2dd45d..6e958c61da 100644 --- a/tcl/target/mdr32f9q2i.cfg +++ b/tcl/target/mdr32f9q2i.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # MDR32F9Q2I (1986ВЕ92У) # http://milandr.ru/index.php?mact=Products,cntnt01,details,0&cntnt01productid=57&cntnt01returnid=68 diff --git a/tcl/target/nds32v2.cfg b/tcl/target/nds32v2.cfg deleted file mode 100644 index bbf6b3aee2..0000000000 --- a/tcl/target/nds32v2.cfg +++ /dev/null @@ -1,10 +0,0 @@ -# -# Andes Core -# -# http://www.andestech.com -# - -jtag newtap $_CHIPNAME cpu -expected-id $_CPUTAPID - -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME nds32_v2 -endian little -chain-position $_TARGETNAME diff --git a/tcl/target/nds32v3.cfg b/tcl/target/nds32v3.cfg deleted file mode 100644 index 0c267cd752..0000000000 --- a/tcl/target/nds32v3.cfg +++ /dev/null @@ -1,10 +0,0 @@ -# -# Andes Core -# -# http://www.andestech.com -# - -jtag newtap $_CHIPNAME cpu -expected-id $_CPUTAPID - -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME nds32_v3 -endian little -chain-position $_TARGETNAME diff --git a/tcl/target/nds32v3m.cfg b/tcl/target/nds32v3m.cfg deleted file mode 100644 index 169e3d1195..0000000000 --- a/tcl/target/nds32v3m.cfg +++ /dev/null @@ -1,10 +0,0 @@ -# -# Andes Core -# -# http://www.andestech.com -# - -jtag newtap $_CHIPNAME cpu -expected-id $_CPUTAPID - -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME nds32_v3m -endian little -chain-position $_TARGETNAME diff --git a/tcl/target/netl_xlp304.cfg b/tcl/target/netl_xlp304.cfg new file mode 100644 index 0000000000..27c30a0d27 --- /dev/null +++ b/tcl/target/netl_xlp304.cfg @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Target: XLP304 processor by NetLogic Microsystems +# + +set XLP_NT 4 +source [find target/netl_xlp3xx.cfg] diff --git a/tcl/target/netl_xlp308.cfg b/tcl/target/netl_xlp308.cfg new file mode 100644 index 0000000000..c3ba11e781 --- /dev/null +++ b/tcl/target/netl_xlp308.cfg @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Target: XLP308 processor by NetLogic Microsystems +# + +set XLP_NT 8 +source [find target/netl_xlp3xx.cfg] diff --git a/tcl/target/netl_xlp316.cfg b/tcl/target/netl_xlp316.cfg new file mode 100644 index 0000000000..961b67f180 --- /dev/null +++ b/tcl/target/netl_xlp316.cfg @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Target: XLP316 processor by NetLogic Microsystems +# + +set XLP_NT 16 +source [find target/netl_xlp3xx.cfg] diff --git a/tcl/target/netl_xlp3xx.cfg b/tcl/target/netl_xlp3xx.cfg new file mode 100644 index 0000000000..2366503cb6 --- /dev/null +++ b/tcl/target/netl_xlp3xx.cfg @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Target: XLP 300-series processors by NetLogic Microsystems +# +# See http://www.broadcom.com/products/Processors/Enterprise/XLP300-Series +# +# Use xlp304.cfg, xlp308.cfg, xlp316.cfg for particular processor model. +# + +transport select jtag + +global XLP_NT + +for {set i $XLP_NT} {$i > 0} {incr i -1} { + jtag newtap xlp cpu_$i -irlen 5 -disable + if {$i != 1} { + jtag configure xlp.cpu_$i -event tap-enable {} + } +} +jtag newtap xlp jrc -irlen 16 -expected-id 0x00011449 + +jtag configure xlp.cpu_1 -event tap-enable { + global XLP_NT + irscan xlp.jrc 0xe0 + drscan xlp.jrc 1 1 + for {set i $XLP_NT} {$i > 1} {incr i -1} { + jtag tapenable xlp.cpu_$i + } +} + +proc chipreset {} { + irscan xlp.jrc 0xab + drscan xlp.jrc 1 1 + drscan xlp.jrc 1 0 +} + +jtag configure xlp.jrc -event setup "jtag tapenable xlp.cpu_1" + +target create xlp.cpu_1 mips_mips64 -endian big -chain-position xlp.cpu_1 diff --git a/tcl/target/ngultra.cfg b/tcl/target/ngultra.cfg new file mode 100644 index 0000000000..956fdbb5ca --- /dev/null +++ b/tcl/target/ngultra.cfg @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (C) 2022 by NanoXplore, France - all rights reserved +# +# configuration file for NG-Ultra SoC from NanoXplore. +# NG-Ultra is a quad-core Cortex-R52 SoC + an FPGA. +# +transport select jtag +adapter speed 10000 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME NGULTRA +} + +if { [info exists CHIPCORES] } { + set _cores $CHIPCORES +} else { + set _cores 4 +} + +set DBGBASE {0x88210000 0x88310000 0x88410000 0x88510000} +set CTIBASE {0x88220000 0x88320000 0x88420000 0x88520000} + +# Coresight access to the SoC +jtag newtap $_CHIPNAME.coresight cpu -irlen 4 -expected-id 0x6BA00477 + +# Misc TAP devices +jtag newtap $_CHIPNAME.soc cpu -irlen 7 -expected-id 0xFAAA0555 +jtag newtap $_CHIPNAME.pmb unknown1 -irlen 5 -expected-id 0xBA20A005 +jtag newtap $_CHIPNAME.fpga fpga -irlen 4 -ignore-version -ignore-bypass + +# Create the Coresight DAP +dap create $_CHIPNAME.coresight.dap -chain-position $_CHIPNAME.coresight.cpu + +for { set _core 0 } { $_core < $_cores } { incr _core } { + cti create cti.$_core -dap $_CHIPNAME.coresight.dap -ap-num 0 \ + -baseaddr [lindex $CTIBASE $_core] +# Cores are armv8-r but works with aarch64 (since armv8-r not directly supported by openocd yet). + if { $_core == 0} { + target create core.$_core aarch64 -dap $_CHIPNAME.coresight.dap \ + -ap-num 0 -dbgbase [lindex $DBGBASE $_core] -cti cti.$_core + } else { + target create core.$_core aarch64 -dap $_CHIPNAME.coresight.dap \ + -ap-num 0 -dbgbase [lindex $DBGBASE $_core] -cti cti.$_core -defer-examine + } +} + +# Create direct APB and AXI interfaces +target create APB mem_ap -dap $_CHIPNAME.coresight.dap -ap-num 0 +target create AXI mem_ap -dap $_CHIPNAME.coresight.dap -ap-num 1 diff --git a/tcl/target/nhs31xx.cfg b/tcl/target/nhs31xx.cfg index 964be7b764..7e4bc4c0ee 100644 --- a/tcl/target/nhs31xx.cfg +++ b/tcl/target/nhs31xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # NXP NHS31xx Cortex-M0+ with 8kB SRAM set CHIPNAME nhs31xx diff --git a/tcl/target/npcx.cfg b/tcl/target/npcx.cfg index 1a21e1f7f5..84bb0b7a53 100644 --- a/tcl/target/npcx.cfg +++ b/tcl/target/npcx.cfg @@ -9,7 +9,7 @@ source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { - set _CHIPNAME NPCX_M4 + set _CHIPNAME npcx } # SWD DAP ID of Nuvoton NPCX Cortex-M4. @@ -27,6 +27,12 @@ if { [info exists WORKAREASIZE] } { set _WORKAREASIZE 0x8000 } +if { [info exists FIUNAME]} { + set _FIUNAME $FIUNAME +} else { + set _FIUNAME npcx.fiu +} + # Debug Adapter Target Settings swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUDAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu @@ -48,4 +54,4 @@ cortex_m reset_config sysresetreq # flash configuration set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME npcx 0x64000000 0 0 0 $_TARGETNAME +flash bank $_FLASHNAME npcx 0x64000000 0 0 0 $_TARGETNAME $_FIUNAME diff --git a/tcl/target/nrf51.cfg b/tcl/target/nrf51.cfg index d51a50e231..48c2715d10 100644 --- a/tcl/target/nrf51.cfg +++ b/tcl/target/nrf51.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # script for Nordic nRF51 series, a Cortex-M0 chip # diff --git a/tcl/target/nrf52.cfg b/tcl/target/nrf52.cfg index d0c52fdabc..0c82c5758a 100644 --- a/tcl/target/nrf52.cfg +++ b/tcl/target/nrf52.cfg @@ -1,8 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Nordic nRF52 series: ARM Cortex-M4 @ 64 MHz # source [find target/swj-dp.tcl] +source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -114,3 +117,51 @@ proc nrf52_recover {} { } add_help_text nrf52_recover "Mass erase and unlock nRF52 device" + +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + +lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu +proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname _chipname} { + targets $_targetname + + # Read FICR.INFO.PART + set PART [mrw 0x10000100] + + switch $PART { + 0x52840 - + 0x52833 - + 0x52832 { + if { [$_chipname.tpiu cget -protocol] eq "sync" } { + if { [$_chipname.tpiu cget -port-width] != 4 } { + echo "Error. Device only supports 4-bit sync traces." + return + } + + # Set TRACECONFIG.TRACEMUX to enable synchronous trace + mmw 0x4000055C 0x00020000 0x00010000 + $_targetname configure -event reset-end { + mmw 0x4000055C 0x00020000 0x00010000 + } + } else { + # Set TRACECONFIG.TRACEMUX to enable SWO + mmw 0x4000055C 0x00010000 0x00020000 + $_targetname configure -event reset-end { + mmw 0x4000055C 0x00010000 0x00020000 + } + } + } + 0x52820 - + 0x52811 - + 0x52810 - + 0x52805 { + echo "Error: Device does not support TPIU" + return + } + default { + echo "Error: Unknown device" + return + } + } +} + +$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME $_CHIPNAME" diff --git a/tcl/target/nuc910.cfg b/tcl/target/nuc910.cfg index 29cd29f35c..31a3ac629c 100644 --- a/tcl/target/nuc910.cfg +++ b/tcl/target/nuc910.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Nuvoton nuc910 (previously W90P910) based soc # diff --git a/tcl/target/numicro.cfg b/tcl/target/numicro.cfg index 73022df476..29077f39f8 100644 --- a/tcl/target/numicro.cfg +++ b/tcl/target/numicro.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for Nuvoton MuMicro Cortex-M0 Series # Adapt based on what transport is active. diff --git a/tcl/target/numicro_m4.cfg b/tcl/target/numicro_m4.cfg new file mode 100644 index 0000000000..1302515d34 --- /dev/null +++ b/tcl/target/numicro_m4.cfg @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# script for Nuvoton MuMicro Cortex-M4 Series + +source [find target/swj-dp.tcl] + +# Set Chipname +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME NuMicro +} + +# SWD DP-ID Nuvoton NuMicro Cortex-M4 has SWD Transport only. +if { [info exists CPUDAPID] } { + set _CPUDAPID $CPUDAPID +} else { + set _CPUDAPID 0x2BA01477 +} + +# Work-area is a space in RAM used for flash programming +# By default use 16kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x4000 +} + + +# Debug Adapter Target Settings +swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUDAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +# flash bank <name> numicro <base> <size(autodetect,set to 0)> 0 0 <target#> +#set _FLASHNAME $_CHIPNAME.flash +#flash bank $_FLASHNAME numicro 0 $_FLASHSIZE 0 0 $_TARGETNAME +# flash size will be probed +set _FLASHNAME $_CHIPNAME.flash_aprom +flash bank $_FLASHNAME numicro 0x00000000 0 0 0 $_TARGETNAME +set _FLASHNAME $_CHIPNAME.flash_data +flash bank $_FLASHNAME numicro 0x0001F000 0 0 0 $_TARGETNAME +set _FLASHNAME $_CHIPNAME.flash_ldrom +flash bank $_FLASHNAME numicro 0x00100000 0 0 0 $_TARGETNAME +set _FLASHNAME $_CHIPNAME.flash_config +flash bank $_FLASHNAME numicro 0x00300000 0 0 0 $_TARGETNAME + +# set default SWCLK frequency +adapter speed 1000 + +# set default srst setting "none" +reset_config none + +# HLA doesn't have cortex_m commands +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} diff --git a/tcl/target/omap2420.cfg b/tcl/target/omap2420.cfg index 7968ad1e82..3e31bafc13 100644 --- a/tcl/target/omap2420.cfg +++ b/tcl/target/omap2420.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Texas Instruments OMAP 2420 # http://www.ti.com/omap # as seen in Nokia N8x0 tablets diff --git a/tcl/target/omap3530.cfg b/tcl/target/omap3530.cfg index dcf7c51395..bd8b111a0b 100644 --- a/tcl/target/omap3530.cfg +++ b/tcl/target/omap3530.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # TI OMAP3530 # http://focus.ti.com/docs/prod/folders/print/omap3530.html # Other OMAP3 chips remove DSP and/or the OpenGL support diff --git a/tcl/target/omap4430.cfg b/tcl/target/omap4430.cfg index 5b9e23c2ae..a448550f67 100644 --- a/tcl/target/omap4430.cfg +++ b/tcl/target/omap4430.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # OMAP4430 if { [info exists CHIPNAME] } { diff --git a/tcl/target/omap4460.cfg b/tcl/target/omap4460.cfg index fb76e136b8..bbc824b2af 100644 --- a/tcl/target/omap4460.cfg +++ b/tcl/target/omap4460.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # OMAP4460 if { [info exists CHIPNAME] } { diff --git a/tcl/target/omap5912.cfg b/tcl/target/omap5912.cfg index 2f9338bc37..783f460f9a 100644 --- a/tcl/target/omap5912.cfg +++ b/tcl/target/omap5912.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # TI OMAP5912 dual core processor # http://focus.ti.com/docs/prod/folders/print/omap5912.html diff --git a/tcl/target/omapl138.cfg b/tcl/target/omapl138.cfg index 30cf23c9ec..2d670b98a3 100644 --- a/tcl/target/omapl138.cfg +++ b/tcl/target/omapl138.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Texas Instruments DaVinci family: OMAPL138 # diff --git a/tcl/target/or1k.cfg b/tcl/target/or1k.cfg index f85c2ee63a..ddd4fa210e 100644 --- a/tcl/target/or1k.cfg +++ b/tcl/target/or1k.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + set _ENDIAN big if { [info exists CHIPNAME] } { diff --git a/tcl/target/pic32mx.cfg b/tcl/target/pic32mx.cfg index f15924fc25..df68e807ae 100644 --- a/tcl/target/pic32mx.cfg +++ b/tcl/target/pic32mx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { diff --git a/tcl/target/psoc4.cfg b/tcl/target/psoc4.cfg index 40f2fcab3a..baa2c83f41 100644 --- a/tcl/target/psoc4.cfg +++ b/tcl/target/psoc4.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for Cypress PSoC 4 devices # diff --git a/tcl/target/psoc5lp.cfg b/tcl/target/psoc5lp.cfg index c90fd422d2..fe44174900 100644 --- a/tcl/target/psoc5lp.cfg +++ b/tcl/target/psoc5lp.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Cypress PSoC 5LP # diff --git a/tcl/target/psoc6.cfg b/tcl/target/psoc6.cfg index bf63fd5d43..d69515cdf7 100644 --- a/tcl/target/psoc6.cfg +++ b/tcl/target/psoc6.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Configuration script for Cypress PSoC6 family of microcontrollers (CY8C6xxx) # PSoC6 is a dual-core device with CM0+ and CM4 cores. Both cores share diff --git a/tcl/target/pxa255.cfg b/tcl/target/pxa255.cfg index 73518bf7e4..14ee13c372 100644 --- a/tcl/target/pxa255.cfg +++ b/tcl/target/pxa255.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # PXA255 chip ... originally from Intel, PXA line was sold to Marvell. # This chip is now at end-of-life. Final orders have been taken. diff --git a/tcl/target/pxa270.cfg b/tcl/target/pxa270.cfg index bd904b5dd6..3121e96061 100644 --- a/tcl/target/pxa270.cfg +++ b/tcl/target/pxa270.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #Marvell/Intel PXA270 Script if { [info exists CHIPNAME] } { diff --git a/tcl/target/pxa3xx.cfg b/tcl/target/pxa3xx.cfg index 1a4539ca9b..d670c84c85 100644 --- a/tcl/target/pxa3xx.cfg +++ b/tcl/target/pxa3xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Marvell PXA3xx if { [info exists CHIPNAME] } { diff --git a/tcl/target/qn908x.cfg b/tcl/target/qn908x.cfg new file mode 100644 index 0000000000..ac3e06b69c --- /dev/null +++ b/tcl/target/qn908x.cfg @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# NXP QN908x Cortex-M4F with 128 KiB SRAM + +source [find target/swj-dp.tcl] + +set CHIPNAME qn908x +set CHIPSERIES qn9080 +if { ![info exists WORKAREASIZE] } { + set WORKAREASIZE 0x20000 +} + +# SWD IDCODE (Cortex M4). +set CPUTAPID 0x2ba01477 + +swj_newdap $CHIPNAME cpu -irlen 4 -expected-id $CPUTAPID +dap create $CHIPNAME.dap -chain-position $CHIPNAME.cpu + +set TARGETNAME $CHIPNAME.cpu +target create $TARGETNAME cortex_m -dap $CHIPNAME.dap + +# SRAM is mapped at 0x04000000. +$TARGETNAME configure -work-area-phys 0x04000000 -work-area-size $WORKAREASIZE + +# flash bank <name> qn908x <base> <size> 0 0 <target#> [calc_checksum] +# The base must be set as 0x01000000, and the size parameter is unused. +set FLASHNAME $CHIPNAME.flash +flash bank $FLASHNAME qn908x 0x01000000 0 0 0 $TARGETNAME calc_checksum + +# We write directly to flash memory over this adapter interface. For debugging +# this could in theory be faster (the Core clock on reset is normally at 32MHz), +# but for flashing 1MHz is more reliable. +adapter speed 1000 + +# Delay on reset line. +adapter srst delay 200 + +cortex_m reset_config sysresetreq diff --git a/tcl/target/qualcomm_qca4531.cfg b/tcl/target/qualcomm_qca4531.cfg index 0b046b8427..be0c8fab37 100644 --- a/tcl/target/qualcomm_qca4531.cfg +++ b/tcl/target/qualcomm_qca4531.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # The QCA4531 is a two stream (2x2) 802.11b/g/n single-band programmable # Wi-Fi System-on-Chip (SoC) for the Internet of Things (IoT). # diff --git a/tcl/target/quark_d20xx.cfg b/tcl/target/quark_d20xx.cfg index 7d718c26dc..ca8f4406a5 100644 --- a/tcl/target/quark_d20xx.cfg +++ b/tcl/target/quark_d20xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { diff --git a/tcl/target/quark_x10xx.cfg b/tcl/target/quark_x10xx.cfg index a5bbfb4971..6463f21650 100644 --- a/tcl/target/quark_x10xx.cfg +++ b/tcl/target/quark_x10xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { diff --git a/tcl/target/readme.txt b/tcl/target/readme.txt index 91bb2d5f35..deec5b544e 100644 --- a/tcl/target/readme.txt +++ b/tcl/target/readme.txt @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + Prerequisites: The users of OpenOCD as well as computer programs interacting with OpenOCD are expecting that certain commands do the same thing across all the targets. diff --git a/tcl/target/renesas_r7s72100.cfg b/tcl/target/renesas_r7s72100.cfg index 5220b3ccb5..dc9a1d8290 100644 --- a/tcl/target/renesas_r7s72100.cfg +++ b/tcl/target/renesas_r7s72100.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Renesas RZ/A1H # https://www.renesas.com/eu/en/products/microcontrollers-microprocessors/rz/rza/rza1h.html diff --git a/tcl/target/renesas_rcar_gen2.cfg b/tcl/target/renesas_rcar_gen2.cfg index e51b372020..31ba156857 100644 --- a/tcl/target/renesas_rcar_gen2.cfg +++ b/tcl/target/renesas_rcar_gen2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Renesas R-Car Generation 2 SOCs # - There are a combination of Cortex-A15s and Cortex-A7s for each Gen2 SOC # - Each SOC can boot through any of the, up to 2, core types that it has diff --git a/tcl/target/renesas_rcar_gen3.cfg b/tcl/target/renesas_rcar_gen3.cfg index 334d25568f..8dc0e7a0dd 100644 --- a/tcl/target/renesas_rcar_gen3.cfg +++ b/tcl/target/renesas_rcar_gen3.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Renesas R-Car Generation 3 SOCs # - There are a combination of Cortex-A57s, Cortex-A53s, and Cortex-R7 for each Gen3 SOC # - Each SOC can boot through any of the, up to 3, core types that it has @@ -154,15 +156,20 @@ proc setup_a5x {core_name dbgbase ctibase num boot} { } } -proc setup_cr7 {core_name dbgbase ctibase num boot} { +proc setup_crx {core_name dbgbase ctibase num boot} { global _CHIPNAME global _DAPNAME for { set _core 0 } { $_core < $num } { incr _core } { set _TARGETNAME $_CHIPNAME.$core_name set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $_DAPNAME -ap-num 1 -baseaddr $ctibase - set _command "target create $_TARGETNAME cortex_r4 -dap $_DAPNAME \ - -ap-num 1 -dbgbase $dbgbase" + if { $core_name == "r52" } { + set _command "target create $_TARGETNAME armv8r -dap $_DAPNAME \ + -ap-num 1 -dbgbase $dbgbase -cti $_CTINAME" + } else { + set _command "target create $_TARGETNAME cortex_r4 -dap $_DAPNAME \ + -ap-num 1 -dbgbase $dbgbase" + } if { $boot == 1 } { set _targets "$_TARGETNAME" } else { @@ -175,20 +182,20 @@ proc setup_cr7 {core_name dbgbase ctibase num boot} { # Organize target list based on the boot core if { [string equal $_boot_core CA76] } { setup_a5x a76 $CA76_DBGBASE $CA76_CTIBASE $_num_ca76 1 - setup_cr7 r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 0 + setup_crx r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 0 } elseif { [string equal $_boot_core CA57] } { setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 1 setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0 - setup_cr7 r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0 + setup_crx r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0 } elseif { [string equal $_boot_core CA53] } { setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 1 setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0 - setup_cr7 r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0 + setup_crx r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0 } elseif { [string equal $_boot_core CR52] } { - setup_cr7 r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 1 + setup_crx r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 1 setup_a5x a76 $CA76_DBGBASE $CA76_CTIBASE $_num_ca76 0 } else { - setup_cr7 r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 1 + setup_crx r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 1 setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0 setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0 } diff --git a/tcl/target/renesas_rcar_reset_common.cfg b/tcl/target/renesas_rcar_reset_common.cfg index 3e4579b91d..987f0c88eb 100644 --- a/tcl/target/renesas_rcar_reset_common.cfg +++ b/tcl/target/renesas_rcar_reset_common.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Renesas R-Car Gen2 Evaluation Board common settings reset_config trst_and_srst srst_nogate diff --git a/tcl/target/renesas_rz_five.cfg b/tcl/target/renesas_rz_five.cfg new file mode 100644 index 0000000000..5ab94ab1f5 --- /dev/null +++ b/tcl/target/renesas_rz_five.cfg @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Renesas RZ/Five SoC +# +# General-purpose Microprocessors with RISC-V CPU Core (Andes AX45MP Single) (1.0 GHz) + +transport select jtag + +reset_config trst_and_srst srst_gates_jtag +adapter speed 4000 +adapter srst delay 500 + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME r9A07g043u +} + +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME riscv -chain-position $_TARGETNAME diff --git a/tcl/target/renesas_rz_g2.cfg b/tcl/target/renesas_rz_g2.cfg index 3615aa0e2f..a3d5f48fbc 100644 --- a/tcl/target/renesas_rz_g2.cfg +++ b/tcl/target/renesas_rz_g2.cfg @@ -6,11 +6,13 @@ # - Each SOC can boot through the Cortex-A5x cores # Supported RZ/G2 SOCs and their cores: -# RZ/G2H: Cortex-A57 x4, Cortex-A53 x4, Cortex-R7 -# RZ/G2M: Cortex-A57 x2, Cortex-A53 x4, Cortex-R7 -# RZ/G2N: Cortex-A57 x2, Cortex-R7 -# RZ/G2E: Cortex-A53 x2, Cortex-R7 -# RZ/G2L: Cortex-A55 x2, Cortex-M33 +# RZ/G2H: Cortex-A57 x4, Cortex-A53 x4, Cortex-R7 +# RZ/G2M: Cortex-A57 x2, Cortex-A53 x4, Cortex-R7 +# RZ/G2N: Cortex-A57 x2, Cortex-R7 +# RZ/G2E: Cortex-A53 x2, Cortex-R7 +# RZ/G2L: Cortex-A55 x2, Cortex-M33 +# RZ/G2LC: Cortex-A55 x2, Cortex-M33 +# RZ/G2UL: Cortex-A55 x1, Cortex-M33 # Usage: # There are 2 configuration options: @@ -75,6 +77,20 @@ switch $_soc { set _boot_core CA55 set _ap_num 0 } + G2LC { + set _CHIPNAME r9a07g044c + set _num_ca55 2 + set _num_cm33 1 + set _boot_core CA55 + set _ap_num 0 + } + G2UL { + set _CHIPNAME r9a07g043u + set _num_ca55 1 + set _num_cm33 1 + set _boot_core CA55 + set _ap_num 0 + } default { error "'$_soc' is invalid!" } @@ -169,7 +185,7 @@ if { $_boot_core == "CA57" } { echo "SMP targets:$smp_targets" eval "target smp $smp_targets" -if { $_soc == "G2L"} { +if { $_soc == "G2L" || $_soc == "G2LC" || $_soc == "G2UL" } { target create $_CHIPNAME.axi_ap mem_ap -dap $_DAPNAME -ap-num 1 } diff --git a/tcl/target/renesas_s7g2.cfg b/tcl/target/renesas_s7g2.cfg index b4be88f610..fa9c579755 100644 --- a/tcl/target/renesas_s7g2.cfg +++ b/tcl/target/renesas_s7g2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Renesas Synergy S7 G2 w/ ARM Cortex-M4 @ 240 MHz # diff --git a/tcl/target/rk3308.cfg b/tcl/target/rk3308.cfg index 7f957da066..b6086f1701 100644 --- a/tcl/target/rk3308.cfg +++ b/tcl/target/rk3308.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Rockchip RK3308 Target # https://rockchip.fr/RK3308%20datasheet%20V1.5.pdf # https://dl.radxa.com/rockpis/docs/hw/datasheets/Rockchip%20RK3308TRM%20V1.1%20Part1-20180810.pdf diff --git a/tcl/target/rp2040-core0.cfg b/tcl/target/rp2040-core0.cfg deleted file mode 100644 index 8c3533bfb1..0000000000 --- a/tcl/target/rp2040-core0.cfg +++ /dev/null @@ -1,37 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later - -transport select swd - -source [find target/swj-dp.tcl] - -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME rp2040 -} - -if { [info exists WORKAREASIZE] } { - set _WORKAREASIZE $WORKAREASIZE -} else { - set _WORKAREASIZE 0x10000 -} - -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - set _CPUTAPID 0x01002927 -} - -swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID -dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap -$_TARGETNAME configure -work-area-phys 0x20010000 -work-area-size $_WORKAREASIZE - -set _FLASHNAME $_CHIPNAME.flash -set _FLASHSIZE 0x200000 -set _FLASHBASE 0x10000000 -flash bank $_FLASHNAME rp2040_flash $_FLASHBASE $_FLASHSIZE 1 32 $_TARGETNAME - -# srst does not exist; use SYSRESETREQ to perform a soft reset -cortex_m reset_config sysresetreq diff --git a/tcl/target/rp2040.cfg b/tcl/target/rp2040.cfg new file mode 100644 index 0000000000..de76b4e29c --- /dev/null +++ b/tcl/target/rp2040.cfg @@ -0,0 +1,110 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# RP2040 is a microcontroller with dual Cortex-M0+ core. +# https://www.raspberrypi.com/documentation/microcontrollers/rp2040.html + +# The device requires multidrop SWD for debug. +transport select swd + +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME rp2040 +} + +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x10000 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x01002927 +} + +# Set to '1' to start rescue mode +if { [info exists RESCUE] } { + set _RESCUE $RESCUE +} else { + set _RESCUE 0 +} + +# Set to '0' or '1' for single core configuration, 'SMP' for -rtos hwthread +# handling of both cores, anything else for isolated debugging of both cores +if { [info exists USE_CORE] } { + set _USE_CORE $USE_CORE +} else { + set _USE_CORE SMP +} +set _BOTH_CORES [expr { $_USE_CORE != 0 && $_USE_CORE != 1 }] + +swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID + +# The rescue debug port uses the DP CTRL/STAT bit DBGPWRUPREQ to reset the +# PSM (power on state machine) of the RP2040 with a flag set in the +# VREG_AND_POR_CHIP_RESET register. Once the reset is released +# (by clearing the DBGPWRUPREQ flag), the bootrom will run, see this flag, +# and halt. Allowing the user to load some fresh code, rather than loading +# the potentially broken code stored in flash +if { $_RESCUE } { + dap create $_CHIPNAME.rescue_dap -chain-position $_CHIPNAME.cpu -dp-id $_CPUTAPID -instance-id 0xf -ignore-syspwrupack + init + + # Clear DBGPWRUPREQ + $_CHIPNAME.rescue_dap dpreg 0x4 0x00000000 + + # Verifying CTRL/STAT is 0 + set _CTRLSTAT [$_CHIPNAME.rescue_dap dpreg 0x4] + if {[expr {$_CTRLSTAT & 0xf0000000}]} { + echo "Rescue failed, DP CTRL/STAT readback $_CTRLSTAT" + } else { + echo "Now restart OpenOCD without RESCUE flag and load code to RP2040" + } + shutdown +} + +# core 0 +if { $_USE_CORE != 1 } { + dap create $_CHIPNAME.dap0 -chain-position $_CHIPNAME.cpu -dp-id $_CPUTAPID -instance-id 0 + set _TARGETNAME_0 $_CHIPNAME.core0 + target create $_TARGETNAME_0 cortex_m -dap $_CHIPNAME.dap0 -coreid 0 + # srst does not exist; use SYSRESETREQ to perform a soft reset + $_TARGETNAME_0 cortex_m reset_config sysresetreq +} + +# core 1 +if { $_USE_CORE != 0 } { + dap create $_CHIPNAME.dap1 -chain-position $_CHIPNAME.cpu -dp-id $_CPUTAPID -instance-id 1 + set _TARGETNAME_1 $_CHIPNAME.core1 + target create $_TARGETNAME_1 cortex_m -dap $_CHIPNAME.dap1 -coreid 1 + $_TARGETNAME_1 cortex_m reset_config sysresetreq +} + +if {[string compare $_USE_CORE SMP] == 0} { + $_TARGETNAME_0 configure -rtos hwthread + $_TARGETNAME_1 configure -rtos hwthread + target smp $_TARGETNAME_0 $_TARGETNAME_1 +} + +if { $_USE_CORE == 1 } { + set _FLASH_TARGET $_TARGETNAME_1 +} else { + set _FLASH_TARGET $_TARGETNAME_0 +} +# Backup the work area. The flash probe runs an algorithm on the target CPU. +# The flash is probed during gdb connect if gdb_memory_map is enabled (by default). +$_FLASH_TARGET configure -work-area-phys 0x20010000 -work-area-size $_WORKAREASIZE -work-area-backup 1 +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME rp2040_flash 0x10000000 0 0 0 $_FLASH_TARGET + +if { $_BOTH_CORES } { + # Alias to ensure gdb connecting to core 1 gets the correct memory map + flash bank $_CHIPNAME.alias virtual 0x10000000 0 0 0 $_TARGETNAME_1 $_FLASHNAME + + # Select core 0 + targets $_TARGETNAME_0 +} diff --git a/tcl/target/rsl10.cfg b/tcl/target/rsl10.cfg new file mode 100644 index 0000000000..f4692cc7fe --- /dev/null +++ b/tcl/target/rsl10.cfg @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# RSL10: ARM Cortex-M3 +# + +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME rsl10 +} + +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x8000 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x2ba01477 +} + +swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x200000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +# TODO: configure reset +# reset_config srst_only srst_nogate connect_assert_srst + +$_TARGETNAME configure -event examine-fail rsl10_lock_warning + +proc rsl10_check_connection {} { + set target [target current] + set dap [$target cget -dap] + + set IDR [$dap apreg 0 0xfc] + if {$IDR != 0x24770011} { + echo "Error: Cannot access RSL10 AP, maybe connection problem!" + return 1 + } + return 0 +} + +proc rsl10_lock_warning {} { + if {[rsl10_check_connection]} {return} + + poll off + echo "****** WARNING ******" + echo "RSL10 device probably has lock engaged." + echo "Debug access is denied." + echo "Use 'rsl10 unlock key1 key2 key3 key4' to erase and unlock the device." + echo "****** ....... ******" + echo "" +} + +flash bank $_CHIPNAME.main rsl10 0x00100000 0x60000 0 0 $_TARGETNAME +flash bank $_CHIPNAME.nvr1 rsl10 0x00080000 0x800 0 0 $_TARGETNAME +flash bank $_CHIPNAME.nvr2 rsl10 0x00080800 0x800 0 0 $_TARGETNAME +flash bank $_CHIPNAME.nvr3 rsl10 0x00081000 0x800 0 0 $_TARGETNAME + +# TODO: implement flashing for nvr4 +# flash bank $_CHIPNAME.nvr4 rsl10 0x00081800 0x400 0 0 $_TARGETNAME diff --git a/tcl/target/rtl872xd.cfg b/tcl/target/rtl872xd.cfg new file mode 100644 index 0000000000..65730e217f --- /dev/null +++ b/tcl/target/rtl872xd.cfg @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR MIT +# Realtek RTL872xD (ARM Cortex-M33 + M23, wifi+bt dualband soc) + +# HLA does not support AP other than 0 +if { [using_hla] } { + echo "ERROR: HLA transport cannot work with this target." + shutdown +} + +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME rtl872xd +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x6ba02477 +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME.km0 cortex_m -endian little -dap $_CHIPNAME.dap -ap-num 1 +target create $_TARGETNAME.km4 cortex_m -endian little -dap $_CHIPNAME.dap -ap-num 2 + +cortex_m reset_config sysresetreq + +adapter speed 1000 diff --git a/tcl/target/s32k.cfg b/tcl/target/s32k.cfg new file mode 100644 index 0000000000..3ff3239739 --- /dev/null +++ b/tcl/target/s32k.cfg @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Freescale S32K devices +# Similar to Kinetis Kx series devices. +# + +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME s32k +} + +# Work-area is a space in RAM used for flash programming +# By default use 4kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x1000 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x0995001d +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.pflash +flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME -s32k +kinetis create_banks + +adapter speed 1000 + +reset_config srst_nogate + +if {[using_hla]} { + echo "" + echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" + echo " Kinetis MCUs have a MDM-AP dedicated mainly to MCU security related functions." + echo " A high level adapter (like a ST-Link) you are currently using cannot access" + echo " the MDM-AP, so commands like 'mdm mass_erase' are not available in your" + echo " configuration. Also security locked state of the device will not be reported." + echo " Expect problems connecting to a blank device without boot ROM." + echo "" + echo " Be very careful as you can lock the device though there is no way to unlock" + echo " it without mass erase. Don't set write protection on the first block." + echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" + echo "" +} else { + # Detect secured MCU or boot lock-up in RESET/WDOG loop + $_TARGETNAME configure -event examine-fail { + kinetis mdm check_security + } + # During RESET/WDOG loop the target is sometimes falsely examined + $_TARGETNAME configure -event examine-end { + kinetis mdm check_security + } + + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +# Disable watchdog not to disturb OpenOCD algorithms running on MCU +# (e.g. armv7m_checksum_memory() in verify_image) +# Flash driver also disables watchdog before FTFA flash programming. +$_TARGETNAME configure -event reset-init { + kinetis disable_wdog +} diff --git a/tcl/target/samsung_s3c2410.cfg b/tcl/target/samsung_s3c2410.cfg index 017c104927..5a04871f26 100644 --- a/tcl/target/samsung_s3c2410.cfg +++ b/tcl/target/samsung_s3c2410.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Found on the 'TinCanTools' Hammer board. if { [info exists CHIPNAME] } { diff --git a/tcl/target/samsung_s3c2440.cfg b/tcl/target/samsung_s3c2440.cfg index a97659be54..d976a8e3f8 100644 --- a/tcl/target/samsung_s3c2440.cfg +++ b/tcl/target/samsung_s3c2440.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Target configuration for the Samsung 2440 system on chip # Tested on a S3C2440 Evaluation board by keesj # Processor : ARM920Tid(wb) rev 0 (v4l) diff --git a/tcl/target/samsung_s3c2450.cfg b/tcl/target/samsung_s3c2450.cfg index 2482557198..801e1bc972 100644 --- a/tcl/target/samsung_s3c2450.cfg +++ b/tcl/target/samsung_s3c2450.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Target configuration for the Samsung 2450 system on chip # Processor : ARM926ejs (wb) rev 0 (v4l) # Info: JTAG tap: s3c2450.cpu tap/device found: 0x07926F0F diff --git a/tcl/target/samsung_s3c4510.cfg b/tcl/target/samsung_s3c4510.cfg index 8bc5da530f..45bed2f9a4 100644 --- a/tcl/target/samsung_s3c4510.cfg +++ b/tcl/target/samsung_s3c4510.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { diff --git a/tcl/target/samsung_s3c6410.cfg b/tcl/target/samsung_s3c6410.cfg index 9f7c2cddf7..c1574587b8 100644 --- a/tcl/target/samsung_s3c6410.cfg +++ b/tcl/target/samsung_s3c6410.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # -*- tcl -*- # Target configuration for the Samsung s3c6410 system on chip # Tested on a SMDK6410 diff --git a/tcl/target/sharp_lh79532.cfg b/tcl/target/sharp_lh79532.cfg index a464839dc3..af6ceab886 100644 --- a/tcl/target/sharp_lh79532.cfg +++ b/tcl/target/sharp_lh79532.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + reset_config srst_only srst_pulls_trst if { [info exists CHIPNAME] } { diff --git a/tcl/target/sim3x.cfg b/tcl/target/sim3x.cfg index 3d3fc5c3e5..e6bea70e23 100644 --- a/tcl/target/sim3x.cfg +++ b/tcl/target/sim3x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Silicon Laboratories SiM3x Cortex-M3 # diff --git a/tcl/target/smp8634.cfg b/tcl/target/smp8634.cfg index e95f633db1..0e609d84cb 100644 --- a/tcl/target/smp8634.cfg +++ b/tcl/target/smp8634.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for Sigma Designs SMP8634 (eventually even SMP8635) if { [info exists CHIPNAME] } { diff --git a/tcl/target/snps_em_sk_fpga.cfg b/tcl/target/snps_em_sk_fpga.cfg index d09561f387..62f4dec102 100644 --- a/tcl/target/snps_em_sk_fpga.cfg +++ b/tcl/target/snps_em_sk_fpga.cfg @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (C) 2014-2015,2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> -# -# SPDX-License-Identifier: GPL-2.0-or-later # # Xilinx Spartan-6 XC6SLX45 FPGA on EM Starter Kit v1. diff --git a/tcl/target/snps_hsdk.cfg b/tcl/target/snps_hsdk.cfg index 372b406f93..b4f368425c 100644 --- a/tcl/target/snps_hsdk.cfg +++ b/tcl/target/snps_hsdk.cfg @@ -1,8 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (C) 2019,2020 Synopsys, Inc. # Anton Kolesov <anton.kolesov@synopsys.com> # Didin Evgeniy <didin@synopsys.com> -# -# SPDX-License-Identifier: GPL-2.0-or-later # # HS Development Kit SoC. diff --git a/tcl/target/snps_hsdk_4xd.cfg b/tcl/target/snps_hsdk_4xd.cfg new file mode 100644 index 0000000000..1520e3d7c9 --- /dev/null +++ b/tcl/target/snps_hsdk_4xd.cfg @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Copyright (C) 2023 Synopsys, Inc. +# Artemiy Volkov <artemiy@synopsys.com> + +# Adapted from tcl/target/snps_hsdk.cfg. + +# +# HS Development Kit SoC. +# +# Contains quad-core ARC HS47D. +# + +source [find cpu/arc/hs.tcl] + +set _coreid 0 +set _dbgbase [expr {$_coreid << 13}] + +# CHIPNAME will be used to choose core family (600, 700 or EM). As far as +# OpenOCD is concerned EM and HS are identical. +set _CHIPNAME arc-em + + +proc setup_cpu {core_index expected_id} { + global _coreid + global _dbgbase + global _CHIPNAME + + set _TARGETNAME $_CHIPNAME.cpu$core_index + jtag newtap $_CHIPNAME cpu$core_index -irlen 4 -ircapture 0x1 -expected-id $expected_id + + target create $_TARGETNAME arcv2 -chain-position $_TARGETNAME + $_TARGETNAME configure -coreid $_coreid + $_TARGETNAME configure -dbgbase $_dbgbase + $_TARGETNAME configure -event reset-assert "arc_hs_reset $_TARGETNAME" + + arc_hs_init_regs + + $_TARGETNAME arc cache l2 auto 1 + + set _coreid [expr {$_coreid + 1}] + set _dbgbase [expr {$_coreid << 13}] +} + +# OpenOCD discovers JTAG TAPs in reverse order. + +setup_cpu 4 0x100c54b1 +setup_cpu 3 0x100854b1 +setup_cpu 2 0x100454b1 +setup_cpu 1 0x100054b1 diff --git a/tcl/target/spear3xx.cfg b/tcl/target/spear3xx.cfg index a86a3c4ebe..1261cd4721 100644 --- a/tcl/target/spear3xx.cfg +++ b/tcl/target/spear3xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Target configuration for the ST SPEAr3xx family of system on chip # Supported SPEAr300, SPEAr310, SPEAr320 # http://www.st.com/spear diff --git a/tcl/target/stellaris.cfg b/tcl/target/stellaris.cfg index 4865e2916f..3cd91eb372 100644 --- a/tcl/target/stellaris.cfg +++ b/tcl/target/stellaris.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # TI/Luminary Stellaris LM3S chip family # Some devices have errata in returning their device class. diff --git a/tcl/target/stm32c0x.cfg b/tcl/target/stm32c0x.cfg new file mode 100644 index 0000000000..d015120319 --- /dev/null +++ b/tcl/target/stm32c0x.cfg @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# script for stm32c0x family +# +# stm32c0 devices support SWD transports only. +# + +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32c0x +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# By default use 6kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x1800 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + # SWD IDCODE (single drop, arm) + set _CPUTAPID 0x0bc11477 +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME + +# reasonable default +adapter speed 2000 + +adapter srst delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +reset_config srst_nogate + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +$_TARGETNAME configure -event examine-end { + # Enable DBGMCU clock + # RCC_APB1ENR |= DBGMCUEN + mmw 0x4002103C 0x08000000 0 + + # Enable debug during low power modes (uses more power) + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP + mmw 0x40015804 0x00000006 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZ |= DBG_WDGLS_STOP | DBG_WWDG_STOP + mmw 0x40015808 0x00001800 0 +} diff --git a/tcl/target/stm32f0x.cfg b/tcl/target/stm32f0x.cfg index b20d036cf1..5b8954eb21 100644 --- a/tcl/target/stm32f0x.cfg +++ b/tcl/target/stm32f0x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm32f0x family # diff --git a/tcl/target/stm32f1x.cfg b/tcl/target/stm32f1x.cfg index 3e85fb217a..53e81a59f6 100644 --- a/tcl/target/stm32f1x.cfg +++ b/tcl/target/stm32f1x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm32f1x family # @@ -81,9 +83,16 @@ $_TARGETNAME configure -event examine-end { mmw 0xE0042004 0x00000307 0 } -$_TARGETNAME configure -event trace-config { +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + +lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu +proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { + targets $_targetname + # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } + +$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" diff --git a/tcl/target/stm32f2x.cfg b/tcl/target/stm32f2x.cfg index d790febd56..f47582648a 100644 --- a/tcl/target/stm32f2x.cfg +++ b/tcl/target/stm32f2x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm32f2x family # @@ -81,9 +83,16 @@ $_TARGETNAME configure -event examine-end { mmw 0xE0042008 0x00001800 0 } -$_TARGETNAME configure -event trace-config { +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + +lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu +proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { + targets $_targetname + # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } + +$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" diff --git a/tcl/target/stm32f3x.cfg b/tcl/target/stm32f3x.cfg index e3f1a34ddc..aa978d9c84 100644 --- a/tcl/target/stm32f3x.cfg +++ b/tcl/target/stm32f3x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm32f3x family # @@ -22,6 +24,14 @@ if { [info exists WORKAREASIZE] } { set _WORKAREASIZE 0x4000 } +# Allow overriding the Flash bank size +if { [info exists FLASH_SIZE] } { + set _FLASH_SIZE $FLASH_SIZE +} else { + # autodetect size + set _FLASH_SIZE 0 +} + # JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz # # Since we may be running of an RC oscilator, we crank down the speed a @@ -61,7 +71,7 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME stm32f1x 0 0 0 0 $_TARGETNAME +flash bank $_FLASHNAME stm32f1x 0 $_FLASH_SIZE 0 0 $_TARGETNAME reset_config srst_nogate @@ -101,9 +111,16 @@ $_TARGETNAME configure -event examine-end { stm32f3x_default_examine_end } $_TARGETNAME configure -event reset-start { stm32f3x_default_reset_start } $_TARGETNAME configure -event reset-init { stm32f3x_default_reset_init } -$_TARGETNAME configure -event trace-config { +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + +lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu +proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { + targets $_targetname + # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xe0042004 0x00000020 0 } + +$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" diff --git a/tcl/target/stm32f4x.cfg b/tcl/target/stm32f4x.cfg index aa2816e76a..35d8275b55 100644 --- a/tcl/target/stm32f4x.cfg +++ b/tcl/target/stm32f4x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm32f4x family # @@ -38,8 +40,6 @@ if { [info exists CPUTAPID] } { swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu -tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 - if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } @@ -91,24 +91,30 @@ $_TARGETNAME configure -event examine-end { mmw 0xE0042008 0x00001800 0 } -proc proc_post_enable {_chipname} { +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + +lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu +proc _proc_pre_enable_$_CHIPNAME.tpiu {_chipname} { targets $_chipname.cpu if { [$_chipname.tpiu cget -protocol] eq "sync" } { switch [$_chipname.tpiu cget -port-width] { 1 { + # Set TRACE_IOEN; TRACE_MODE to sync 1 bit; GPIOE[2-3] to AF0 mmw 0xE0042004 0x00000060 0x000000c0 mmw 0x40021020 0x00000000 0x0000ff00 mmw 0x40021000 0x000000a0 0x000000f0 mmw 0x40021008 0x000000f0 0x00000000 } 2 { + # Set TRACE_IOEN; TRACE_MODE to sync 2 bit; GPIOE[2-4] to AF0 mmw 0xE0042004 0x000000a0 0x000000c0 mmw 0x40021020 0x00000000 0x000fff00 mmw 0x40021000 0x000002a0 0x000003f0 mmw 0x40021008 0x000003f0 0x00000000 } 4 { + # Set TRACE_IOEN; TRACE_MODE to sync 4 bit; GPIOE[2-6] to AF0 mmw 0xE0042004 0x000000e0 0x000000c0 mmw 0x40021020 0x00000000 0x0fffff00 mmw 0x40021000 0x00002aa0 0x00003ff0 @@ -116,11 +122,12 @@ proc proc_post_enable {_chipname} { } } } else { + # Set TRACE_IOEN; TRACE_MODE to async mmw 0xE0042004 0x00000020 0x000000c0 } } -$_CHIPNAME.tpiu configure -event post-enable "proc_post_enable $_CHIPNAME" +$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_CHIPNAME" $_TARGETNAME configure -event reset-init { # Configure PLL to boost clock to HSI x 4 (64 MHz) diff --git a/tcl/target/stm32f7x.cfg b/tcl/target/stm32f7x.cfg index 91ab2891ba..3782b9a9cc 100644 --- a/tcl/target/stm32f7x.cfg +++ b/tcl/target/stm32f7x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm32f7x family # @@ -107,13 +109,20 @@ $_TARGETNAME configure -event examine-end { mmw 0xE0042008 0x00001800 0 } -$_TARGETNAME configure -event trace-config { +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + +lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu +proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { + targets $_targetname + # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } +$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" + $_TARGETNAME configure -event reset-init { # If the HSE was previously enabled and the external clock source # disappeared, RCC_CR.HSERDY can get stuck at 1 and the PLL cannot be diff --git a/tcl/target/stm32g0x.cfg b/tcl/target/stm32g0x.cfg index 7df5306559..b6d9a22a2c 100644 --- a/tcl/target/stm32g0x.cfg +++ b/tcl/target/stm32g0x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm32g0x family # diff --git a/tcl/target/stm32g4x.cfg b/tcl/target/stm32g4x.cfg index 360447bd5e..39ed1e3818 100644 --- a/tcl/target/stm32g4x.cfg +++ b/tcl/target/stm32g4x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm32g4x family # @@ -95,9 +97,16 @@ $_TARGETNAME configure -event examine-end { mmw 0xE0042008 0x00001800 0 } -$_TARGETNAME configure -event trace-config { +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + +lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu +proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { + targets $_targetname + # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } + +$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg index ca685c2f27..5aae938619 100644 --- a/tcl/target/stm32h7x.cfg +++ b/tcl/target/stm32h7x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm32h7x family # diff --git a/tcl/target/stm32h7x_dual_bank.cfg b/tcl/target/stm32h7x_dual_bank.cfg index a88d70dcfb..41a4773d68 100644 --- a/tcl/target/stm32h7x_dual_bank.cfg +++ b/tcl/target/stm32h7x_dual_bank.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm32h7x family (dual flash bank) # STM32H7xxxI 2Mo have a dual bank flash. diff --git a/tcl/target/stm32l0.cfg b/tcl/target/stm32l0.cfg index 7653d13efe..b4bdb18a4d 100644 --- a/tcl/target/stm32l0.cfg +++ b/tcl/target/stm32l0.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # M0+ devices only have SW-DP, but swj-dp code works, just don't # set any jtag related features diff --git a/tcl/target/stm32l0_dual_bank.cfg b/tcl/target/stm32l0_dual_bank.cfg index f9f1a4e7e7..ff3cb90f55 100644 --- a/tcl/target/stm32l0_dual_bank.cfg +++ b/tcl/target/stm32l0_dual_bank.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/stm32l0.cfg] # Add the second flash bank. diff --git a/tcl/target/stm32l1.cfg b/tcl/target/stm32l1.cfg index a81d7c7985..53d9076e19 100644 --- a/tcl/target/stm32l1.cfg +++ b/tcl/target/stm32l1.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # stm32l1 devices support both JTAG and SWD transports. # @@ -99,9 +101,16 @@ $_TARGETNAME configure -event examine-end { mmw 0xE0042008 0x00001800 0 } -$_TARGETNAME configure -event trace-config { +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + +lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu +proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { + targets $_targetname + # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } + +$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" diff --git a/tcl/target/stm32l1x_dual_bank.cfg b/tcl/target/stm32l1x_dual_bank.cfg index a3f7413a0c..deefdb429b 100644 --- a/tcl/target/stm32l1x_dual_bank.cfg +++ b/tcl/target/stm32l1x_dual_bank.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/stm32l1.cfg] # The stm32l1x 384kb have a dual bank flash. diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg index 9bd7e37ba1..9a696736cd 100644 --- a/tcl/target/stm32l4x.cfg +++ b/tcl/target/stm32l4x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm32l4x family # @@ -38,8 +40,6 @@ if { [info exists CPUTAPID] } { swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu -tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 - if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } @@ -101,24 +101,30 @@ $_TARGETNAME configure -event examine-end { mmw 0xE0042008 0x00001800 0 } -proc proc_post_enable {_chipname} { +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + +lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu +proc _proc_pre_enable_$_CHIPNAME.tpiu {_chipname} { targets $_chipname.cpu if { [$_chipname.tpiu cget -protocol] eq "sync" } { switch [$_chipname.tpiu cget -port-width] { 1 { + # Set TRACE_IOEN; TRACE_MODE to sync 1 bit; GPIOE[2-3] to AF0 mmw 0xE0042004 0x00000060 0x000000c0 mmw 0x48001020 0x00000000 0x0000ff00 mmw 0x48001000 0x000000a0 0x000000f0 mmw 0x48001008 0x000000f0 0x00000000 } 2 { + # Set TRACE_IOEN; TRACE_MODE to sync 2 bit; GPIOE[2-4] to AF0 mmw 0xE0042004 0x000000a0 0x000000c0 mmw 0x48001020 0x00000000 0x000fff00 mmw 0x48001000 0x000002a0 0x000003f0 mmw 0x48001008 0x000003f0 0x00000000 } 4 { + # Set TRACE_IOEN; TRACE_MODE to sync 4 bit; GPIOE[2-6] to AF0 mmw 0xE0042004 0x000000e0 0x000000c0 mmw 0x48001020 0x00000000 0x0fffff00 mmw 0x48001000 0x00002aa0 0x00003ff0 @@ -126,11 +132,12 @@ proc proc_post_enable {_chipname} { } } } else { + # Set TRACE_IOEN; TRACE_MODE to async mmw 0xE0042004 0x00000020 0x000000c0 } } -$_CHIPNAME.tpiu configure -event post-enable "proc_post_enable $_CHIPNAME" +$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_CHIPNAME" $_TARGETNAME configure -event reset-init { # CPU comes out of reset with MSI_ON | MSI_RDY | MSI Range 6 (4 MHz). diff --git a/tcl/target/stm32mp13x.cfg b/tcl/target/stm32mp13x.cfg index 0c464b4116..bcf25c9049 100644 --- a/tcl/target/stm32mp13x.cfg +++ b/tcl/target/stm32mp13x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STMicroelectronics STM32MP13x (Single Cortex-A7) # http://www.st.com/stm32mp1 diff --git a/tcl/target/stm32mp15x.cfg b/tcl/target/stm32mp15x.cfg index afd5d2413e..bcdda73e90 100644 --- a/tcl/target/stm32mp15x.cfg +++ b/tcl/target/stm32mp15x.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # STMicroelectronics STM32MP15x (Single/Dual Cortex-A7 plus Cortex-M4) # http://www.st.com/stm32mp1 diff --git a/tcl/target/stm32w108xx.cfg b/tcl/target/stm32w108xx.cfg index 0470bf6ce8..e6a62e8df2 100644 --- a/tcl/target/stm32w108xx.cfg +++ b/tcl/target/stm32w108xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Target configuration for the ST STM32W108xx chips # diff --git a/tcl/target/stm32wbax.cfg b/tcl/target/stm32wbax.cfg new file mode 100644 index 0000000000..129940720b --- /dev/null +++ b/tcl/target/stm32wbax.cfg @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# script for stm32wbax family + +# +# stm32wba devices support both JTAG and SWD transports. +# +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32wbax +} + +# Work-area is a space in RAM used for flash programming +# By default use 64kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x10000 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x6ba00477 + } else { + # SWD IDCODE (single drop, arm) + set _CPUTAPID 0x6ba02477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +if {[using_jtag]} { + jtag newtap $_CHIPNAME bs -irlen 5 +} + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap -ap-num 1 + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x0FF90000 0 0 0 $_TARGETNAME + +# Common knowledges tells JTAG speed should be <= F_CPU/6. +# F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on +# the safe side. +# +# Note that there is a pretty wide band where things are +# more or less stable, see http://openocd.zylin.com/#/c/3366/ +adapter speed 500 + +adapter srst delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +reset_config srst_nogate + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +$_TARGETNAME configure -event reset-init { + # CPU comes out of reset with HSION | HSIRDY. + # Use HSI 16 MHz clock, compliant even with VOS == 2. + # 1 WS compliant with VOS == 2 and 16 MHz. + mmw 0x40022000 0x00000001 0x0000000E ;# FLASH_ACR: Latency = 1 + mmw 0x56020C00 0x00000100 0x00000000 ;# RCC_CR |= HSION + mmw 0x56020C1C 0x00000000 0x00000002 ;# RCC_CFGR1: SW=HSI16 + # Boost JTAG frequency + adapter speed 4000 +} + +$_TARGETNAME configure -event reset-start { + # Reset clock is HSI (16 MHz) + adapter speed 2000 +} + +$_TARGETNAME configure -event examine-end { + # Enable debug during low power modes (uses more power) + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP + mmw 0xE0042004 0x00000006 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1LFZR |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0xE0042008 0x00001800 0 +} + +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + +lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu +proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { + targets $_targetname +} + +$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" diff --git a/tcl/target/stm32wbx.cfg b/tcl/target/stm32wbx.cfg index 6467667de0..737b1447c0 100644 --- a/tcl/target/stm32wbx.cfg +++ b/tcl/target/stm32wbx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm32wbx family # @@ -95,9 +97,16 @@ $_TARGETNAME configure -event examine-end { mmw 0xE004203C 0x00001800 0 } -$_TARGETNAME configure -event trace-config { +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + +lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu +proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { + targets $_targetname + # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync # change this value accordingly to configure trace pins # assignment mmw 0xE0042004 0x00000020 0 } + +$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" diff --git a/tcl/target/stm32wlx.cfg b/tcl/target/stm32wlx.cfg index 75f6f0288d..39c897fc5d 100644 --- a/tcl/target/stm32wlx.cfg +++ b/tcl/target/stm32wlx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm32wlx family # @@ -117,9 +119,7 @@ $_CHIPNAME.cpu0 configure -event examine-end { } } -$_CHIPNAME.cpu0 configure -event trace-config { - # nothing to do -} +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 if {[set $_CHIPNAME.DUAL_CORE]} { target create $_CHIPNAME.cpu1 cortex_m -endian little -dap $_CHIPNAME.dap -ap-num 1 diff --git a/tcl/target/stm32x5x_common.cfg b/tcl/target/stm32x5x_common.cfg index 276d0cca0c..fb3aeb18c1 100644 --- a/tcl/target/stm32x5x_common.cfg +++ b/tcl/target/stm32x5x_common.cfg @@ -58,7 +58,9 @@ if {[using_jtag]} { reset_config srst_nogate -if {![using_hla]} { +if {[using_hla]} { + echo "Warn : The selected adapter does not support debugging this device in secure mode" +} else { # if srst is not fitted use SYSRESETREQ to # perform a soft reset cortex_m reset_config sysresetreq @@ -71,13 +73,18 @@ proc stm32x5x_is_secure {} { } proc stm32x5x_ahb_ap_non_secure_access {} { - # SPROT=1=Non Secure access, Priv=1 - [[target current] cget -dap] apcsw 0x4B000000 0x4F000000 + # in HLA mode, non-secure debugging is possible without changing the AP CSW + if {![using_hla]} { + # SPROT=1=Non Secure access, Priv=1 + [[target current] cget -dap] apcsw 0x4B000000 0x4F000000 + } } proc stm32x5x_ahb_ap_secure_access {} { - # SPROT=0=Secure access, Priv=1 - [[target current] cget -dap] apcsw 0x0B000000 0x4F000000 + if {![using_hla]} { + # SPROT=0=Secure access, Priv=1 + [[target current] cget -dap] apcsw 0x0B000000 0x4F000000 + } } $_TARGETNAME configure -event reset-start { @@ -146,9 +153,17 @@ $_TARGETNAME configure -event gdb-flash-erase-start { $_TARGETNAME configure -work-area-phys $workarea_addr } -$_TARGETNAME configure -event trace-config { - # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync - # change this value accordingly to configure trace pins +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + +lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu +proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { + targets $_targetname + + # Set TRACE_EN and TRACE_IOEN in DBGMCU_CR + # Leave TRACE_MODE untouched (defaults to async). + # When using sync change this value accordingly to configure trace pins # assignment - mmw 0xE0044004 0x00000020 0 + mmw 0xE0044004 0x00000030 0 } + +$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" diff --git a/tcl/target/stm32xl.cfg b/tcl/target/stm32xl.cfg index f72896d32f..ad68f3a67f 100644 --- a/tcl/target/stm32xl.cfg +++ b/tcl/target/stm32xl.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm32xl family (dual flash bank) source [find target/stm32f1x.cfg] diff --git a/tcl/target/stm8l.cfg b/tcl/target/stm8l.cfg index a06c4cb60c..583a2a4834 100644 --- a/tcl/target/stm8l.cfg +++ b/tcl/target/stm8l.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm8l family # diff --git a/tcl/target/stm8l151x2.cfg b/tcl/target/stm8l151x2.cfg new file mode 100644 index 0000000000..db88c715ba --- /dev/null +++ b/tcl/target/stm8l151x2.cfg @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Config script for STM8L151x2 +# Supported Devices: +# STM8L151C2 +# STM8L151F2 +# STM8L151G2 +# STM8L151K2 + +# 1kB RAM +# Start 0x0000 +# End 0x03ff +set WORKAREASIZE 1024 + +# 4kB Flash +set FLASHSTART 0x8000 +set FLASHEND 0x8fff + +# 256B EEPROM +set EEPROMSTART 0x1000 +set EEPROMEND 0x10ff + +set OPTIONSTART 0x4800 +set OPTIONEND 0x487f + +proc stm8_reset_rop {} { + mwb 0x4800 0xaa + mwb 0x4800 0xaa + reset halt +} + +source [find target/stm8l.cfg] diff --git a/tcl/target/stm8l151x3.cfg b/tcl/target/stm8l151x3.cfg new file mode 100644 index 0000000000..fe904b4f28 --- /dev/null +++ b/tcl/target/stm8l151x3.cfg @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Config script for STM8L151x3 +# Supported Devices: +# STM8L151C3 +# STM8L151F3 +# STM8L151G3 +# STM8L151K3 + +# 1kB RAM +# Start 0x0000 +# End 0x03ff +set WORKAREASIZE 1024 + +# 8kB Flash +set FLASHSTART 0x8000 +set FLASHEND 0x9fff + +# 256B EEPROM +set EEPROMSTART 0x1000 +set EEPROMEND 0x10ff + +set OPTIONSTART 0x4800 +set OPTIONEND 0x487f + +proc stm8_reset_rop {} { + mwb 0x4800 0xaa + mwb 0x4800 0xaa + reset halt +} + +source [find target/stm8l.cfg] diff --git a/tcl/target/stm8l152.cfg b/tcl/target/stm8l152.cfg index 8545a5ab21..033b826d8e 100644 --- a/tcl/target/stm8l152.cfg +++ b/tcl/target/stm8l152.cfg @@ -1,4 +1,7 @@ -#config script for STM8L152 +# SPDX-License-Identifier: GPL-2.0-or-later + +echo 'DEPRECATED: choose between stm8l15xx4.cfg, stm8l15xx6.cfg and stm8l15xx8.cfg instead of stm8l152.cfg' +echo ' using stm8l152.cfg for backwards compatability' set EEPROMSTART 0x1000 set EEPROMEND 0x13ff diff --git a/tcl/target/stm8l15xx4.cfg b/tcl/target/stm8l15xx4.cfg new file mode 100644 index 0000000000..443819357b --- /dev/null +++ b/tcl/target/stm8l15xx4.cfg @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Config script for STM8L151x4/STM8L152x4 +# Supported Devices: +# STM8L151C4 +# STM8L151G4 +# STM8L151K4 +# STM8L152C4 +# STM8L152K4 + +# 2kB RAM +# Start 0x0000 +# End 0x07ff +set WORKAREASIZE 2048 + +# 16kB Flash +set FLASHSTART 0x8000 +set FLASHEND 0xbfff + +# 1kB EEPROM +set EEPROMSTART 0x1000 +set EEPROMEND 0x13ff + +set OPTIONSTART 0x4800 +set OPTIONEND 0x48ff + +proc stm8_reset_rop {} { + mwb 0x4800 0xaa + mwb 0x4800 0xaa + reset halt +} + +source [find target/stm8l.cfg] diff --git a/tcl/target/stm8l15xx6.cfg b/tcl/target/stm8l15xx6.cfg new file mode 100644 index 0000000000..5243295173 --- /dev/null +++ b/tcl/target/stm8l15xx6.cfg @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Config script for STM8L151x6/STM8L152x6 +# Supported Devices: +# STM8L151C6 +# STM8L151G6 +# STM8L151K6 +# STM8L151R6 +# STM8L152C6 +# STM8L152K6 +# STM8L152R6 + +# 2kB RAM +# Start 0x0000 +# End 0x07ff +set WORKAREASIZE 2048 + +# 32kB Flash +set FLASHSTART 0x8000 +set FLASHEND 0xffff + +# 1kB EEPROM +set EEPROMSTART 0x1000 +set EEPROMEND 0x13ff + +set OPTIONSTART 0x4800 +set OPTIONEND 0x48ff + +proc stm8_reset_rop {} { + mwb 0x4800 0xaa + mwb 0x4800 0xaa + reset halt +} + +source [find target/stm8l.cfg] diff --git a/tcl/target/stm8l15xx8.cfg b/tcl/target/stm8l15xx8.cfg new file mode 100644 index 0000000000..e354827377 --- /dev/null +++ b/tcl/target/stm8l15xx8.cfg @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Config script for STM8L151x8/STM8L152x8 +# Supported Devices: +# STM8L151C8 +# STM8L151M8 +# STM8L151R8 +# STM8L152C8 +# STM8L152K8 +# STM8L152M8 +# STM8L152R8 + +# 4kB RAM +# Start 0x0000 +# End 0x0fff +set WORKAREASIZE 4096 + +# 64kB Flash +set FLASHSTART 0x08000 +set FLASHEND 0x17fff + +# 2kB EEPROM +set EEPROMSTART 0x1000 +set EEPROMEND 0x17ff + +set OPTIONSTART 0x4800 +set OPTIONEND 0x48ff + +proc stm8_reset_rop {} { + mwb 0x4800 0xaa + mwb 0x4800 0xaa + reset halt +} + +source [find target/stm8l.cfg] diff --git a/tcl/target/stm8s.cfg b/tcl/target/stm8s.cfg index 2dae655157..01e50d08ef 100644 --- a/tcl/target/stm8s.cfg +++ b/tcl/target/stm8s.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for stm8s family # diff --git a/tcl/target/stm8s003.cfg b/tcl/target/stm8s003.cfg index 34997bec20..60f5c3cea7 100644 --- a/tcl/target/stm8s003.cfg +++ b/tcl/target/stm8s003.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #config script for STM8S003 set FLASHEND 0x9FFF diff --git a/tcl/target/stm8s103.cfg b/tcl/target/stm8s103.cfg index 714acf4800..41350cbb39 100644 --- a/tcl/target/stm8s103.cfg +++ b/tcl/target/stm8s103.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #config script for STM8S103 set FLASHEND 0x9FFF diff --git a/tcl/target/stm8s105.cfg b/tcl/target/stm8s105.cfg index 820bcf75f4..6af491ebf5 100644 --- a/tcl/target/stm8s105.cfg +++ b/tcl/target/stm8s105.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #config script for STM8S105 proc stm8_reset_rop {} { diff --git a/tcl/target/str710.cfg b/tcl/target/str710.cfg index 29faaaa58f..ff89717195 100644 --- a/tcl/target/str710.cfg +++ b/tcl/target/str710.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #start slow, speed up after reset adapter speed 10 diff --git a/tcl/target/str730.cfg b/tcl/target/str730.cfg index e9e2f26e8d..57681f9fcc 100644 --- a/tcl/target/str730.cfg +++ b/tcl/target/str730.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #STR730 CPU adapter speed 3000 diff --git a/tcl/target/str750.cfg b/tcl/target/str750.cfg index 335d5ada9c..5af7b74a70 100644 --- a/tcl/target/str750.cfg +++ b/tcl/target/str750.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + #STR750 CPU if { [info exists CHIPNAME] } { diff --git a/tcl/target/str912.cfg b/tcl/target/str912.cfg index 7426276bfb..3167b407cc 100644 --- a/tcl/target/str912.cfg +++ b/tcl/target/str912.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # script for str9 if { [info exists CHIPNAME] } { diff --git a/tcl/target/swj-dp.tcl b/tcl/target/swj-dp.tcl index 3fb0263f1c..f2b233fb78 100644 --- a/tcl/target/swj-dp.tcl +++ b/tcl/target/swj-dp.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # ARM Debug Interface V5 (ADI_V5) utility # ... Mostly for SWJ-DP (not SW-DP or JTAG-DP, since # SW-DP and JTAG-DP targets don't need to switch based diff --git a/tcl/target/swm050.cfg b/tcl/target/swm050.cfg index e6f2ecbf9d..6cc5f6dccb 100644 --- a/tcl/target/swm050.cfg +++ b/tcl/target/swm050.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Synwit SWM050 source [find target/swj-dp.tcl] diff --git a/tcl/target/test_reset_syntax_error.cfg b/tcl/target/test_reset_syntax_error.cfg index cb4e46fa4e..7ef5914aa3 100644 --- a/tcl/target/test_reset_syntax_error.cfg +++ b/tcl/target/test_reset_syntax_error.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Test script to check that syntax error in reset # script is reported properly. diff --git a/tcl/target/test_syntax_error.cfg b/tcl/target/test_syntax_error.cfg index d4f92fab7b..2d5da7fe08 100644 --- a/tcl/target/test_syntax_error.cfg +++ b/tcl/target/test_syntax_error.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This script tests a syntax error in the startup # config script diff --git a/tcl/target/ti-ar7.cfg b/tcl/target/ti-ar7.cfg index 19d8c6f349..28b6cf7877 100644 --- a/tcl/target/ti-ar7.cfg +++ b/tcl/target/ti-ar7.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Texas Instruments AR7 SOC - used in many adsl modems. # http://www.linux-mips.org/wiki/AR7 diff --git a/tcl/target/ti-cjtag.cfg b/tcl/target/ti-cjtag.cfg index 7114b2adf9..97111f1cc4 100644 --- a/tcl/target/ti-cjtag.cfg +++ b/tcl/target/ti-cjtag.cfg @@ -1,8 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # A start sequence to change from cJTAG to 4-pin JTAG # This is needed for CC2538 and CC26xx to be able to communicate through JTAG # Read section 6.3 in http://www.ti.com/lit/pdf/swru319 for more information. proc ti_cjtag_to_4pin_jtag {jrc} { # Bypass + runtest 20 irscan $jrc 0x3f -endstate RUN/IDLE # Two zero bit scans and a one bit drshift pathmove RUN/IDLE DRSELECT DRCAPTURE DREXIT1 DRPAUSE diff --git a/tcl/target/ti_calypso.cfg b/tcl/target/ti_calypso.cfg index 52a84fb9b4..9083336890 100644 --- a/tcl/target/ti_calypso.cfg +++ b/tcl/target/ti_calypso.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # TI Calypso (lite) G2 C035 Digital Base Band chip # diff --git a/tcl/target/ti_cc13x0.cfg b/tcl/target/ti_cc13x0.cfg index 6ea9bd8075..f1c43a6899 100644 --- a/tcl/target/ti_cc13x0.cfg +++ b/tcl/target/ti_cc13x0.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Texas Instruments CC13x0 - ARM Cortex-M3 # diff --git a/tcl/target/ti_cc13x2.cfg b/tcl/target/ti_cc13x2.cfg index 280eef45fd..c850816851 100644 --- a/tcl/target/ti_cc13x2.cfg +++ b/tcl/target/ti_cc13x2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Texas Instruments CC13x2 - ARM Cortex-M4 # diff --git a/tcl/target/ti_cc26x0.cfg b/tcl/target/ti_cc26x0.cfg index f95d7b2fca..b9ccf31232 100644 --- a/tcl/target/ti_cc26x0.cfg +++ b/tcl/target/ti_cc26x0.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Texas Instruments CC26x0 - ARM Cortex-M3 # diff --git a/tcl/target/ti_cc26x2.cfg b/tcl/target/ti_cc26x2.cfg index ecee3fab53..62c91c3395 100644 --- a/tcl/target/ti_cc26x2.cfg +++ b/tcl/target/ti_cc26x2.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Texas Instruments CC26x2 - ARM Cortex-M4 # diff --git a/tcl/target/ti_cc3220sf.cfg b/tcl/target/ti_cc3220sf.cfg index c0a7b568d3..cf43363768 100644 --- a/tcl/target/ti_cc3220sf.cfg +++ b/tcl/target/ti_cc3220sf.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Texas Instruments CC3220SF - ARM Cortex-M4 # diff --git a/tcl/target/ti_cc32xx.cfg b/tcl/target/ti_cc32xx.cfg index e3e3ebc928..9eb03eb2f4 100644 --- a/tcl/target/ti_cc32xx.cfg +++ b/tcl/target/ti_cc32xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Texas Instruments CC32xx - ARM Cortex-M4 # diff --git a/tcl/target/ti_dm355.cfg b/tcl/target/ti_dm355.cfg index 19fb0b6252..42923733ea 100644 --- a/tcl/target/ti_dm355.cfg +++ b/tcl/target/ti_dm355.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Texas Instruments DaVinci family: TMS320DM355 # diff --git a/tcl/target/ti_dm365.cfg b/tcl/target/ti_dm365.cfg index f71a77aa8b..e19efd7ee4 100644 --- a/tcl/target/ti_dm365.cfg +++ b/tcl/target/ti_dm365.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Texas Instruments DaVinci family: TMS320DM365 # diff --git a/tcl/target/ti_dm6446.cfg b/tcl/target/ti_dm6446.cfg index ccc650a3df..8938234c30 100644 --- a/tcl/target/ti_dm6446.cfg +++ b/tcl/target/ti_dm6446.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Texas Instruments DaVinci family: TMS320DM6446 # diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index 254bb69716..ebea821793 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -2,16 +2,36 @@ # Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments K3 devices: +# * AM243: https://www.ti.com/lit/pdf/spruim2 +# Has 4 R5 Cores, M4F and an M3 +# * AM263: https://www.ti.com/lit/pdf/spruj17 +# Has 4 R5 Cores and an M3 +# * AM273: https://www.ti.com/lit/pdf/spruiu0 +# Has 2 R5 Cores and an M3 +# * AM625: https://www.ti.com/lit/pdf/spruiv7a +# Has 4 ARMV8 Cores and 1 R5 Core and an M4F +# * AM62A7: https://www.ti.com/lit/pdf/spruj16a +# Has 4 ARMV8 Cores and 2 R5 Cores +# * AM62P: https://www.ti.com/lit/pdf/spruj83 +# Has 4 ARMV8 Cores and 2 R5 Cores +# * AM642: https://www.ti.com/lit/pdf/spruim2 +# Has 2 ARMV8 Cores and 4 R5 Cores, M4F and an M3 # * AM654x: https://www.ti.com/lit/pdf/spruid7 # Has 4 ARMV8 Cores and 2 R5 Cores and an M3 -# * J721E: https://www.ti.com/lit/pdf/spruil1 -# Has 2 ARMV8 Cores and 6 R5 Cores and an M3 # * J7200: https://www.ti.com/lit/pdf/spruiu1 # Has 2 ARMV8 Cores and 4 R5 Cores and an M3 -# * AM642: https://www.ti.com/lit/pdf/spruim2 -# Has 2 ARMV8 Cores and 4 R5 Cores, M4F and an M3 +# * J721E: https://www.ti.com/lit/pdf/spruil1 +# Has 2 ARMV8 Cores and 6 R5 Cores and an M3 +# * J721S2: https://www.ti.com/lit/pdf/spruj28 +# Has 2 ARMV8 Cores and 6 R5 Cores and an M4F +# * J722S: https://www.ti.com/lit/zip/sprujb3 +# Has 4 ARMV8 Cores and 3 R5 Cores +# * J784S4/AM69: http://www.ti.com/lit/zip/spruj52 +# Has 8 ARMV8 Cores and 8 R5 Cores # +source [find target/swj-dp.tcl] + if { [info exists SOC] } { set _soc $SOC } else { @@ -32,6 +52,7 @@ set CM3_CTIBASE {0x3C016000} # sysctrl power-ap unlock offsets set _sysctrl_ap_unlock_offsets {0xf0 0x44} +set _sysctrl_ap_num 7 # All the ARMV8s are the next processors. # CL0,CORE0 CL0,CORE1 CL1,CORE0 CL1,CORE1 @@ -43,6 +64,7 @@ set ARMV8_CTIBASE {0x90420000 0x90520000 0x90820000 0x90920000} set R5_DBGBASE {0x9d010000 0x9d012000 0x9d410000 0x9d412000 0x9d510000 0x9d512000} set R5_CTIBASE {0x9d018000 0x9d019000 0x9d418000 0x9d419000 0x9d518000 0x9d519000} set R5_NAMES {mcu_r5.0 mcu_r5.1 main0_r5.0 main0_r5.1 main1_r5.0 main1_r5.1} +set _r5_ap_num 1 # Finally an General Purpose(GP) MCU set CM4_CTIBASE {0x20001000} @@ -52,10 +74,47 @@ set _gp_mcu_cores 0 # General Purpose MCU power-ap unlock offsets set _gp_mcu_ap_unlock_offsets {0xf0 0x60} +# Generic mem-ap port number +set _mem_ap_num 2 + # Set configuration overrides for each SOC switch $_soc { + am263 { + set _K3_DAP_TAPID 0x2bb7d02f + + # Mem-ap port + set _mem_ap_num 6 + + # AM263 has 0 ARMV8 CPUs + set _armv8_cores 0 + + # AM263 has 2 cluster of 2 R5s cores. + set _r5_cores 4 + set R5_NAMES {main0_r5.0 main0_r5.1 main1_r5.0 main1_r5.1} + set R5_DBGBASE {0x90030000 0x90032000 0x90050000 0x90052000} + set R5_CTIBASE {0x90038000 0x90039000 0x90058000 0x90059000} + set _r5_ap_num 5 + } + am273 { + set _K3_DAP_TAPID 0x1bb6a02f + + # Mem-ap port + set _mem_ap_num 6 + + # system controller is on AP0 + set _sysctrl_ap_num 0 + + # AM273 has 0 ARMV8 CPUs + set _armv8_cores 0 + + # AM273 has 1 cluster of 2 R5s cores. + set _r5_cores 2 + set R5_NAMES {main0_r5.0 main0_r5.1} + set R5_DBGBASE {0x90030000 0x90032000} + set R5_CTIBASE {0x90038000 0x90039000} + set _r5_ap_num 5 + } am654 { - set _CHIPNAME am654 set _K3_DAP_TAPID 0x0bb5a02f # AM654 has 2 clusters of 2 A53 cores each. @@ -69,8 +128,8 @@ switch $_soc { # Sysctrl power-ap unlock offsets set _sysctrl_ap_unlock_offsets {0xf0 0x50} } + am243 - am642 { - set _CHIPNAME am642 set _K3_DAP_TAPID 0x0bb3802f # AM642 has 1 clusters of 2 A53 cores each. @@ -87,9 +146,14 @@ switch $_soc { # M4 processor set _gp_mcu_cores 1 + + # Overrides for am243 + if { "$_soc" == "am243" } { + # Uses the same JTAG ID + set _armv8_cores 0 + } } am625 { - set _CHIPNAME am625 set _K3_DAP_TAPID 0x0bb7e02f # AM625 has 1 clusters of 4 A53 cores. @@ -112,9 +176,54 @@ switch $_soc { # M4 processor set _gp_mcu_cores 1 set _gp_mcu_ap_unlock_offsets {0xf0 0x7c} + + # Setup DMEM access descriptions + # DAPBUS (Debugger) description + set _dmem_base_address 0x740002000 + set _dmem_ap_address_offset 0x100 + set _dmem_max_aps 10 + # Emulated AP description + set _dmem_emu_base_address 0x760000000 + set _dmem_emu_base_address_map_to 0x1d500000 + set _dmem_emu_ap_list 1 + } + j722s - + am62p - + am62a7 { + set _K3_DAP_TAPID 0x0bb8d02f + + # AM62a7/AM62P has 1 cluster of 4 A53 cores. + set _armv8_cpu_name a53 + set _armv8_cores 4 + set ARMV8_DBGBASE {0x90010000 0x90110000 0x90210000 0x90310000} + set ARMV8_CTIBASE {0x90020000 0x90120000 0x90220000 0x90320000} + + # AM62a7/AM62P has 2 cluster of 1 R5 core. + set _r5_cores 2 + set R5_NAMES {main0_r5.0 mcu0_r5.0} + set R5_DBGBASE {0x9d410000 0x9d810000} + set R5_CTIBASE {0x9d418000 0x9d818000} + + # sysctrl CTI base + set CM3_CTIBASE {0x20001000} + # Sysctrl power-ap unlock offsets + set _sysctrl_ap_unlock_offsets {0xf0 0x78} + + # Overrides for am62p + if { "$_soc" == "am62p" } { + set _K3_DAP_TAPID 0x0bb9d02f + set R5_NAMES {wkup0_r5.0 mcu0_r5.0} + } + # Overrides for j722s + if { "$_soc" == "j722s" } { + set _K3_DAP_TAPID 0x0bba002f + set _r5_cores 3 + set R5_NAMES {wkup0_r5.0 main0_r5.0 mcu0_r5.0} + set R5_DBGBASE {0x9d410000 0x9d510000 0x9d810000} + set R5_CTIBASE {0x9d418000 0x9d518000 0x9d818000} + } } j721e { - set _CHIPNAME j721e set _K3_DAP_TAPID 0x0bb6402f # J721E has 1 cluster of 2 A72 cores. set _armv8_cpu_name a72 @@ -122,9 +231,18 @@ switch $_soc { # J721E has 3 clusters of 2 R5 cores each. set _r5_cores 6 + + # Setup DMEM access descriptions + # DAPBUS (Debugger) description + set _dmem_base_address 0x4c40002000 + set _dmem_ap_address_offset 0x100 + set _dmem_max_aps 8 + # Emulated AP description + set _dmem_emu_base_address 0x4c60000000 + set _dmem_emu_base_address_map_to 0x1d600000 + set _dmem_emu_ap_list 1 } j7200 { - set _CHIPNAME j7200 set _K3_DAP_TAPID 0x0bb6d02f # J7200 has 1 cluster of 2 A72 cores. @@ -140,7 +258,6 @@ switch $_soc { set CM3_CTIBASE {0x20001000} } j721s2 { - set _CHIPNAME j721s2 set _K3_DAP_TAPID 0x0bb7502f # J721s2 has 1 cluster of 2 A72 cores. @@ -159,12 +276,53 @@ switch $_soc { set _gp_mcu_cores 1 set _gp_mcu_ap_unlock_offsets {0xf0 0x7c} } + j784s4 { + set _K3_DAP_TAPID 0x0bb8002f + + # j784s4 has 2 cluster of 4 A72 cores each. + set _armv8_cpu_name a72 + set _armv8_cores 8 + set ARMV8_DBGBASE {0x90410000 0x90510000 0x90610000 0x90710000 + 0x90810000 0x90910000 0x90a10000 0x90b10000} + set ARMV8_CTIBASE {0x90420000 0x90520000 0x90620000 0x90720000 + 0x90820000 0x90920000 0x90a20000 0x90b20000} + + # J721s2 has 4 clusters of 2 R5 cores each. + set _r5_cores 8 + set R5_DBGBASE {0x9d010000 0x9d012000 + 0x9d410000 0x9d412000 + 0x9d510000 0x9d512000 + 0x9d610000 0x9d612000} + set R5_CTIBASE {0x9d018000 0x9d019000 + 0x9d418000 0x9d419000 + 0x9d518000 0x9d519000 + 0x9d618000 0x9d619000} + set R5_NAMES {mcu_r5.0 mcu_r5.1 + main0_r5.0 main0_r5.1 + main1_r5.0 main1_r5.1 + main2_r5.0 main2_r5.1} + + # sysctrl CTI base + set CM3_CTIBASE {0x20001000} + # Sysctrl power-ap unlock offsets + set _sysctrl_ap_unlock_offsets {0xf0 0x78} + } default { echo "'$_soc' is invalid!" } } -jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_K3_DAP_TAPID -ignore-version +proc _get_rtos_type_for_cpu { target_name } { + if { [info exists ::RTOS($target_name)] } { + return $::RTOS($target_name) + } + return none +} + +set _CHIPNAME $_soc + +swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_K3_DAP_TAPID -ignore-version + dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu @@ -172,8 +330,13 @@ set _TARGETNAME $_CHIPNAME.cpu set _CTINAME $_CHIPNAME.cti # sysctrl is always present -cti create $_CTINAME.sysctrl -dap $_CHIPNAME.dap -ap-num 7 -baseaddr [lindex $CM3_CTIBASE 0] -target create $_TARGETNAME.sysctrl cortex_m -dap $_CHIPNAME.dap -ap-num 7 -defer-examine +cti create $_CTINAME.sysctrl -dap $_CHIPNAME.dap \ + -ap-num $_sysctrl_ap_num -baseaddr [lindex $CM3_CTIBASE 0] + +target create $_TARGETNAME.sysctrl cortex_m -dap $_CHIPNAME.dap \ + -ap-num $_sysctrl_ap_num -defer-examine \ + -rtos [_get_rtos_type_for_cpu $_TARGETNAME.sysctrl] + $_TARGETNAME.sysctrl configure -event reset-assert { } proc sysctrl_up {} { @@ -216,8 +379,9 @@ for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { cti create $_CTINAME.$_armv8_cpu_name.$_core -dap $_CHIPNAME.dap -ap-num 1 \ -baseaddr [lindex $ARMV8_CTIBASE $_core] - target create $_TARGETNAME.$_armv8_cpu_name.$_core aarch64 -dap $_CHIPNAME.dap \ - -dbgbase [lindex $ARMV8_DBGBASE $_core] -cti $_CTINAME.$_armv8_cpu_name.$_core -defer-examine + target create $_TARGETNAME.$_armv8_cpu_name.$_core aarch64 -dap $_CHIPNAME.dap -coreid $_core \ + -dbgbase [lindex $ARMV8_DBGBASE $_core] -cti $_CTINAME.$_armv8_cpu_name.$_core -defer-examine \ + -rtos [_get_rtos_type_for_cpu $_TARGETNAME.$_armv8_cpu_name.$_core] set _v8_smp_targets "$_v8_smp_targets $_TARGETNAME.$_armv8_cpu_name.$_core" @@ -236,34 +400,37 @@ for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { } } -# Setup ARMV8 proc commands based on CPU to prevent people confusing SoCs -set _armv8_up_cmd "$_armv8_cpu_name"_up -# Available if V8_SMP_DEBUG is set to non-zero value -set _armv8_smp_cmd "$_armv8_cpu_name"_smp +if { $_armv8_cores > 0 } { + # Setup ARMV8 proc commands based on CPU to prevent people confusing SoCs + set _armv8_up_cmd "$_armv8_cpu_name"_up + # Available if V8_SMP_DEBUG is set to non-zero value + set _armv8_smp_cmd "$_armv8_cpu_name"_smp -if { $_v8_smp_debug == 0 } { - proc $_armv8_up_cmd { args } { - foreach _core $args { - targets $_core - _cpu_no_smp_up + if { $_v8_smp_debug == 0 } { + proc $_armv8_up_cmd { args } { + foreach _core $args { + targets $_core + _cpu_no_smp_up + } } + } else { + proc $_armv8_smp_cmd { args } { + _armv8_smp_up + } + # Declare SMP + target smp {*}$_v8_smp_targets } -} else { - proc $_armv8_smp_cmd { args } { - _armv8_smp_up - } - # Declare SMP - target smp $:::_v8_smp_targets } for { set _core 0 } { $_core < $_r5_cores } { incr _core } { set _r5_name [lindex $R5_NAMES $_core] - cti create $_CTINAME.$_r5_name -dap $_CHIPNAME.dap -ap-num 1 \ + cti create $_CTINAME.$_r5_name -dap $_CHIPNAME.dap -ap-num $_r5_ap_num \ -baseaddr [lindex $R5_CTIBASE $_core] # inactive core examination will fail - wait till startup of additional core target create $_TARGETNAME.$_r5_name cortex_r4 -dap $_CHIPNAME.dap \ - -dbgbase [lindex $R5_DBGBASE $_core] -ap-num 1 -defer-examine + -dbgbase [lindex $R5_DBGBASE $_core] -ap-num $_r5_ap_num -defer-examine \ + -rtos [_get_rtos_type_for_cpu $_TARGETNAME.$_r5_name] $_TARGETNAME.$_r5_name configure -event gdb-attach { _cpu_no_smp_up @@ -281,7 +448,8 @@ proc r5_up { args } { if { $_gp_mcu_cores != 0 } { cti create $_CTINAME.gp_mcu -dap $_CHIPNAME.dap -ap-num 8 -baseaddr [lindex $CM4_CTIBASE 0] - target create $_TARGETNAME.gp_mcu cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine + target create $_TARGETNAME.gp_mcu cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine \ + -rtos [_get_rtos_type_for_cpu $_TARGETNAME.gp_mcu] $_TARGETNAME.gp_mcu configure -event reset-assert { } proc gp_mcu_up {} { @@ -299,3 +467,25 @@ if { $_gp_mcu_cores != 0 } { halt 1000 } } + +# In case of DMEM access, configure the dmem adapter with offsets from above. +if { 0 == [string compare [adapter name] dmem ] } { + if { [info exists _dmem_base_address] } { + # DAPBUS (Debugger) description + dmem base_address $_dmem_base_address + dmem ap_address_offset $_dmem_ap_address_offset + dmem max_aps $_dmem_max_aps + + # The following are the details of APs to be emulated for direct address access. + # Debug Config (Debugger) description + dmem emu_base_address_range $_dmem_emu_base_address $_dmem_emu_base_address_map_to + dmem emu_ap_list $_dmem_emu_ap_list + # We are going local bus, so speed is really dummy here. + adapter speed 2500 + } else { + puts "ERROR: ${SOC} data is missing to support dmem access!" + } +} else { + # AXI AP access port for SoC address map + target create $_CHIPNAME.axi_ap mem_ap -dap $_CHIPNAME.dap -ap-num $_mem_ap_num +} diff --git a/tcl/target/ti_msp432.cfg b/tcl/target/ti_msp432.cfg index 77f81da690..8a90b98d5b 100644 --- a/tcl/target/ti_msp432.cfg +++ b/tcl/target/ti_msp432.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Texas Instruments MSP432 - ARM Cortex-M4F @ up to 48 MHz # diff --git a/tcl/target/ti_rm4x.cfg b/tcl/target/ti_rm4x.cfg index 85c3e814b3..715aa5b705 100644 --- a/tcl/target/ti_rm4x.cfg +++ b/tcl/target/ti_rm4x.cfg @@ -1 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + source [find target/ti_tms570.cfg] diff --git a/tcl/target/ti_tms570.cfg b/tcl/target/ti_tms570.cfg index d06ff973fc..18e0d82941 100644 --- a/tcl/target/ti_tms570.cfg +++ b/tcl/target/ti_tms570.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + adapter speed 1500 if { [info exists CHIPNAME] } { @@ -20,7 +22,7 @@ source [find target/icepick.cfg] if { [info exists DAP_TAPID] } { set _DAP_TAPID $DAP_TAPID } -jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable -ignore-version jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" # ICEpick-C (JTAG route controller) @@ -33,10 +35,7 @@ set _JRC_TAPID2 0x0B7B302F set _JRC_TAPID3 0x0B95502F set _JRC_TAPID4 0x0B97102F set _JRC_TAPID5 0x0D8A002F -set _JRC_TAPID6 0x2B8A002F -set _JRC_TAPID7 0x2D8A002F -set _JRC_TAPID8 0x3B8A002F -set _JRC_TAPID9 0x3D8A002F +set _JRC_TAPID6 0x0B8A002F jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f \ @@ -46,9 +45,6 @@ jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f \ -expected-id $_JRC_TAPID4 \ -expected-id $_JRC_TAPID5 \ -expected-id $_JRC_TAPID6 \ - -expected-id $_JRC_TAPID7 \ - -expected-id $_JRC_TAPID8 \ - -expected-id $_JRC_TAPID9 \ -ignore-version jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu" jtag configure $_CHIPNAME.jrc -event post-reset "runtest 100" @@ -58,7 +54,7 @@ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # Cortex-R4 target set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_r4 -endian $_ENDIAN \ - -dap $_CHIPNAME.dap -coreid 0 -dbgbase 0x00001003 + -dap $_CHIPNAME.dap -coreid 0 -dbgbase 0x80001000 # TMS570 uses quirky BE-32 mode $_CHIPNAME.dap ti_be_32_quirks 1 diff --git a/tcl/target/ti_tms570lc43xx.cfg b/tcl/target/ti_tms570lc43xx.cfg new file mode 100644 index 0000000000..ffda989f97 --- /dev/null +++ b/tcl/target/ti_tms570lc43xx.cfg @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set DAP_TAPID 0x0B95A02F +set JRC_TAPID 0x0B95A02F + +source [find target/ti_tms570.cfg] diff --git a/tcl/target/ti_tms570ls20xxx.cfg b/tcl/target/ti_tms570ls20xxx.cfg index ef45b7a5cb..cc2bbd6904 100644 --- a/tcl/target/ti_tms570ls20xxx.cfg +++ b/tcl/target/ti_tms570ls20xxx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # TMS570LS20216, TMS570LS20206, TMS570LS10216 # TMS570LS10206, TMS570LS10116, TMS570LS10106 set DAP_TAPID 0x0B7B302F diff --git a/tcl/target/ti_tms570ls3137.cfg b/tcl/target/ti_tms570ls3137.cfg index f29180356b..ebe2cfc652 100644 --- a/tcl/target/ti_tms570ls3137.cfg +++ b/tcl/target/ti_tms570ls3137.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # TMS570LS3137 set DAP_TAPID 0x0B8A002F set JRC_TAPID 0x0B8A002F diff --git a/tcl/target/tmpa900.cfg b/tcl/target/tmpa900.cfg index 8e70700201..b7ec689f13 100644 --- a/tcl/target/tmpa900.cfg +++ b/tcl/target/tmpa900.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: Toshiba TMPA900 ###################################### diff --git a/tcl/target/tmpa910.cfg b/tcl/target/tmpa910.cfg index d933c0b2a8..276d1ad9b0 100644 --- a/tcl/target/tmpa910.cfg +++ b/tcl/target/tmpa910.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + ###################################### # Target: Toshiba TMPA910 ###################################### diff --git a/tcl/target/tnetc4401.cfg b/tcl/target/tnetc4401.cfg index 48f754527a..6a24980ec7 100644 --- a/tcl/target/tnetc4401.cfg +++ b/tcl/target/tnetc4401.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Texas Instruments (TI) TNETC4401, MIPS32 DOCSIS-tailored SoC (4Kc-based) # Used in Knovative KC-100 and Motorola Surfboard SB5120 cable modems. # Datasheet: https://brezn.muc.ccc.de/~mazzoo/DOCSIS/tnetc4401.pdf diff --git a/tcl/target/u8500.cfg b/tcl/target/u8500.cfg index 5aee13541b..417fdd18f2 100644 --- a/tcl/target/u8500.cfg +++ b/tcl/target/u8500.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Copyright (C) ST-Ericsson SA 2011 # Author : michel.jaouen@stericsson.com # U8500 target diff --git a/tcl/target/vd_aarch64.cfg b/tcl/target/vd_aarch64.cfg index 619134aa64..177416bd0a 100644 --- a/tcl/target/vd_aarch64.cfg +++ b/tcl/target/vd_aarch64.cfg @@ -2,36 +2,44 @@ # Cadence virtual debug interface # Arm v8 64b Cortex A -if {![info exists _CORES]} { - set _CORES 1 +if {![info exists CORES]} { + set CORES 1 } -if {![info exists _CHIPNAME]} { - set _CHIPNAME aarch64 +if {![info exists CHIPNAME]} { + set CHIPNAME aarch64 +} +if {[info exists ACCESSPORT]} { + set _APNUM "-ap-num $ACCESSPORT" + if { $ACCESSPORT > 0xff } { + set _DAP6 "-adiv6" + } else { + set _DAP6 "-adiv5" + } +} else { + set _APNUM "" } -set _TARGETNAME $_CHIPNAME.cpu -set _CTINAME $_CHIPNAME.cti -set DBGBASE {0x80810000 0x80910000} -set CTIBASE {0x80820000 0x80920000} +set _TARGETNAME $CHIPNAME.cpu +set _CTINAME $CHIPNAME.cti +set _DAPNAME $CHIPNAME.dap -dap create $_CHIPNAME.dap -chain-position $_TARGETNAME -$_CHIPNAME.dap apsel 1 +dap create $_DAPNAME $_DAP6 -chain-position $_TARGETNAME -for { set _core 0 } { $_core < $_CORES } { incr _core } \ +for { set _core 0 } { $_core < $CORES } { incr _core } \ { - cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 -baseaddr [lindex $CTIBASE $_core] - set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ - -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core -coreid $_core" + set _cmd "cti create $_CTINAME.$_core -dap $_DAPNAME $_APNUM -baseaddr [lindex $CTIBASE $_core]" + eval $_cmd + set _cmd "target create $_TARGETNAME.$_core aarch64 -dap $_DAPNAME $_APNUM -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core -coreid $_core" if { $_core != 0 } { # non-boot core examination may fail - set _command "$_command -defer-examine" - set _smp_command "$_smp_command $_TARGETNAME.$_core" + set _cmd "$_cmd -defer-examine" + set _smp_cmd "$_smp_cmd $_TARGETNAME.$_core" } else { - set _smp_command "target smp $_TARGETNAME.$_core" + set _smp_cmd "target smp $_TARGETNAME.$_core" } - eval $_command + eval $_cmd } -eval $_smp_command +eval $_smp_cmd -# default target is core 0 -targets $_TARGETNAME.0 +set _TARGETCUR $_TARGETNAME.0 +targets $_TARGETCUR diff --git a/tcl/target/vd_cortex_m.cfg b/tcl/target/vd_cortex_m.cfg index 4d7b0df267..7db9d3aba4 100644 --- a/tcl/target/vd_cortex_m.cfg +++ b/tcl/target/vd_cortex_m.cfg @@ -2,11 +2,12 @@ # Cadence virtual debug interface # ARM Cortex M -if {![info exists _CHIPNAME]} { - set _CHIPNAME cortex_m +if {![info exists CHIPNAME]} { + set CHIPNAME cortex_m } -set _TARGETNAME $_CHIPNAME.cpu +set _TARGETNAME $CHIPNAME.cpu +set _DAPNAME $CHIPNAME.dap -dap create $_CHIPNAME.dap -chain-position $_TARGETNAME +dap create $_DAPNAME -chain-position $_TARGETNAME -target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap +target create $_TARGETNAME cortex_m -dap $_DAPNAME diff --git a/tcl/target/vd_riscv.cfg b/tcl/target/vd_riscv.cfg index b42b25a3a5..f08cb1ac8b 100644 --- a/tcl/target/vd_riscv.cfg +++ b/tcl/target/vd_riscv.cfg @@ -14,5 +14,4 @@ target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid $_HARTID riscv set_reset_timeout_sec 120 riscv set_command_timeout_sec 120 -# prefer to use sba for system bus access -riscv set_prefer_sba on +riscv set_mem_access sysbus progbuf diff --git a/tcl/target/vybrid_vf6xx.cfg b/tcl/target/vybrid_vf6xx.cfg index c888d259ff..776c16bbf8 100644 --- a/tcl/target/vybrid_vf6xx.cfg +++ b/tcl/target/vybrid_vf6xx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Freescale Vybrid VF610 # diff --git a/tcl/target/xilinx_zynqmp.cfg b/tcl/target/xilinx_zynqmp.cfg index 2df7a4ff91..9734a18376 100644 --- a/tcl/target/xilinx_zynqmp.cfg +++ b/tcl/target/xilinx_zynqmp.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # target configuration for # Xilinx ZynqMP (UltraScale+ / A53) @@ -84,8 +86,7 @@ for { set _core 0 } { $_core < $_cores } { incr _core } { set _command "$_command -defer-examine" set _smp_command "$_smp_command $_TARGETNAME.$_core" } else { - # uncomment when "hawt" rtos is merged - #set _command "$_command -rtos hawt" + set _command "$_command -rtos hwthread" set _smp_command "target smp $_TARGETNAME.$_core" } diff --git a/tcl/target/xmc1xxx.cfg b/tcl/target/xmc1xxx.cfg index eb94d7b3c5..cafd03221c 100644 --- a/tcl/target/xmc1xxx.cfg +++ b/tcl/target/xmc1xxx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Infineon XMC1100/XMC1200/XMC1300 family (ARM Cortex-M0 @ 32 MHz) # diff --git a/tcl/target/xmc4xxx.cfg b/tcl/target/xmc4xxx.cfg index 3020b28b0f..0e28494a8e 100644 --- a/tcl/target/xmc4xxx.cfg +++ b/tcl/target/xmc4xxx.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # Infineon XMC4100/XMC4200/XMC4400/XMC4500 family (ARM Cortex-M4 @ 80-120 MHz) # diff --git a/tcl/target/xmos_xs1-xau8a-10_arm.cfg b/tcl/target/xmos_xs1-xau8a-10_arm.cfg index 3fc197a3c6..60fe9adbcc 100644 --- a/tcl/target/xmos_xs1-xau8a-10_arm.cfg +++ b/tcl/target/xmos_xs1-xau8a-10_arm.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # # XMOS xCORE-XA XS1-XAU8A-10: ARM Cortex-M3 @ 48 MHz # diff --git a/tcl/target/xtensa-core-esp32.cfg b/tcl/target/xtensa-core-esp32.cfg new file mode 100644 index 0000000000..9a70072e45 --- /dev/null +++ b/tcl/target/xtensa-core-esp32.cfg @@ -0,0 +1,224 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# OpenOCD configuration file for Xtensa ESP32 target + +# Core definition and ABI +xtensa xtdef LX +xtensa xtopt arnum 64 +xtensa xtopt windowed 1 + +# Exception/Interrupt Options +xtensa xtopt exceptions 1 +xtensa xtopt hipriints 1 +xtensa xtopt intlevels 6 +xtensa xtopt excmlevel 3 + +# Cache Options +xtensa xtmem icache 4 0 1 +xtensa xtmem dcache 4 0 1 0 + +# Memory Options +xtensa xtmem irom 0x400D0000 0x330000 +xtensa xtmem irom 0x40000000 0x64F00 +xtensa xtmem iram 0x40070000 0x30000 +xtensa xtmem iram 0x400C0000 0x2000 +xtensa xtmem drom 0x3F400000 0x800000 +xtensa xtmem drom 0x3FF90000 0x10000 +xtensa xtmem dram 0x3FFAE000 0x52000 +xtensa xtmem dram 0x3FF80000 0x2000 +xtensa xtmem dram 0x3F800000 0x400000 +xtensa xtmem dram 0x50000000 0x2000 +xtensa xtmem dram 0x3FF00000 0x71000 +xtensa xtmem dram 0x60000000 0x20000000 + +# Memory Protection/Translation Options + +# Debug Options +xtensa xtopt debuglevel 6 +xtensa xtopt ibreaknum 2 +xtensa xtopt dbreaknum 2 +xtensa xtopt tracemem 0x4000 +xtensa xtopt tracememrev 1 +xtensa xtopt perfcount 2 + +# Core Registers +# xtregfmt: Optionally specify "contiguous" vs. "sparse" GDB register map. +# Default setting is "sparse" and is used with xt-gdb. +# If contiguous, optional parameter specifies number of registers +# in "Read General Registers" (g-packet) requests. +# NOTE: For contiguous format, registers listed in GDB order. +# xtregs: Total number of Xtensa registers in the system +xtensa xtregs 173 +xtensa xtregfmt contiguous 105 +xtensa xtreg pc 0x0020 +xtensa xtreg ar0 0x0100 +xtensa xtreg ar1 0x0101 +xtensa xtreg ar2 0x0102 +xtensa xtreg ar3 0x0103 +xtensa xtreg ar4 0x0104 +xtensa xtreg ar5 0x0105 +xtensa xtreg ar6 0x0106 +xtensa xtreg ar7 0x0107 +xtensa xtreg ar8 0x0108 +xtensa xtreg ar9 0x0109 +xtensa xtreg ar10 0x010a +xtensa xtreg ar11 0x010b +xtensa xtreg ar12 0x010c +xtensa xtreg ar13 0x010d +xtensa xtreg ar14 0x010e +xtensa xtreg ar15 0x010f +xtensa xtreg ar16 0x0110 +xtensa xtreg ar17 0x0111 +xtensa xtreg ar18 0x0112 +xtensa xtreg ar19 0x0113 +xtensa xtreg ar20 0x0114 +xtensa xtreg ar21 0x0115 +xtensa xtreg ar22 0x0116 +xtensa xtreg ar23 0x0117 +xtensa xtreg ar24 0x0118 +xtensa xtreg ar25 0x0119 +xtensa xtreg ar26 0x011a +xtensa xtreg ar27 0x011b +xtensa xtreg ar28 0x011c +xtensa xtreg ar29 0x011d +xtensa xtreg ar30 0x011e +xtensa xtreg ar31 0x011f +xtensa xtreg ar32 0x0120 +xtensa xtreg ar33 0x0121 +xtensa xtreg ar34 0x0122 +xtensa xtreg ar35 0x0123 +xtensa xtreg ar36 0x0124 +xtensa xtreg ar37 0x0125 +xtensa xtreg ar38 0x0126 +xtensa xtreg ar39 0x0127 +xtensa xtreg ar40 0x0128 +xtensa xtreg ar41 0x0129 +xtensa xtreg ar42 0x012a +xtensa xtreg ar43 0x012b +xtensa xtreg ar44 0x012c +xtensa xtreg ar45 0x012d +xtensa xtreg ar46 0x012e +xtensa xtreg ar47 0x012f +xtensa xtreg ar48 0x0130 +xtensa xtreg ar49 0x0131 +xtensa xtreg ar50 0x0132 +xtensa xtreg ar51 0x0133 +xtensa xtreg ar52 0x0134 +xtensa xtreg ar53 0x0135 +xtensa xtreg ar54 0x0136 +xtensa xtreg ar55 0x0137 +xtensa xtreg ar56 0x0138 +xtensa xtreg ar57 0x0139 +xtensa xtreg ar58 0x013a +xtensa xtreg ar59 0x013b +xtensa xtreg ar60 0x013c +xtensa xtreg ar61 0x013d +xtensa xtreg ar62 0x013e +xtensa xtreg ar63 0x013f +xtensa xtreg lbeg 0x0200 +xtensa xtreg lend 0x0201 +xtensa xtreg lcount 0x0202 +xtensa xtreg sar 0x0203 +xtensa xtreg windowbase 0x0248 +xtensa xtreg windowstart 0x0249 +xtensa xtreg configid0 0x02b0 +xtensa xtreg configid1 0x02d0 +xtensa xtreg ps 0x02e6 +xtensa xtreg threadptr 0x03e7 +xtensa xtreg br 0x0204 +xtensa xtreg scompare1 0x020c +xtensa xtreg acclo 0x0210 +xtensa xtreg acchi 0x0211 +xtensa xtreg m0 0x0220 +xtensa xtreg m1 0x0221 +xtensa xtreg m2 0x0222 +xtensa xtreg m3 0x0223 +xtensa xtreg expstate 0x03e6 +xtensa xtreg f64r_lo 0x03ea +xtensa xtreg f64r_hi 0x03eb +xtensa xtreg f64s 0x03ec +xtensa xtreg f0 0x0030 +xtensa xtreg f1 0x0031 +xtensa xtreg f2 0x0032 +xtensa xtreg f3 0x0033 +xtensa xtreg f4 0x0034 +xtensa xtreg f5 0x0035 +xtensa xtreg f6 0x0036 +xtensa xtreg f7 0x0037 +xtensa xtreg f8 0x0038 +xtensa xtreg f9 0x0039 +xtensa xtreg f10 0x003a +xtensa xtreg f11 0x003b +xtensa xtreg f12 0x003c +xtensa xtreg f13 0x003d +xtensa xtreg f14 0x003e +xtensa xtreg f15 0x003f +xtensa xtreg fcr 0x03e8 +xtensa xtreg fsr 0x03e9 +xtensa xtreg mmid 0x0259 +xtensa xtreg ibreakenable 0x0260 +xtensa xtreg memctl 0x0261 +xtensa xtreg atomctl 0x0263 +xtensa xtreg ddr 0x0268 +xtensa xtreg ibreaka0 0x0280 +xtensa xtreg ibreaka1 0x0281 +xtensa xtreg dbreaka0 0x0290 +xtensa xtreg dbreaka1 0x0291 +xtensa xtreg dbreakc0 0x02a0 +xtensa xtreg dbreakc1 0x02a1 +xtensa xtreg epc1 0x02b1 +xtensa xtreg epc2 0x02b2 +xtensa xtreg epc3 0x02b3 +xtensa xtreg epc4 0x02b4 +xtensa xtreg epc5 0x02b5 +xtensa xtreg epc6 0x02b6 +xtensa xtreg epc7 0x02b7 +xtensa xtreg depc 0x02c0 +xtensa xtreg eps2 0x02c2 +xtensa xtreg eps3 0x02c3 +xtensa xtreg eps4 0x02c4 +xtensa xtreg eps5 0x02c5 +xtensa xtreg eps6 0x02c6 +xtensa xtreg eps7 0x02c7 +xtensa xtreg excsave1 0x02d1 +xtensa xtreg excsave2 0x02d2 +xtensa xtreg excsave3 0x02d3 +xtensa xtreg excsave4 0x02d4 +xtensa xtreg excsave5 0x02d5 +xtensa xtreg excsave6 0x02d6 +xtensa xtreg excsave7 0x02d7 +xtensa xtreg cpenable 0x02e0 +xtensa xtreg interrupt 0x02e2 +xtensa xtreg intset 0x02e2 +xtensa xtreg intclear 0x02e3 +xtensa xtreg intenable 0x02e4 +xtensa xtreg vecbase 0x02e7 +xtensa xtreg exccause 0x02e8 +xtensa xtreg debugcause 0x02e9 +xtensa xtreg ccount 0x02ea +xtensa xtreg prid 0x02eb +xtensa xtreg icount 0x02ec +xtensa xtreg icountlevel 0x02ed +xtensa xtreg excvaddr 0x02ee +xtensa xtreg ccompare0 0x02f0 +xtensa xtreg ccompare1 0x02f1 +xtensa xtreg ccompare2 0x02f2 +xtensa xtreg misc0 0x02f4 +xtensa xtreg misc1 0x02f5 +xtensa xtreg misc2 0x02f6 +xtensa xtreg misc3 0x02f7 +xtensa xtreg a0 0x0000 +xtensa xtreg a1 0x0001 +xtensa xtreg a2 0x0002 +xtensa xtreg a3 0x0003 +xtensa xtreg a4 0x0004 +xtensa xtreg a5 0x0005 +xtensa xtreg a6 0x0006 +xtensa xtreg a7 0x0007 +xtensa xtreg a8 0x0008 +xtensa xtreg a9 0x0009 +xtensa xtreg a10 0x000a +xtensa xtreg a11 0x000b +xtensa xtreg a12 0x000c +xtensa xtreg a13 0x000d +xtensa xtreg a14 0x000e +xtensa xtreg a15 0x000f diff --git a/tcl/target/xtensa-core-esp32s2.cfg b/tcl/target/xtensa-core-esp32s2.cfg new file mode 100644 index 0000000000..b38cb1dbb5 --- /dev/null +++ b/tcl/target/xtensa-core-esp32s2.cfg @@ -0,0 +1,223 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# OpenOCD configuration file for Xtensa ESP32S2 target + +# Core definition and ABI +xtensa xtdef LX +xtensa xtopt arnum 64 +xtensa xtopt windowed 1 + +# Exception/Interrupt Options +xtensa xtopt exceptions 1 +xtensa xtopt hipriints 1 +xtensa xtopt intlevels 6 +xtensa xtopt excmlevel 3 + +# Cache Options +xtensa xtmem icache 4 0 1 +xtensa xtmem dcache 4 0 1 0 + +# Memory Options +xtensa xtmem irom 0x40080000 0x780000 +xtensa xtmem irom 0x40000000 0x20000 +xtensa xtmem iram 0x40020000 0x50000 +xtensa xtmem iram 0x40070000 0x2000 +xtensa xtmem drom 0x3F000000 0x400000 +xtensa xtmem drom 0x3F4D3FFC 0xAAC004 +xtensa xtmem drom 0x3FFA0000 0x10000 +xtensa xtmem dram 0x3FFB0000 0x50000 +xtensa xtmem dram 0x3FF9E000 0x2000 +xtensa xtmem dram 0x50000000 0x2000 +xtensa xtmem dram 0x3F500000 0xA80000 +xtensa xtmem dram 0x3F400000 0xD3FFC +xtensa xtmem dram 0x60000000 0x20000000 + +# Memory Protection/Translation Options + +# Debug Options +xtensa xtopt debuglevel 6 +xtensa xtopt ibreaknum 2 +xtensa xtopt dbreaknum 2 +xtensa xtopt tracemem 0x4000 +xtensa xtopt tracememrev 0 +xtensa xtopt perfcount 2 + +# Core Registers +# xtregfmt: Optionally specify "contiguous" vs. "sparse" GDB register map. +# Default setting is "sparse" and is used with xt-gdb. +# If contiguous, optional parameter specifies number of registers +# in "Read General Registers" (g-packet) requests. +# NOTE: For contiguous format, registers listed in GDB order. +# xtregs: Total number of Xtensa registers in the system +xtensa xtregs 171 +xtensa xtregfmt contiguous 73 +xtensa xtreg pc 0x0020 +xtensa xtreg ar0 0x0100 +xtensa xtreg ar1 0x0101 +xtensa xtreg ar2 0x0102 +xtensa xtreg ar3 0x0103 +xtensa xtreg ar4 0x0104 +xtensa xtreg ar5 0x0105 +xtensa xtreg ar6 0x0106 +xtensa xtreg ar7 0x0107 +xtensa xtreg ar8 0x0108 +xtensa xtreg ar9 0x0109 +xtensa xtreg ar10 0x010a +xtensa xtreg ar11 0x010b +xtensa xtreg ar12 0x010c +xtensa xtreg ar13 0x010d +xtensa xtreg ar14 0x010e +xtensa xtreg ar15 0x010f +xtensa xtreg ar16 0x0110 +xtensa xtreg ar17 0x0111 +xtensa xtreg ar18 0x0112 +xtensa xtreg ar19 0x0113 +xtensa xtreg ar20 0x0114 +xtensa xtreg ar21 0x0115 +xtensa xtreg ar22 0x0116 +xtensa xtreg ar23 0x0117 +xtensa xtreg ar24 0x0118 +xtensa xtreg ar25 0x0119 +xtensa xtreg ar26 0x011a +xtensa xtreg ar27 0x011b +xtensa xtreg ar28 0x011c +xtensa xtreg ar29 0x011d +xtensa xtreg ar30 0x011e +xtensa xtreg ar31 0x011f +xtensa xtreg ar32 0x0120 +xtensa xtreg ar33 0x0121 +xtensa xtreg ar34 0x0122 +xtensa xtreg ar35 0x0123 +xtensa xtreg ar36 0x0124 +xtensa xtreg ar37 0x0125 +xtensa xtreg ar38 0x0126 +xtensa xtreg ar39 0x0127 +xtensa xtreg ar40 0x0128 +xtensa xtreg ar41 0x0129 +xtensa xtreg ar42 0x012a +xtensa xtreg ar43 0x012b +xtensa xtreg ar44 0x012c +xtensa xtreg ar45 0x012d +xtensa xtreg ar46 0x012e +xtensa xtreg ar47 0x012f +xtensa xtreg ar48 0x0130 +xtensa xtreg ar49 0x0131 +xtensa xtreg ar50 0x0132 +xtensa xtreg ar51 0x0133 +xtensa xtreg ar52 0x0134 +xtensa xtreg ar53 0x0135 +xtensa xtreg ar54 0x0136 +xtensa xtreg ar55 0x0137 +xtensa xtreg ar56 0x0138 +xtensa xtreg ar57 0x0139 +xtensa xtreg ar58 0x013a +xtensa xtreg ar59 0x013b +xtensa xtreg ar60 0x013c +xtensa xtreg ar61 0x013d +xtensa xtreg ar62 0x013e +xtensa xtreg ar63 0x013f +xtensa xtreg sar 0x0203 +xtensa xtreg windowbase 0x0248 +xtensa xtreg windowstart 0x0249 +xtensa xtreg configid0 0x02b0 +xtensa xtreg configid1 0x02d0 +xtensa xtreg ps 0x02e6 +xtensa xtreg threadptr 0x03e7 +xtensa xtreg gpio_out 0x0300 +xtensa xtreg mmid 0x0259 +xtensa xtreg ibreakenable 0x0260 +xtensa xtreg ddr 0x0268 +xtensa xtreg ibreaka0 0x0280 +xtensa xtreg ibreaka1 0x0281 +xtensa xtreg dbreaka0 0x0290 +xtensa xtreg dbreaka1 0x0291 +xtensa xtreg dbreakc0 0x02a0 +xtensa xtreg dbreakc1 0x02a1 +xtensa xtreg epc1 0x02b1 +xtensa xtreg epc2 0x02b2 +xtensa xtreg epc3 0x02b3 +xtensa xtreg epc4 0x02b4 +xtensa xtreg epc5 0x02b5 +xtensa xtreg epc6 0x02b6 +xtensa xtreg epc7 0x02b7 +xtensa xtreg depc 0x02c0 +xtensa xtreg eps2 0x02c2 +xtensa xtreg eps3 0x02c3 +xtensa xtreg eps4 0x02c4 +xtensa xtreg eps5 0x02c5 +xtensa xtreg eps6 0x02c6 +xtensa xtreg eps7 0x02c7 +xtensa xtreg excsave1 0x02d1 +xtensa xtreg excsave2 0x02d2 +xtensa xtreg excsave3 0x02d3 +xtensa xtreg excsave4 0x02d4 +xtensa xtreg excsave5 0x02d5 +xtensa xtreg excsave6 0x02d6 +xtensa xtreg excsave7 0x02d7 +xtensa xtreg cpenable 0x02e0 +xtensa xtreg interrupt 0x02e2 +xtensa xtreg intset 0x02e2 +xtensa xtreg intclear 0x02e3 +xtensa xtreg intenable 0x02e4 +xtensa xtreg vecbase 0x02e7 +xtensa xtreg exccause 0x02e8 +xtensa xtreg debugcause 0x02e9 +xtensa xtreg ccount 0x02ea +xtensa xtreg prid 0x02eb +xtensa xtreg icount 0x02ec +xtensa xtreg icountlevel 0x02ed +xtensa xtreg excvaddr 0x02ee +xtensa xtreg ccompare0 0x02f0 +xtensa xtreg ccompare1 0x02f1 +xtensa xtreg ccompare2 0x02f2 +xtensa xtreg misc0 0x02f4 +xtensa xtreg misc1 0x02f5 +xtensa xtreg misc2 0x02f6 +xtensa xtreg misc3 0x02f7 +xtensa xtreg pwrctl 0x2014 +xtensa xtreg pwrstat 0x2015 +xtensa xtreg eristat 0x2016 +xtensa xtreg cs_itctrl 0x2017 +xtensa xtreg cs_claimset 0x2018 +xtensa xtreg cs_claimclr 0x2019 +xtensa xtreg cs_lockaccess 0x201a +xtensa xtreg cs_lockstatus 0x201b +xtensa xtreg cs_authstatus 0x201c +xtensa xtreg fault_info 0x202b +xtensa xtreg trax_id 0x202c +xtensa xtreg trax_control 0x202d +xtensa xtreg trax_status 0x202e +xtensa xtreg trax_data 0x202f +xtensa xtreg trax_address 0x2030 +xtensa xtreg trax_pctrigger 0x2031 +xtensa xtreg trax_pcmatch 0x2032 +xtensa xtreg trax_delay 0x2033 +xtensa xtreg trax_memstart 0x2034 +xtensa xtreg trax_memend 0x2035 +xtensa xtreg pmg 0x2043 +xtensa xtreg pmpc 0x2044 +xtensa xtreg pm0 0x2045 +xtensa xtreg pm1 0x2046 +xtensa xtreg pmctrl0 0x2047 +xtensa xtreg pmctrl1 0x2048 +xtensa xtreg pmstat0 0x2049 +xtensa xtreg pmstat1 0x204a +xtensa xtreg ocdid 0x204b +xtensa xtreg ocd_dcrclr 0x204c +xtensa xtreg ocd_dcrset 0x204d +xtensa xtreg ocd_dsr 0x204e +xtensa xtreg a0 0x0000 +xtensa xtreg a1 0x0001 +xtensa xtreg a2 0x0002 +xtensa xtreg a3 0x0003 +xtensa xtreg a4 0x0004 +xtensa xtreg a5 0x0005 +xtensa xtreg a6 0x0006 +xtensa xtreg a7 0x0007 +xtensa xtreg a8 0x0008 +xtensa xtreg a9 0x0009 +xtensa xtreg a10 0x000a +xtensa xtreg a11 0x000b +xtensa xtreg a12 0x000c +xtensa xtreg a13 0x000d +xtensa xtreg a14 0x000e +xtensa xtreg a15 0x000f diff --git a/tcl/target/xtensa-core-esp32s3.cfg b/tcl/target/xtensa-core-esp32s3.cfg new file mode 100644 index 0000000000..b3f20e39d5 --- /dev/null +++ b/tcl/target/xtensa-core-esp32s3.cfg @@ -0,0 +1,276 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# OpenOCD configuration file for Xtensa ESP32S3 target + +# Core definition and ABI +xtensa xtdef LX +xtensa xtopt arnum 64 +xtensa xtopt windowed 1 + +# Exception/Interrupt Options +xtensa xtopt exceptions 1 +xtensa xtopt hipriints 1 +xtensa xtopt intlevels 6 +xtensa xtopt excmlevel 3 + +# Cache Options + +# Memory Options +xtensa xtmem irom 0x42000000 0x2000000 +xtensa xtmem irom 0x40000000 0x60000 +xtensa xtmem iram 0x40370000 0x70000 +xtensa xtmem iram 0x600FE000 0x2000 +xtensa xtmem drom 0x3C000000 0x1000000 +xtensa xtmem drom 0x3FF00000 0x20000 +xtensa xtmem dram 0x3FC88000 0x78000 +xtensa xtmem dram 0x600FE000 0x2000 +xtensa xtmem dram 0x50000000 0x2000 +xtensa xtmem dram 0x60000000 0x10000000 + +# Memory Protection/Translation Options + +# Debug Options +xtensa xtopt debuglevel 6 +xtensa xtopt ibreaknum 2 +xtensa xtopt dbreaknum 2 +xtensa xtopt tracemem 0x4000 +xtensa xtopt tracememrev 0 +xtensa xtopt perfcount 2 + + +# Core Registers +# xtregfmt: Optionally specify "contiguous" vs. "sparse" GDB register map. +# Default setting is "sparse" and is used with xt-gdb. +# If contiguous, optional parameter specifies number of registers +# in "Read General Registers" (g-packet) requests. +# NOTE: For contiguous format, registers listed in GDB order. +# xtregs: Total number of Xtensa registers in the system +xtensa xtregs 228 +xtensa xtregfmt contiguous 128 +xtensa xtreg pc 0x0020 +xtensa xtreg ar0 0x0100 +xtensa xtreg ar1 0x0101 +xtensa xtreg ar2 0x0102 +xtensa xtreg ar3 0x0103 +xtensa xtreg ar4 0x0104 +xtensa xtreg ar5 0x0105 +xtensa xtreg ar6 0x0106 +xtensa xtreg ar7 0x0107 +xtensa xtreg ar8 0x0108 +xtensa xtreg ar9 0x0109 +xtensa xtreg ar10 0x010a +xtensa xtreg ar11 0x010b +xtensa xtreg ar12 0x010c +xtensa xtreg ar13 0x010d +xtensa xtreg ar14 0x010e +xtensa xtreg ar15 0x010f +xtensa xtreg ar16 0x0110 +xtensa xtreg ar17 0x0111 +xtensa xtreg ar18 0x0112 +xtensa xtreg ar19 0x0113 +xtensa xtreg ar20 0x0114 +xtensa xtreg ar21 0x0115 +xtensa xtreg ar22 0x0116 +xtensa xtreg ar23 0x0117 +xtensa xtreg ar24 0x0118 +xtensa xtreg ar25 0x0119 +xtensa xtreg ar26 0x011a +xtensa xtreg ar27 0x011b +xtensa xtreg ar28 0x011c +xtensa xtreg ar29 0x011d +xtensa xtreg ar30 0x011e +xtensa xtreg ar31 0x011f +xtensa xtreg ar32 0x0120 +xtensa xtreg ar33 0x0121 +xtensa xtreg ar34 0x0122 +xtensa xtreg ar35 0x0123 +xtensa xtreg ar36 0x0124 +xtensa xtreg ar37 0x0125 +xtensa xtreg ar38 0x0126 +xtensa xtreg ar39 0x0127 +xtensa xtreg ar40 0x0128 +xtensa xtreg ar41 0x0129 +xtensa xtreg ar42 0x012a +xtensa xtreg ar43 0x012b +xtensa xtreg ar44 0x012c +xtensa xtreg ar45 0x012d +xtensa xtreg ar46 0x012e +xtensa xtreg ar47 0x012f +xtensa xtreg ar48 0x0130 +xtensa xtreg ar49 0x0131 +xtensa xtreg ar50 0x0132 +xtensa xtreg ar51 0x0133 +xtensa xtreg ar52 0x0134 +xtensa xtreg ar53 0x0135 +xtensa xtreg ar54 0x0136 +xtensa xtreg ar55 0x0137 +xtensa xtreg ar56 0x0138 +xtensa xtreg ar57 0x0139 +xtensa xtreg ar58 0x013a +xtensa xtreg ar59 0x013b +xtensa xtreg ar60 0x013c +xtensa xtreg ar61 0x013d +xtensa xtreg ar62 0x013e +xtensa xtreg ar63 0x013f +xtensa xtreg lbeg 0x0200 +xtensa xtreg lend 0x0201 +xtensa xtreg lcount 0x0202 +xtensa xtreg sar 0x0203 +xtensa xtreg windowbase 0x0248 +xtensa xtreg windowstart 0x0249 +xtensa xtreg configid0 0x02b0 +xtensa xtreg configid1 0x02d0 +xtensa xtreg ps 0x02e6 +xtensa xtreg threadptr 0x03e7 +xtensa xtreg br 0x0204 +xtensa xtreg scompare1 0x020c +xtensa xtreg acclo 0x0210 +xtensa xtreg acchi 0x0211 +xtensa xtreg m0 0x0220 +xtensa xtreg m1 0x0221 +xtensa xtreg m2 0x0222 +xtensa xtreg m3 0x0223 +xtensa xtreg gpio_out 0x030c +xtensa xtreg f0 0x0030 +xtensa xtreg f1 0x0031 +xtensa xtreg f2 0x0032 +xtensa xtreg f3 0x0033 +xtensa xtreg f4 0x0034 +xtensa xtreg f5 0x0035 +xtensa xtreg f6 0x0036 +xtensa xtreg f7 0x0037 +xtensa xtreg f8 0x0038 +xtensa xtreg f9 0x0039 +xtensa xtreg f10 0x003a +xtensa xtreg f11 0x003b +xtensa xtreg f12 0x003c +xtensa xtreg f13 0x003d +xtensa xtreg f14 0x003e +xtensa xtreg f15 0x003f +xtensa xtreg fcr 0x03e8 +xtensa xtreg fsr 0x03e9 +xtensa xtreg accx_0 0x0300 +xtensa xtreg accx_1 0x0301 +xtensa xtreg qacc_h_0 0x0302 +xtensa xtreg qacc_h_1 0x0303 +xtensa xtreg qacc_h_2 0x0304 +xtensa xtreg qacc_h_3 0x0305 +xtensa xtreg qacc_h_4 0x0306 +xtensa xtreg qacc_l_0 0x0307 +xtensa xtreg qacc_l_1 0x0308 +xtensa xtreg qacc_l_2 0x0309 +xtensa xtreg qacc_l_3 0x030a +xtensa xtreg qacc_l_4 0x030b +xtensa xtreg sar_byte 0x030d +xtensa xtreg fft_bit_width 0x030e +xtensa xtreg ua_state_0 0x030f +xtensa xtreg ua_state_1 0x0310 +xtensa xtreg ua_state_2 0x0311 +xtensa xtreg ua_state_3 0x0312 +xtensa xtreg q0 0x1008 +xtensa xtreg q1 0x1009 +xtensa xtreg q2 0x100a +xtensa xtreg q3 0x100b +xtensa xtreg q4 0x100c +xtensa xtreg q5 0x100d +xtensa xtreg q6 0x100e +xtensa xtreg q7 0x100f +xtensa xtreg mmid 0x0259 +xtensa xtreg ibreakenable 0x0260 +xtensa xtreg memctl 0x0261 +xtensa xtreg atomctl 0x0263 +xtensa xtreg ddr 0x0268 +xtensa xtreg ibreaka0 0x0280 +xtensa xtreg ibreaka1 0x0281 +xtensa xtreg dbreaka0 0x0290 +xtensa xtreg dbreaka1 0x0291 +xtensa xtreg dbreakc0 0x02a0 +xtensa xtreg dbreakc1 0x02a1 +xtensa xtreg epc1 0x02b1 +xtensa xtreg epc2 0x02b2 +xtensa xtreg epc3 0x02b3 +xtensa xtreg epc4 0x02b4 +xtensa xtreg epc5 0x02b5 +xtensa xtreg epc6 0x02b6 +xtensa xtreg epc7 0x02b7 +xtensa xtreg depc 0x02c0 +xtensa xtreg eps2 0x02c2 +xtensa xtreg eps3 0x02c3 +xtensa xtreg eps4 0x02c4 +xtensa xtreg eps5 0x02c5 +xtensa xtreg eps6 0x02c6 +xtensa xtreg eps7 0x02c7 +xtensa xtreg excsave1 0x02d1 +xtensa xtreg excsave2 0x02d2 +xtensa xtreg excsave3 0x02d3 +xtensa xtreg excsave4 0x02d4 +xtensa xtreg excsave5 0x02d5 +xtensa xtreg excsave6 0x02d6 +xtensa xtreg excsave7 0x02d7 +xtensa xtreg cpenable 0x02e0 +xtensa xtreg interrupt 0x02e2 +xtensa xtreg intset 0x02e2 +xtensa xtreg intclear 0x02e3 +xtensa xtreg intenable 0x02e4 +xtensa xtreg vecbase 0x02e7 +xtensa xtreg exccause 0x02e8 +xtensa xtreg debugcause 0x02e9 +xtensa xtreg ccount 0x02ea +xtensa xtreg prid 0x02eb +xtensa xtreg icount 0x02ec +xtensa xtreg icountlevel 0x02ed +xtensa xtreg excvaddr 0x02ee +xtensa xtreg ccompare0 0x02f0 +xtensa xtreg ccompare1 0x02f1 +xtensa xtreg ccompare2 0x02f2 +xtensa xtreg misc0 0x02f4 +xtensa xtreg misc1 0x02f5 +xtensa xtreg misc2 0x02f6 +xtensa xtreg misc3 0x02f7 +xtensa xtreg pwrctl 0x2028 +xtensa xtreg pwrstat 0x2029 +xtensa xtreg eristat 0x202a +xtensa xtreg cs_itctrl 0x202b +xtensa xtreg cs_claimset 0x202c +xtensa xtreg cs_claimclr 0x202d +xtensa xtreg cs_lockaccess 0x202e +xtensa xtreg cs_lockstatus 0x202f +xtensa xtreg cs_authstatus 0x2030 +xtensa xtreg fault_info 0x203f +xtensa xtreg trax_id 0x2040 +xtensa xtreg trax_control 0x2041 +xtensa xtreg trax_status 0x2042 +xtensa xtreg trax_data 0x2043 +xtensa xtreg trax_address 0x2044 +xtensa xtreg trax_pctrigger 0x2045 +xtensa xtreg trax_pcmatch 0x2046 +xtensa xtreg trax_delay 0x2047 +xtensa xtreg trax_memstart 0x2048 +xtensa xtreg trax_memend 0x2049 +xtensa xtreg pmg 0x2057 +xtensa xtreg pmpc 0x2058 +xtensa xtreg pm0 0x2059 +xtensa xtreg pm1 0x205a +xtensa xtreg pmctrl0 0x205b +xtensa xtreg pmctrl1 0x205c +xtensa xtreg pmstat0 0x205d +xtensa xtreg pmstat1 0x205e +xtensa xtreg ocdid 0x205f +xtensa xtreg ocd_dcrclr 0x2060 +xtensa xtreg ocd_dcrset 0x2061 +xtensa xtreg ocd_dsr 0x2062 +xtensa xtreg a0 0x0000 +xtensa xtreg a1 0x0001 +xtensa xtreg a2 0x0002 +xtensa xtreg a3 0x0003 +xtensa xtreg a4 0x0004 +xtensa xtreg a5 0x0005 +xtensa xtreg a6 0x0006 +xtensa xtreg a7 0x0007 +xtensa xtreg a8 0x0008 +xtensa xtreg a9 0x0009 +xtensa xtreg a10 0x000a +xtensa xtreg a11 0x000b +xtensa xtreg a12 0x000c +xtensa xtreg a13 0x000d +xtensa xtreg a14 0x000e +xtensa xtreg a15 0x000f diff --git a/tcl/target/xtensa-core-nxp_rt600.cfg b/tcl/target/xtensa-core-nxp_rt600.cfg new file mode 100644 index 0000000000..ca7fd68480 --- /dev/null +++ b/tcl/target/xtensa-core-nxp_rt600.cfg @@ -0,0 +1,255 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# OpenOCD configuration file for Xtensa HiFi DSP in NXP RT600 target + + +# Core instance default definition +if { [info exists XTNAME] } { + set _XTNAME $XTNAME +} else { + set _XTNAME xtensa.cpu +} + + +# Core definition and ABI +$_XTNAME xtensa xtdef LX +$_XTNAME xtensa xtopt arnum 32 +$_XTNAME xtensa xtopt windowed 1 + + +# Exception/Interrupt Options +$_XTNAME xtensa xtopt exceptions 1 +$_XTNAME xtensa xtopt hipriints 1 +$_XTNAME xtensa xtopt intlevels 4 +$_XTNAME xtensa xtopt excmlevel 2 + + +# Cache Options +$_XTNAME xtensa xtmem icache 256 32768 4 +$_XTNAME xtensa xtmem dcache 256 65536 4 1 + + +# Memory Options +$_XTNAME xtensa xtmem iram 0x24020000 65536 +$_XTNAME xtensa xtmem dram 0x24000000 65536 +$_XTNAME xtensa xtmem sram 0x00000000 603979776 + + +# Memory Protection/Translation Options + + +# Debug Options +$_XTNAME xtensa xtopt debuglevel 4 +$_XTNAME xtensa xtopt ibreaknum 2 +$_XTNAME xtensa xtopt dbreaknum 2 + + +# Core Registers +$_XTNAME xtensa xtregs 208 +$_XTNAME xtensa xtreg pc 0x0020 +$_XTNAME xtensa xtreg ar0 0x0100 +$_XTNAME xtensa xtreg ar1 0x0101 +$_XTNAME xtensa xtreg ar2 0x0102 +$_XTNAME xtensa xtreg ar3 0x0103 +$_XTNAME xtensa xtreg ar4 0x0104 +$_XTNAME xtensa xtreg ar5 0x0105 +$_XTNAME xtensa xtreg ar6 0x0106 +$_XTNAME xtensa xtreg ar7 0x0107 +$_XTNAME xtensa xtreg ar8 0x0108 +$_XTNAME xtensa xtreg ar9 0x0109 +$_XTNAME xtensa xtreg ar10 0x010a +$_XTNAME xtensa xtreg ar11 0x010b +$_XTNAME xtensa xtreg ar12 0x010c +$_XTNAME xtensa xtreg ar13 0x010d +$_XTNAME xtensa xtreg ar14 0x010e +$_XTNAME xtensa xtreg ar15 0x010f +$_XTNAME xtensa xtreg ar16 0x0110 +$_XTNAME xtensa xtreg ar17 0x0111 +$_XTNAME xtensa xtreg ar18 0x0112 +$_XTNAME xtensa xtreg ar19 0x0113 +$_XTNAME xtensa xtreg ar20 0x0114 +$_XTNAME xtensa xtreg ar21 0x0115 +$_XTNAME xtensa xtreg ar22 0x0116 +$_XTNAME xtensa xtreg ar23 0x0117 +$_XTNAME xtensa xtreg ar24 0x0118 +$_XTNAME xtensa xtreg ar25 0x0119 +$_XTNAME xtensa xtreg ar26 0x011a +$_XTNAME xtensa xtreg ar27 0x011b +$_XTNAME xtensa xtreg ar28 0x011c +$_XTNAME xtensa xtreg ar29 0x011d +$_XTNAME xtensa xtreg ar30 0x011e +$_XTNAME xtensa xtreg ar31 0x011f +$_XTNAME xtensa xtreg lbeg 0x0200 +$_XTNAME xtensa xtreg lend 0x0201 +$_XTNAME xtensa xtreg lcount 0x0202 +$_XTNAME xtensa xtreg sar 0x0203 +$_XTNAME xtensa xtreg prefctl 0x0228 +$_XTNAME xtensa xtreg windowbase 0x0248 +$_XTNAME xtensa xtreg windowstart 0x0249 +$_XTNAME xtensa xtreg configid0 0x02b0 +$_XTNAME xtensa xtreg configid1 0x02d0 +$_XTNAME xtensa xtreg ps 0x02e6 +$_XTNAME xtensa xtreg threadptr 0x03e7 +$_XTNAME xtensa xtreg br 0x0204 +$_XTNAME xtensa xtreg scompare1 0x020c +$_XTNAME xtensa xtreg acclo 0x0210 +$_XTNAME xtensa xtreg acchi 0x0211 +$_XTNAME xtensa xtreg m0 0x0220 +$_XTNAME xtensa xtreg m1 0x0221 +$_XTNAME xtensa xtreg m2 0x0222 +$_XTNAME xtensa xtreg m3 0x0223 +$_XTNAME xtensa xtreg expstate 0x03e6 +$_XTNAME xtensa xtreg f64r_lo 0x03ea +$_XTNAME xtensa xtreg f64r_hi 0x03eb +$_XTNAME xtensa xtreg f64s 0x03ec +$_XTNAME xtensa xtreg ae_ovf_sar 0x03f0 +$_XTNAME xtensa xtreg ae_bithead 0x03f1 +$_XTNAME xtensa xtreg ae_ts_fts_bu_bp 0x03f2 +$_XTNAME xtensa xtreg ae_cw_sd_no 0x03f3 +$_XTNAME xtensa xtreg ae_cbegin0 0x03f6 +$_XTNAME xtensa xtreg ae_cend0 0x03f7 +$_XTNAME xtensa xtreg ae_cbegin1 0x03f8 +$_XTNAME xtensa xtreg ae_cend1 0x03f9 +$_XTNAME xtensa xtreg aed0 0x1010 +$_XTNAME xtensa xtreg aed1 0x1011 +$_XTNAME xtensa xtreg aed2 0x1012 +$_XTNAME xtensa xtreg aed3 0x1013 +$_XTNAME xtensa xtreg aed4 0x1014 +$_XTNAME xtensa xtreg aed5 0x1015 +$_XTNAME xtensa xtreg aed6 0x1016 +$_XTNAME xtensa xtreg aed7 0x1017 +$_XTNAME xtensa xtreg aed8 0x1018 +$_XTNAME xtensa xtreg aed9 0x1019 +$_XTNAME xtensa xtreg aed10 0x101a +$_XTNAME xtensa xtreg aed11 0x101b +$_XTNAME xtensa xtreg aed12 0x101c +$_XTNAME xtensa xtreg aed13 0x101d +$_XTNAME xtensa xtreg aed14 0x101e +$_XTNAME xtensa xtreg aed15 0x101f +$_XTNAME xtensa xtreg u0 0x1020 +$_XTNAME xtensa xtreg u1 0x1021 +$_XTNAME xtensa xtreg u2 0x1022 +$_XTNAME xtensa xtreg u3 0x1023 +$_XTNAME xtensa xtreg aep0 0x1024 +$_XTNAME xtensa xtreg aep1 0x1025 +$_XTNAME xtensa xtreg aep2 0x1026 +$_XTNAME xtensa xtreg aep3 0x1027 +$_XTNAME xtensa xtreg fcr_fsr 0x1029 +$_XTNAME xtensa xtreg mmid 0x0259 +$_XTNAME xtensa xtreg ibreakenable 0x0260 +$_XTNAME xtensa xtreg memctl 0x0261 +$_XTNAME xtensa xtreg atomctl 0x0263 +$_XTNAME xtensa xtreg ddr 0x0268 +$_XTNAME xtensa xtreg ibreaka0 0x0280 +$_XTNAME xtensa xtreg ibreaka1 0x0281 +$_XTNAME xtensa xtreg dbreaka0 0x0290 +$_XTNAME xtensa xtreg dbreaka1 0x0291 +$_XTNAME xtensa xtreg dbreakc0 0x02a0 +$_XTNAME xtensa xtreg dbreakc1 0x02a1 +$_XTNAME xtensa xtreg epc1 0x02b1 +$_XTNAME xtensa xtreg epc2 0x02b2 +$_XTNAME xtensa xtreg epc3 0x02b3 +$_XTNAME xtensa xtreg epc4 0x02b4 +$_XTNAME xtensa xtreg epc5 0x02b5 +$_XTNAME xtensa xtreg depc 0x02c0 +$_XTNAME xtensa xtreg eps2 0x02c2 +$_XTNAME xtensa xtreg eps3 0x02c3 +$_XTNAME xtensa xtreg eps4 0x02c4 +$_XTNAME xtensa xtreg eps5 0x02c5 +$_XTNAME xtensa xtreg excsave1 0x02d1 +$_XTNAME xtensa xtreg excsave2 0x02d2 +$_XTNAME xtensa xtreg excsave3 0x02d3 +$_XTNAME xtensa xtreg excsave4 0x02d4 +$_XTNAME xtensa xtreg excsave5 0x02d5 +$_XTNAME xtensa xtreg cpenable 0x02e0 +$_XTNAME xtensa xtreg interrupt 0x02e2 +$_XTNAME xtensa xtreg intset 0x02e2 +$_XTNAME xtensa xtreg intclear 0x02e3 +$_XTNAME xtensa xtreg intenable 0x02e4 +$_XTNAME xtensa xtreg vecbase 0x02e7 +$_XTNAME xtensa xtreg exccause 0x02e8 +$_XTNAME xtensa xtreg debugcause 0x02e9 +$_XTNAME xtensa xtreg ccount 0x02ea +$_XTNAME xtensa xtreg prid 0x02eb +$_XTNAME xtensa xtreg icount 0x02ec +$_XTNAME xtensa xtreg icountlevel 0x02ed +$_XTNAME xtensa xtreg excvaddr 0x02ee +$_XTNAME xtensa xtreg ccompare0 0x02f0 +$_XTNAME xtensa xtreg ccompare1 0x02f1 +$_XTNAME xtensa xtreg misc0 0x02f4 +$_XTNAME xtensa xtreg misc1 0x02f5 +$_XTNAME xtensa xtreg pwrctl 0x2024 +$_XTNAME xtensa xtreg pwrstat 0x2025 +$_XTNAME xtensa xtreg eristat 0x2026 +$_XTNAME xtensa xtreg cs_itctrl 0x2027 +$_XTNAME xtensa xtreg cs_claimset 0x2028 +$_XTNAME xtensa xtreg cs_claimclr 0x2029 +$_XTNAME xtensa xtreg cs_lockaccess 0x202a +$_XTNAME xtensa xtreg cs_lockstatus 0x202b +$_XTNAME xtensa xtreg cs_authstatus 0x202c +$_XTNAME xtensa xtreg pmg 0x203b +$_XTNAME xtensa xtreg pmpc 0x203c +$_XTNAME xtensa xtreg pm0 0x203d +$_XTNAME xtensa xtreg pm1 0x203e +$_XTNAME xtensa xtreg pmctrl0 0x203f +$_XTNAME xtensa xtreg pmctrl1 0x2040 +$_XTNAME xtensa xtreg pmstat0 0x2041 +$_XTNAME xtensa xtreg pmstat1 0x2042 +$_XTNAME xtensa xtreg ocdid 0x2043 +$_XTNAME xtensa xtreg ocd_dcrclr 0x2044 +$_XTNAME xtensa xtreg ocd_dcrset 0x2045 +$_XTNAME xtensa xtreg ocd_dsr 0x2046 +$_XTNAME xtensa xtreg a0 0x0000 +$_XTNAME xtensa xtreg a1 0x0001 +$_XTNAME xtensa xtreg a2 0x0002 +$_XTNAME xtensa xtreg a3 0x0003 +$_XTNAME xtensa xtreg a4 0x0004 +$_XTNAME xtensa xtreg a5 0x0005 +$_XTNAME xtensa xtreg a6 0x0006 +$_XTNAME xtensa xtreg a7 0x0007 +$_XTNAME xtensa xtreg a8 0x0008 +$_XTNAME xtensa xtreg a9 0x0009 +$_XTNAME xtensa xtreg a10 0x000a +$_XTNAME xtensa xtreg a11 0x000b +$_XTNAME xtensa xtreg a12 0x000c +$_XTNAME xtensa xtreg a13 0x000d +$_XTNAME xtensa xtreg a14 0x000e +$_XTNAME xtensa xtreg a15 0x000f +$_XTNAME xtensa xtreg b0 0x0010 +$_XTNAME xtensa xtreg b1 0x0011 +$_XTNAME xtensa xtreg b2 0x0012 +$_XTNAME xtensa xtreg b3 0x0013 +$_XTNAME xtensa xtreg b4 0x0014 +$_XTNAME xtensa xtreg b5 0x0015 +$_XTNAME xtensa xtreg b6 0x0016 +$_XTNAME xtensa xtreg b7 0x0017 +$_XTNAME xtensa xtreg b8 0x0018 +$_XTNAME xtensa xtreg b9 0x0019 +$_XTNAME xtensa xtreg b10 0x001a +$_XTNAME xtensa xtreg b11 0x001b +$_XTNAME xtensa xtreg b12 0x001c +$_XTNAME xtensa xtreg b13 0x001d +$_XTNAME xtensa xtreg b14 0x001e +$_XTNAME xtensa xtreg b15 0x001f +$_XTNAME xtensa xtreg psintlevel 0x2006 +$_XTNAME xtensa xtreg psum 0x2007 +$_XTNAME xtensa xtreg pswoe 0x2008 +$_XTNAME xtensa xtreg psexcm 0x2009 +$_XTNAME xtensa xtreg pscallinc 0x200a +$_XTNAME xtensa xtreg psowb 0x200b +$_XTNAME xtensa xtreg acc 0x200c +$_XTNAME xtensa xtreg dbnum 0x2011 +$_XTNAME xtensa xtreg ae_overflow 0x2014 +$_XTNAME xtensa xtreg ae_sar 0x2015 +$_XTNAME xtensa xtreg ae_cwrap 0x2016 +$_XTNAME xtensa xtreg ae_bitptr 0x2017 +$_XTNAME xtensa xtreg ae_bitsused 0x2018 +$_XTNAME xtensa xtreg ae_tablesize 0x2019 +$_XTNAME xtensa xtreg ae_first_ts 0x201a +$_XTNAME xtensa xtreg ae_nextoffset 0x201b +$_XTNAME xtensa xtreg ae_searchdone 0x201c +$_XTNAME xtensa xtreg roundmode 0x201d +$_XTNAME xtensa xtreg invalidflag 0x201e +$_XTNAME xtensa xtreg divzeroflag 0x201f +$_XTNAME xtensa xtreg overflowflag 0x2020 +$_XTNAME xtensa xtreg underflowflag 0x2021 +$_XTNAME xtensa xtreg inexactflag 0x2022 diff --git a/tcl/target/xtensa-core-xt8.cfg b/tcl/target/xtensa-core-xt8.cfg new file mode 100644 index 0000000000..523dc74e1f --- /dev/null +++ b/tcl/target/xtensa-core-xt8.cfg @@ -0,0 +1,175 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# OpenOCD configuration file for Xtensa xt8 target + + +# Core instance default definition +if { [info exists XTNAME] } { + set _XTNAME $XTNAME +} else { + set _XTNAME xtensa +} + + +# Core definition and ABI +$_XTNAME xtensa xtdef LX +$_XTNAME xtensa xtopt arnum 32 +$_XTNAME xtensa xtopt windowed 1 + + +# Exception/Interrupt Options +$_XTNAME xtensa xtopt exceptions 1 +$_XTNAME xtensa xtopt hipriints 1 +$_XTNAME xtensa xtopt intlevels 3 +$_XTNAME xtensa xtopt excmlevel 1 + + +# Cache Options +$_XTNAME xtensa xtmem icache 16 1024 1 +$_XTNAME xtensa xtmem dcache 16 1024 1 1 + + +# Memory Options +$_XTNAME xtensa xtmem iram 0x40000000 1048576 +$_XTNAME xtensa xtmem dram 0x3ff00000 262144 +$_XTNAME xtensa xtmem srom 0x50000000 131072 +$_XTNAME xtensa xtmem sram 0x60000000 4194304 + + +# Memory Protection/Translation Options + + +# Debug Options +$_XTNAME xtensa xtopt debuglevel 3 +$_XTNAME xtensa xtopt ibreaknum 2 +$_XTNAME xtensa xtopt dbreaknum 2 + + +# Core Registers +$_XTNAME xtensa xtregs 127 +$_XTNAME xtensa xtreg a0 0x0000 +$_XTNAME xtensa xtreg a1 0x0001 +$_XTNAME xtensa xtreg a2 0x0002 +$_XTNAME xtensa xtreg a3 0x0003 +$_XTNAME xtensa xtreg a4 0x0004 +$_XTNAME xtensa xtreg a5 0x0005 +$_XTNAME xtensa xtreg a6 0x0006 +$_XTNAME xtensa xtreg a7 0x0007 +$_XTNAME xtensa xtreg a8 0x0008 +$_XTNAME xtensa xtreg a9 0x0009 +$_XTNAME xtensa xtreg a10 0x000a +$_XTNAME xtensa xtreg a11 0x000b +$_XTNAME xtensa xtreg a12 0x000c +$_XTNAME xtensa xtreg a13 0x000d +$_XTNAME xtensa xtreg a14 0x000e +$_XTNAME xtensa xtreg a15 0x000f +$_XTNAME xtensa xtreg pc 0x0020 +$_XTNAME xtensa xtreg ar0 0x0100 +$_XTNAME xtensa xtreg ar1 0x0101 +$_XTNAME xtensa xtreg ar2 0x0102 +$_XTNAME xtensa xtreg ar3 0x0103 +$_XTNAME xtensa xtreg ar4 0x0104 +$_XTNAME xtensa xtreg ar5 0x0105 +$_XTNAME xtensa xtreg ar6 0x0106 +$_XTNAME xtensa xtreg ar7 0x0107 +$_XTNAME xtensa xtreg ar8 0x0108 +$_XTNAME xtensa xtreg ar9 0x0109 +$_XTNAME xtensa xtreg ar10 0x010a +$_XTNAME xtensa xtreg ar11 0x010b +$_XTNAME xtensa xtreg ar12 0x010c +$_XTNAME xtensa xtreg ar13 0x010d +$_XTNAME xtensa xtreg ar14 0x010e +$_XTNAME xtensa xtreg ar15 0x010f +$_XTNAME xtensa xtreg ar16 0x0110 +$_XTNAME xtensa xtreg ar17 0x0111 +$_XTNAME xtensa xtreg ar18 0x0112 +$_XTNAME xtensa xtreg ar19 0x0113 +$_XTNAME xtensa xtreg ar20 0x0114 +$_XTNAME xtensa xtreg ar21 0x0115 +$_XTNAME xtensa xtreg ar22 0x0116 +$_XTNAME xtensa xtreg ar23 0x0117 +$_XTNAME xtensa xtreg ar24 0x0118 +$_XTNAME xtensa xtreg ar25 0x0119 +$_XTNAME xtensa xtreg ar26 0x011a +$_XTNAME xtensa xtreg ar27 0x011b +$_XTNAME xtensa xtreg ar28 0x011c +$_XTNAME xtensa xtreg ar29 0x011d +$_XTNAME xtensa xtreg ar30 0x011e +$_XTNAME xtensa xtreg ar31 0x011f +$_XTNAME xtensa xtreg lbeg 0x0200 +$_XTNAME xtensa xtreg lend 0x0201 +$_XTNAME xtensa xtreg lcount 0x0202 +$_XTNAME xtensa xtreg sar 0x0203 +$_XTNAME xtensa xtreg windowbase 0x0248 +$_XTNAME xtensa xtreg windowstart 0x0249 +$_XTNAME xtensa xtreg configid0 0x02b0 +$_XTNAME xtensa xtreg configid1 0x02d0 +$_XTNAME xtensa xtreg ps 0x02e6 +$_XTNAME xtensa xtreg expstate 0x03e6 +$_XTNAME xtensa xtreg mmid 0x0259 +$_XTNAME xtensa xtreg ibreakenable 0x0260 +$_XTNAME xtensa xtreg ddr 0x0268 +$_XTNAME xtensa xtreg ibreaka0 0x0280 +$_XTNAME xtensa xtreg ibreaka1 0x0281 +$_XTNAME xtensa xtreg dbreaka0 0x0290 +$_XTNAME xtensa xtreg dbreaka1 0x0291 +$_XTNAME xtensa xtreg dbreakc0 0x02a0 +$_XTNAME xtensa xtreg dbreakc1 0x02a1 +$_XTNAME xtensa xtreg epc1 0x02b1 +$_XTNAME xtensa xtreg epc2 0x02b2 +$_XTNAME xtensa xtreg epc3 0x02b3 +$_XTNAME xtensa xtreg depc 0x02c0 +$_XTNAME xtensa xtreg eps2 0x02c2 +$_XTNAME xtensa xtreg eps3 0x02c3 +$_XTNAME xtensa xtreg excsave1 0x02d1 +$_XTNAME xtensa xtreg excsave2 0x02d2 +$_XTNAME xtensa xtreg excsave3 0x02d3 +$_XTNAME xtensa xtreg interrupt 0x02e2 +$_XTNAME xtensa xtreg intset 0x02e2 +$_XTNAME xtensa xtreg intclear 0x02e3 +$_XTNAME xtensa xtreg intenable 0x02e4 +$_XTNAME xtensa xtreg exccause 0x02e8 +$_XTNAME xtensa xtreg debugcause 0x02e9 +$_XTNAME xtensa xtreg ccount 0x02ea +$_XTNAME xtensa xtreg icount 0x02ec +$_XTNAME xtensa xtreg icountlevel 0x02ed +$_XTNAME xtensa xtreg excvaddr 0x02ee +$_XTNAME xtensa xtreg ccompare0 0x02f0 +$_XTNAME xtensa xtreg ccompare1 0x02f1 +$_XTNAME xtensa xtreg pwrctl 0x200f +$_XTNAME xtensa xtreg pwrstat 0x2010 +$_XTNAME xtensa xtreg eristat 0x2011 +$_XTNAME xtensa xtreg cs_itctrl 0x2012 +$_XTNAME xtensa xtreg cs_claimset 0x2013 +$_XTNAME xtensa xtreg cs_claimclr 0x2014 +$_XTNAME xtensa xtreg cs_lockaccess 0x2015 +$_XTNAME xtensa xtreg cs_lockstatus 0x2016 +$_XTNAME xtensa xtreg cs_authstatus 0x2017 +$_XTNAME xtensa xtreg fault_info 0x2026 +$_XTNAME xtensa xtreg trax_id 0x2027 +$_XTNAME xtensa xtreg trax_control 0x2028 +$_XTNAME xtensa xtreg trax_status 0x2029 +$_XTNAME xtensa xtreg trax_data 0x202a +$_XTNAME xtensa xtreg trax_address 0x202b +$_XTNAME xtensa xtreg trax_pctrigger 0x202c +$_XTNAME xtensa xtreg trax_pcmatch 0x202d +$_XTNAME xtensa xtreg trax_delay 0x202e +$_XTNAME xtensa xtreg trax_memstart 0x202f +$_XTNAME xtensa xtreg trax_memend 0x2030 +$_XTNAME xtensa xtreg pmg 0x203e +$_XTNAME xtensa xtreg pmpc 0x203f +$_XTNAME xtensa xtreg pm0 0x2040 +$_XTNAME xtensa xtreg pm1 0x2041 +$_XTNAME xtensa xtreg pmctrl0 0x2042 +$_XTNAME xtensa xtreg pmctrl1 0x2043 +$_XTNAME xtensa xtreg pmstat0 0x2044 +$_XTNAME xtensa xtreg pmstat1 0x2045 +$_XTNAME xtensa xtreg ocdid 0x2046 +$_XTNAME xtensa xtreg ocd_dcrclr 0x2047 +$_XTNAME xtensa xtreg ocd_dcrset 0x2048 +$_XTNAME xtensa xtreg ocd_dsr 0x2049 +$_XTNAME xtensa xtreg psintlevel 0x2003 +$_XTNAME xtensa xtreg psum 0x2004 +$_XTNAME xtensa xtreg pswoe 0x2005 +$_XTNAME xtensa xtreg psexcm 0x2006 +$_XTNAME xtensa xtreg pscallinc 0x2007 +$_XTNAME xtensa xtreg psowb 0x2008 diff --git a/tcl/target/xtensa.cfg b/tcl/target/xtensa.cfg new file mode 100644 index 0000000000..561131d842 --- /dev/null +++ b/tcl/target/xtensa.cfg @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Target Support for Xtensa Processors +# + +set xtensa_ids { 0x120034e5 0x120134e5 + 0x209034e5 0x209134e5 0x209234e5 0x209334e5 0x209434e5 0x209534e5 0x209634e5 0x209734e5 + 0x20a034e5 0x20a134e5 0x20a234e5 0x20a334e5 0x20a434e5 0x20a534e5 0x20a634e5 0x20a734e5 0x20a834e5 + 0x20b034e5 0x20b33ac5 0x20b33ac7 } +set expected_xtensa_ids {} +foreach i $xtensa_ids { + lappend expected_xtensa_ids -expected-id $i +} + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xtensa +} + +if { [info exists CPUTAPID] } { + set _CPUTAPARGLIST "-expected-id $CPUTAPID" +} else { + set _CPUTAPARGLIST [join $expected_xtensa_ids] +} + +if { [info exists XTENSA_NUM_CORES] } { + set _XTENSA_NUM_CORES $XTENSA_NUM_CORES +} else { + set _XTENSA_NUM_CORES 1 +} + +set _TARGETNAME $_CHIPNAME +set _CPU0NAME cpu +set _TAPNAME $_CHIPNAME.$_CPU0NAME + +if { [info exists XTENSA_DAP] } { + source [find target/swj-dp.tcl] + # SWD mode ignores the -irlen parameter + eval swj_newdap $_CHIPNAME cpu -irlen 4 $_CPUTAPARGLIST + dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + + set _TARGETNAME $_CHIPNAME.cpu + if { [info exists XTENSA_DAP_BASE] } { + # Specify fixed offset for accessing XDM via APB behind a DAP interface + target create $_TARGETNAME xtensa -dap $_CHIPNAME.dap -dbgbase $XTENSA_DAP_BASE + } else { + target create $_TARGETNAME xtensa -dap $_CHIPNAME.dap + } +} elseif { $_XTENSA_NUM_CORES > 1 } { + # JTAG direct (without DAP) + for {set i 0} {$i < $_XTENSA_NUM_CORES} {incr i} { + set _LCPUNAME $_CPU0NAME$i + set _LTAPNAME $_CHIPNAME.$_LCPUNAME + eval jtag newtap $_CHIPNAME $_LCPUNAME -irlen 5 $_CPUTAPARGLIST + target create $_LTAPNAME xtensa -chain-position $_LTAPNAME -coreid $i + + $_LTAPNAME configure -event reset-assert-post { soft_reset_halt } + } +} else { + # JTAG direct (without DAP) - for legacy xtensa-config-XXX.cfg format + eval jtag newtap $_CHIPNAME $_CPU0NAME -irlen 5 $_CPUTAPARGLIST + target create $_TARGETNAME xtensa -chain-position $_TAPNAME +} + +if { $_XTENSA_NUM_CORES == 1 } { + # DAP and single-core legacy JTAG + $_TARGETNAME configure -event reset-assert-post { soft_reset_halt } +} + +gdb_report_register_access_error enable diff --git a/tcl/target/zynq_7000.cfg b/tcl/target/zynq_7000.cfg index b4b6f9f189..f5b4478ffc 100644 --- a/tcl/target/zynq_7000.cfg +++ b/tcl/target/zynq_7000.cfg @@ -1,16 +1,34 @@ -# +# SPDX-License-Identifier: GPL-2.0-or-later + # Xilinx Zynq-7000 All Programmable SoC # # http://www.xilinx.com/products/silicon-devices/soc/zynq-7000/index.htm +# https://www.xilinx.com/member/forms/download/sim-model-eval-license-xef.html?filename=bsdl_zynq_2.zip # +# 0x03736093 XQ7Z100 XC7Z100I XC7Z100 +# 0x03731093 XQ7Z045 XC7Z045I XC7Z045 +# 0x0372c093 XQ7Z030 XC7Z030I XC7Z030 XA7Z030 +# 0x03727093 XQ7Z020 XC7Z020I XC7Z020 XA7Z020 +# 0x03732093 XC7Z035I XC7Z035 +# 0x0373b093 XC7Z015I XC7Z015 +# 0x03728093 XC7Z014S +# 0x0373c093 XC7Z012S +# 0x03722093 XC7Z010I XC7Z010 XA7Z010 +# 0x03723093 XC7Z007S set _CHIPNAME zynq set _TARGETNAME $_CHIPNAME.cpu -jtag newtap zynq_pl bs -irlen 6 -ircapture 0x1 -irmask 0x03 \ - -expected-id 0x23727093 \ - -expected-id 0x13722093 \ +jtag newtap zynq_pl bs -irlen 6 -ignore-version -ircapture 0x1 -irmask 0x03 \ + -expected-id 0x03723093 \ + -expected-id 0x03722093 \ + -expected-id 0x0373c093 \ + -expected-id 0x03728093 \ + -expected-id 0x0373B093 \ + -expected-id 0x03732093 \ -expected-id 0x03727093 \ + -expected-id 0x0372C093 \ + -expected-id 0x03731093 \ -expected-id 0x03736093 jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x4ba00477 @@ -28,7 +46,8 @@ adapter speed 1000 ${_TARGETNAME}0 configure -event reset-assert-post "cortex_a dbginit" ${_TARGETNAME}1 configure -event reset-assert-post "cortex_a dbginit" -pld device virtex2 zynq_pl.bs 1 +pld create zynq_pl.pld virtex2 -chain-position zynq_pl.bs -no_jstart +virtex2 set_user_codes $zynq_pl.pld 0x02 0x03 0x22 0x23 set XC7_JSHUTDOWN 0x0d set XC7_JPROGRAM 0x0b @@ -36,6 +55,7 @@ set XC7_JSTART 0x0c set XC7_BYPASS 0x3f proc zynqpl_program {tap} { + echo "DEPRECATED! use 'virtex2 program ...' not 'zynqpl_program'" global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS irscan $tap $XC7_JSHUTDOWN irscan $tap $XC7_JPROGRAM diff --git a/tcl/test/selftest.cfg b/tcl/test/selftest.cfg index 0331b482f5..10efb0c6df 100644 --- a/tcl/test/selftest.cfg +++ b/tcl/test/selftest.cfg @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later add_help_text selftest "run selftest using working ram <tmpfile> <address> <size>" diff --git a/tcl/test/syntax1.cfg b/tcl/test/syntax1.cfg index 2e66188959..7735ee98cb 100644 --- a/tcl/test/syntax1.cfg +++ b/tcl/test/syntax1.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + adapter srst delay 200 jtag_ntrst_delay 200 diff --git a/tcl/tools/firmware-recovery.tcl b/tcl/tools/firmware-recovery.tcl index 9d7e0fce84..6a328cd2e3 100644 --- a/tcl/tools/firmware-recovery.tcl +++ b/tcl/tools/firmware-recovery.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + echo "\n\nFirmware recovery helpers" echo "Use -c firmware_help to get help\n" diff --git a/tcl/tools/memtest.tcl b/tcl/tools/memtest.tcl index c7fa591f3c..f70f950d73 100644 --- a/tcl/tools/memtest.tcl +++ b/tcl/tools/memtest.tcl @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # Algorithms by Michael Barr, released into public domain # Ported to OpenOCD by Shane Volpe, additional fixes by Paul Fertser diff --git a/tcl/tools/test_cpu_speed.tcl b/tcl/tools/test_cpu_speed.tcl index cef2bbbd73..f1a3fb30e0 100644 --- a/tcl/tools/test_cpu_speed.tcl +++ b/tcl/tools/test_cpu_speed.tcl @@ -18,7 +18,7 @@ proc cortex_m_test_cpu_speed { address { timeout 200 } { cycles_per_loop 4 } } { halt # Backup registers and memory. - set backup_regs [get_reg -force {pc r0 xPSR}] + set backup_regs [get_reg -force {pc r0 xpsr}] set backup_mem [read_memory $address 16 3] # We place the following code at the given address to measure the diff --git a/testing/test-am335xgpio-deprecated-commands.cfg b/testing/test-am335xgpio-deprecated-commands.cfg new file mode 100644 index 0000000000..09b2040161 --- /dev/null +++ b/testing/test-am335xgpio-deprecated-commands.cfg @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# OpenOCD script to test that the deprecated "am335xgpio *" commands produce the +# expected results. Run this command as: +# +# openocd -f <path>/test-linuxgpiod-deprecated-commands.cfg + +# Raise an error if the "actual" value does not match the "expected" value. Trim +# whitespace (including newlines) from strings before comparing. +proc expected_value {expected actual} { + if {[string trim $expected] ne [string trim $actual]} { + error [puts "ERROR: '${actual}' != '${expected}'"] + } +} + +adapter driver am335xgpio + +am335xgpio jtag_nums 1 2 3 4 +expected_value "adapter gpio tck (output): num 1, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] +expected_value "adapter gpio tms (output): num 2, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] +expected_value "adapter gpio tdi (output): num 3, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] +expected_value "adapter gpio tdo (input): num 4, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] + +am335xgpio tck_num 5 +expected_value "adapter gpio tck (output): num 5, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] + +am335xgpio tms_num 6 +expected_value "adapter gpio tms (output): num 6, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] + +am335xgpio tdi_num 7 +expected_value "adapter gpio tdi (output): num 7, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] + +am335xgpio tdo_num 8 +expected_value "adapter gpio tdo (input): num 8, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] + +am335xgpio swd_nums 9 10 +expected_value "adapter gpio swclk (output): num 9, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] +expected_value "adapter gpio swdio (bidirectional): num 10, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] + +am335xgpio swclk_num 11 +expected_value "adapter gpio swclk (output): num 11, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] + +am335xgpio swdio_num 12 +expected_value "adapter gpio swdio (bidirectional): num 12, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] + +am335xgpio swdio_dir_num 13 +expected_value "adapter gpio swdio_dir (output): num 13, chip 0, active-high, push-pull, pull-none" [eval adapter gpio swdio_dir] + +am335xgpio swdio_dir_output_state low +expected_value "adapter gpio swdio_dir (output): num 13, chip 0, active-low, push-pull, pull-none" [eval adapter gpio swdio_dir] + +am335xgpio swdio_dir_output_state high +expected_value "adapter gpio swdio_dir (output): num 13, chip 0, active-high, push-pull, pull-none" [eval adapter gpio swdio_dir] + +am335xgpio srst_num 14 +expected_value "adapter gpio srst (output): num 14, chip 0, active-low, pull-none, init-state inactive" [eval adapter gpio srst] + +am335xgpio trst_num 15 +expected_value "adapter gpio trst (output): num 15, chip 0, active-low, pull-none, init-state inactive" [eval adapter gpio trst] + +am335xgpio led_num 16 +expected_value "adapter gpio led (output): num 16, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio led] + +am335xgpio led_on_state low +expected_value "adapter gpio led (output): num 16, chip 0, active-low, push-pull, pull-none, init-state inactive" [eval adapter gpio led] + +am335xgpio led_on_state high +expected_value "adapter gpio led (output): num 16, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio led] + +puts "SUCCESS" diff --git a/testing/test-bcm2835gpio-deprecated-commands.cfg b/testing/test-bcm2835gpio-deprecated-commands.cfg new file mode 100644 index 0000000000..b34eb36bb9 --- /dev/null +++ b/testing/test-bcm2835gpio-deprecated-commands.cfg @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# OpenOCD script to test that the deprecated "bcm2835gpio *" and "bcm2835gpio_*" +# commands produce the expected results. Run this command as: +# openocd -f <path>/test-bcm2835gpio-deprecated-commands.cfg + +# Raise an error if the "actual" value does not match the "expected" value. Trim +# whitespace (including newlines) from strings before comparing. +proc expected_value {expected actual} { + if {[string trim $expected] ne [string trim $actual]} { + error [puts "ERROR: '${actual}' != '${expected}'"] + } +} + +set supported_signals {tdo tdi tms tck trst swdio swdio_dir swclk srst} + +adapter speed 100 +adapter driver bcm2835gpio +puts "Driver is '[adapter name]'" +expected_value "bcm2835gpio" [adapter name] +echo [adapter gpio] + +##################################### +# Test the "bcm2835gpio *" commands + +# Change the GPIO chip for all signals. Don't check directly here, do so when +# each signal command is tested. +# bcm2835gpio gpiochip 0 + +bcm2835gpio jtag_nums 1 2 3 4 +expected_value "adapter gpio tck (output): num 1, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] +expected_value "adapter gpio tms (output): num 2, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] +expected_value "adapter gpio tdi (output): num 3, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] +expected_value "adapter gpio tdo (input): num 4, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] + +bcm2835gpio tck_num 5 +expected_value "adapter gpio tck (output): num 5, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] + +bcm2835gpio tms_num 6 +expected_value "adapter gpio tms (output): num 6, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] + +bcm2835gpio tdi_num 7 +expected_value "adapter gpio tdi (output): num 7, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] + +bcm2835gpio tdo_num 8 +expected_value "adapter gpio tdo (input): num 8, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] + +bcm2835gpio swd_nums 9 10 +expected_value "adapter gpio swclk (output): num 9, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] +expected_value "adapter gpio swdio (bidirectional): num 10, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] + +bcm2835gpio swclk_num 11 +expected_value "adapter gpio swclk (output): num 11, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] + +bcm2835gpio swdio_num 12 +expected_value "adapter gpio swdio (bidirectional): num 12, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] + +bcm2835gpio swdio_dir_num 13 +expected_value "adapter gpio swdio_dir (output): num 13, chip 0, active-high, push-pull, pull-none" [eval adapter gpio swdio_dir] + +bcm2835gpio srst_num 14 +expected_value "adapter gpio srst (output): num 14, chip 0, active-low, pull-none, init-state inactive" [eval adapter gpio srst] + +bcm2835gpio trst_num 15 +expected_value "adapter gpio trst (output): num 15, chip 0, active-low, pull-none, init-state inactive" [eval adapter gpio trst] + + +##################################### +# Test the old bcm2835gpio_* commands + +# Reset the GPIO chip for all signals. Don't check directly here, do so when +# each signal command is tested. +foreach sig_name $supported_signals { + eval adapter gpio $sig_name -chip -1 +} + +bcm2835gpio_jtag_nums 17 18 19 20 +expected_value "adapter gpio tck (output): num 17, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] +expected_value "adapter gpio tms (output): num 18, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] +expected_value "adapter gpio tdi (output): num 19, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] +expected_value "adapter gpio tdo (input): num 20, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] + +bcm2835gpio_tck_num 21 +expected_value "adapter gpio tck (output): num 21, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] + +bcm2835gpio_tms_num 22 +expected_value "adapter gpio tms (output): num 22, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] + +bcm2835gpio_tdi_num 23 +expected_value "adapter gpio tdi (output): num 23, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] + +bcm2835gpio_tdo_num 24 +expected_value "adapter gpio tdo (input): num 24, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] + +bcm2835gpio_swd_nums 25 26 +expected_value "adapter gpio swclk (output): num 25, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] +expected_value "adapter gpio swdio (bidirectional): num 26, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] + +bcm2835gpio_swclk_num 27 +expected_value "adapter gpio swclk (output): num 27, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] + +bcm2835gpio_swdio_num 28 +expected_value "adapter gpio swdio (bidirectional): num 28, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] + +puts "SUCCESS" diff --git a/testing/test-linuxgpiod-deprecated-commands.cfg b/testing/test-linuxgpiod-deprecated-commands.cfg new file mode 100644 index 0000000000..3d4f5cb4c4 --- /dev/null +++ b/testing/test-linuxgpiod-deprecated-commands.cfg @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# OpenOCD script to test that the deprecated "linuxgpiod *" and "linuxgpiod_*" +# commands produce the expected results. Run this command as: +# openocd -f <path>/test-linuxgpiod-deprecated-commands.cfg + +# Raise an error if the "actual" value does not match the "expected" value. Trim +# whitespace (including newlines) from strings before comparing. +proc expected_value {expected actual} { + if {[string trim $expected] ne [string trim $actual]} { + error [puts "ERROR: '${actual}' != '${expected}'"] + } +} + +adapter driver linuxgpiod +puts "Driver is '[adapter name]'" +expected_value "linuxgpiod" [adapter name] +echo [adapter gpio] + +##################################### +# Test the "linuxgpiod *" commands + +# Change the GPIO chip for all signals. Don't check directly here, do so when +# each signal command is tested. +linuxgpiod gpiochip 0 + +linuxgpiod jtag_nums 1 2 3 4 +expected_value "adapter gpio tck (output): num 1, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] +expected_value "adapter gpio tms (output): num 2, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] +expected_value "adapter gpio tdi (output): num 3, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] +expected_value "adapter gpio tdo (input): num 4, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] + +linuxgpiod tck_num 5 +expected_value "adapter gpio tck (output): num 5, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] + +linuxgpiod tms_num 6 +expected_value "adapter gpio tms (output): num 6, chip 0, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] + +linuxgpiod tdi_num 7 +expected_value "adapter gpio tdi (output): num 7, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] + +linuxgpiod tdo_num 8 +expected_value "adapter gpio tdo (input): num 8, chip 0, active-high, pull-none, init-state input" [eval adapter gpio tdo] + +linuxgpiod swd_nums 9 10 +expected_value "adapter gpio swclk (output): num 9, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] +expected_value "adapter gpio swdio (bidirectional): num 10, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] + +linuxgpiod swclk_num 11 +expected_value "adapter gpio swclk (output): num 11, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] + +linuxgpiod swdio_num 12 +expected_value "adapter gpio swdio (bidirectional): num 12, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] + +linuxgpiod swdio_dir_num 13 +expected_value "adapter gpio swdio_dir (output): num 13, chip 0, active-high, push-pull, pull-none" [eval adapter gpio swdio_dir] + +linuxgpiod srst_num 14 +expected_value "adapter gpio srst (output): num 14, chip 0, active-low, pull-none, init-state inactive" [eval adapter gpio srst] + +linuxgpiod trst_num 15 +expected_value "adapter gpio trst (output): num 15, chip 0, active-low, pull-none, init-state inactive" [eval adapter gpio trst] + +linuxgpiod led_num 16 +expected_value "adapter gpio led (output): num 16, chip 0, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio led] + +##################################### +# Test the old linuxgpiod_* commands + +# Change the GPIO chip for all signals. Don't check directly here, do so when +# each signal command is tested. +linuxgpiod_gpiochip 1 + +linuxgpiod_jtag_nums 17 18 19 20 +expected_value "adapter gpio tck (output): num 17, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] +expected_value "adapter gpio tms (output): num 18, chip 1, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] +expected_value "adapter gpio tdi (output): num 19, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] +expected_value "adapter gpio tdo (input): num 20, chip 1, active-high, pull-none, init-state input" [eval adapter gpio tdo] + +linuxgpiod_tck_num 21 +expected_value "adapter gpio tck (output): num 21, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tck] + +linuxgpiod_tms_num 22 +expected_value "adapter gpio tms (output): num 22, chip 1, active-high, push-pull, pull-none, init-state active" [eval adapter gpio tms] + +linuxgpiod_tdi_num 23 +expected_value "adapter gpio tdi (output): num 23, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio tdi] + +linuxgpiod_tdo_num 24 +expected_value "adapter gpio tdo (input): num 24, chip 1, active-high, pull-none, init-state input" [eval adapter gpio tdo] + +linuxgpiod_swd_nums 25 26 +expected_value "adapter gpio swclk (output): num 25, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] +expected_value "adapter gpio swdio (bidirectional): num 26, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] + +linuxgpiod_swclk_num 27 +expected_value "adapter gpio swclk (output): num 27, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swclk] + +linuxgpiod_swdio_num 28 +expected_value "adapter gpio swdio (bidirectional): num 28, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio swdio] + +linuxgpiod_led_num 29 +expected_value "adapter gpio led (output): num 29, chip 1, active-high, push-pull, pull-none, init-state inactive" [eval adapter gpio led] + +puts "SUCCESS" diff --git a/tools/checkpatch.sh b/tools/checkpatch.sh index 0a630a2483..7375fc2b6d 100755 --- a/tools/checkpatch.sh +++ b/tools/checkpatch.sh @@ -1,5 +1,5 @@ #!/bin/sh -# +# SPDX-License-Identifier: GPL-2.0-or-later since=${1:-HEAD^} -git format-patch -M --stdout $since | tools/scripts/checkpatch.pl - +tools/scripts/checkpatch.pl --git ${since}.. diff --git a/tools/disassemble_inc.sh b/tools/disassemble_inc.sh new file mode 100755 index 0000000000..d4b5f80dce --- /dev/null +++ b/tools/disassemble_inc.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later + +# Simple script to disassemble a file .inc generated by +# src/helper/bin2char.sh +# Can be useful to check the correctness of the file .inc +# +# By default it decodes ARM thumb little-endian, e.g. cortex-m. +# Set CROSS_COMPILE for other toolchains. +# Set OBJDUMP_FLAGS for different objdump flags. +# +# Usage: +# contrib/loaders/disassemble_inc.sh file.inc + +default_CROSS_COMPILE="arm-none-eabi-" +default_OBJDUMP_FLAGS="-m arm -EL -M force-thumb" + +if [ $# != 1 -o ! -f "$1" ]; then + echo "Usage:" + echo " $0 path/to/file.inc" + echo "" + echo "Set CROSS_COMPILE and/or OBJDUMP_FLAGS to override current default:" + echo " export CROSS_COMPILE=\"${default_CROSS_COMPILE}\"" + echo " export OBJDUMP_FLAGS=\"${default_OBJDUMP_FLAGS}\"" + exit 1 +fi + +if [ -z "${CROSS_COMPILE}" ]; then + CROSS_COMPILE="${default_CROSS_COMPILE}" +fi + +if [ -z "${OBJDUMP_FLAGS}" ]; then + OBJDUMP_FLAGS="${default_OBJDUMP_FLAGS}" +fi + +perl -v > /dev/null 2>&1 +if [ $? != 0 ]; then + echo "Error: 'perl' interpreter not available." + exit 1 +fi + +tmpfile=$(mktemp --suffix=.bin) + +echo "Disassemble $1:" +echo "${CROSS_COMPILE}objdump ${OBJDUMP_FLAGS} -b binary -D ${tmpfile}" + +perl -e 'while (<>){while ($_=~/(0x..)/g){print chr(hex($1));}}' $1 > ${tmpfile} +${CROSS_COMPILE}objdump ${OBJDUMP_FLAGS} -b binary -D ${tmpfile} + +rm ${tmpfile} diff --git a/tools/scripts/camelcase.txt b/tools/scripts/camelcase.txt new file mode 100644 index 0000000000..b787902006 --- /dev/null +++ b/tools/scripts/camelcase.txt @@ -0,0 +1,202 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# The OpenOCD coding-style rules forbids CamelCase names for symbols, +# either functions, variables, macros and enums. +# The script checkpatch detects the CamelCase symbols. +# This file contains the exceptions to the coding-style, mainly due +# to external dependencies and libraries. + +# format types from inttypes.h (only some are already used) +PRId8 +PRId16 +PRId32 +PRId64 +PRIi8 +PRIi16 +PRIi32 +PRIi64 +PRIo8 +PRIo16 +PRIo32 +PRIo64 +PRIu8 +PRIu16 +PRIu32 +PRIu64 +PRIx8 +PRIx16 +PRIx32 +PRIx64 +PRIX8 +PRIX16 +PRIX32 +PRIX64 +SCNd8 +SCNd16 +SCNd32 +SCNd64 +SCNi8 +SCNi16 +SCNi32 +SCNi64 +SCNo8 +SCNo16 +SCNo32 +SCNo64 +SCNu8 +SCNu16 +SCNu32 +SCNu64 +SCNx8 +SCNx16 +SCNx32 +SCNx64 +SCNX8 +SCNX16 +SCNX32 +SCNX64 + +# OpenOCD format types +TARGET_PRIdADDR +TARGET_PRIoADDR +TARGET_PRIuADDR +TARGET_PRIxADDR + +# from libusb.h +bcdDevice +bConfigurationValue +bEndpointAddress +bInterfaceClass +bInterfaceNumber +bInterfaceProtocol +bInterfaceSubClass +bmAttributes +bNumConfigurations +bNumEndpoints +bNumInterfaces +idProduct +idVendor +iInterface +iManufacturer +iProduct +iSerialNumber +wMaxPacketSize + +# from jimtcl/jim.h and jimtcl/jim-eventloop.h +Jim_AppendString +Jim_AppendStrings +Jim_Cmd +Jim_CmdPrivData +Jim_CmdProc +Jim_CompareStringImmediate +Jim_ConcatObj +Jim_CreateCommand +Jim_CreateInterp +Jim_DecrRefCount +Jim_DelCmdProc +Jim_DeleteAssocData +Jim_DeleteCommand +Jim_DictAddElement +Jim_DictPairs +Jim_DuplicateObj +Jim_Eval +Jim_EvalExpression +Jim_EvalObj +Jim_EvalObjPrefix +Jim_EvalSource +Jim_Eval_Named +Jim_FreeInterp +Jim_FreeObj +Jim_GetAssocData +Jim_GetCommand +Jim_GetDouble +Jim_GetEnum +Jim_GetExitCode +Jim_GetGlobalVariableStr +Jim_GetIntRepPtr +Jim_GetLong +Jim_GetResult +Jim_GetString +Jim_GetVariable +Jim_GetWide +Jim_IncrRefCount +Jim_InitStaticExtensions +Jim_Interp +Jim_ListAppendElement +Jim_ListGetIndex +Jim_ListLength +Jim_MakeErrorMessage +Jim_NewDictObj +Jim_NewEmptyStringObj +Jim_NewIntObj +Jim_NewListObj +Jim_NewStringObj +Jim_NewWideObj +Jim_Obj +Jim_ProcessEvents +Jim_RegisterCoreCommands +Jim_SetAssocData +Jim_SetEmptyResult +Jim_SetResult +Jim_SetResultBool +Jim_SetResultFormatted +Jim_SetResultInt +Jim_SetResultString +Jim_SetVariable +Jim_String +Jim_WrongNumArgs +cmdProc +currentScriptObj +delProc +emptyObj +privData +returnCode +typePtr + +# from elf.h +Elf32_Addr +Elf32_Ehdr +Elf32_Half +Elf32_Off +Elf32_Phdr +Elf32_Size +Elf32_Word +Elf64_Addr +Elf64_Ehdr +Elf64_Half +Elf64_Off +Elf64_Phdr +Elf64_Word +Elf64_Xword + +# for BSD's +__FreeBSD__ +__FreeBSD_kernel__ + +# for Windows +CreateFile +CloseHandle +FormatMessage +GetModuleFileName +GetSystemTimeAsFileTime +GetTickCount +GetVersionEx +HighPart +LowPart +MsgWaitForMultipleObjects +PeekMessage +PeekNamedPipe +QuadPart +SetConsoleCtrlHandler +Sleep +WaitForSingleObject +WSACleanup +WSAGetLastError +WSAStartup +dwHighDateTime +dwLowDateTime +dwPlatformId +dwOSVersionInfoSize + +# OpenOCD exceptions that should be removed +KiB diff --git a/tools/scripts/checkpatch.pl b/tools/scripts/checkpatch.pl index f83ac77ff2..9dda61cde0 100755 --- a/tools/scripts/checkpatch.pl +++ b/tools/scripts/checkpatch.pl @@ -1,38 +1,96 @@ -#!/usr/bin/perl -w +#!/usr/bin/env perl +# SPDX-License-Identifier: GPL-2.0 +# # (c) 2001, Dave Jones. (the file handling bit) # (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit) # (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite) # (c) 2008-2010 Andy Whitcroft <apw@canonical.com> -# Licensed under the terms of the GNU GPL License version 2 +# (c) 2010-2018 Joe Perches <joe@perches.com> use strict; +use warnings; +use POSIX; +use File::Basename; +use Cwd 'abs_path'; +use Term::ANSIColor qw(:constants); +use Encode qw(decode encode); my $P = $0; -$P =~ s@.*/@@g; +my $D = dirname(abs_path($P)); my $V = '0.32'; use Getopt::Long qw(:config no_auto_abbrev); +# ATTENTION: easily track modification to this script for OpenOCD. +# When possible, don't modify the existing code, don't change its indentation, +# but remove it enclosing it within: +# +# if (!$OpenOCD) { +# original_code; +# } # !$OpenOCD +# +# Mark every addition within comments +# # OpenOCD specific: Begin[: additional comment] +# # OpenOCD specific: End +my $OpenOCD = 1; + my $quiet = 0; +my $verbose = 0; +my %verbose_messages = (); +my %verbose_emitted = (); my $tree = 1; my $chk_signoff = 1; my $chk_patch = 1; my $tst_only; my $emacs = 0; my $terse = 0; +my $showfile = 0; my $file = 0; +my $git = 0; +my %git_commits = (); my $check = 0; +my $check_orig = 0; my $summary = 1; my $mailback = 0; my $summary_file = 0; my $show_types = 0; +my $list_types = 0; +my $fix = 0; +my $fix_inplace = 0; my $root; +my $gitroot = $ENV{'GIT_DIR'}; +$gitroot = ".git" if !defined($gitroot); my %debug; +my %camelcase = (); +my %use_type = (); +my @use = (); my %ignore_type = (); my @ignore = (); my $help = 0; my $configuration_file = ".checkpatch.conf"; +my $max_line_length = 100; +my $ignore_perl_version = 0; +my $minimum_perl_version = 5.10.0; +my $min_conf_desc_length = 4; +my $spelling_file = "$D/spelling.txt"; +my $codespell = 0; +my $codespellfile = "/usr/share/codespell/dictionary.txt"; +my $user_codespellfile = ""; +my $conststructsfile = "$D/const_structs.checkpatch"; +if (!$OpenOCD) { +my $docsfile = "$D/../Documentation/dev-tools/checkpatch.rst"; +} # !$OpenOCD +# OpenOCD Specific: Begin +my $docsfile = "$D/../../doc/checkpatch.rst"; +# OpenOCD Specific: End +my $typedefsfile; +my $color = "auto"; +my $allow_c99_comments = 1; # Can be overridden by --ignore C99_COMMENT_TOLERANCE +# git output parsing needs US English output, so first set backtick child process LANGUAGE +my $git_command ='export LANGUAGE=en_US.UTF-8; git'; +my $tabsize = 8; +my ${CONFIG_} = "CONFIG_"; sub help { my ($exitcode) = @_; @@ -43,16 +101,35 @@ sub help { Options: -q, --quiet quiet - --no-tree run without a openocd tree + -v, --verbose verbose mode + --no-tree run without an OpenOCD tree --no-signoff do not check for 'Signed-off-by' line --patch treat FILE as patchfile (default) --emacs emacs compile window format --terse one line per report + --showfile emit diffed file position, not input file position + -g, --git treat FILE as a single commit or git revision range + single git commit with: + <rev> + <rev>^ + <rev>~n + multiple git commits with: + <rev1>..<rev2> + <rev1>...<rev2> + <rev>-<count> + git merges are ignored -f, --file treat FILE as regular source file --subjective, --strict enable more subjective tests + --list-types list the possible message types + --types TYPE(,TYPE2...) show only these comma separated message types --ignore TYPE(,TYPE2...) ignore various comma separated message types - --show-types show the message "types" in the output - --root=PATH PATH to the openocd tree root + --show-types show the specific message type in the output + --max-line-length=n set the maximum line length, (default $max_line_length) + if exceeded, warn on patches + requires --strict for use with --file + --min-conf-desc-length=n set the min description length, if shorter, warn + --tab-size=n set the number of spaces for tab (default $tabsize) + --root=PATH PATH to the OpenOCD tree root --no-summary suppress the per-file summary --mailback only produce a report in case of warnings/errors --summary-file include the filename in summary @@ -61,6 +138,24 @@ sub help { is all off) --test-only=WORD report only warnings/errors containing WORD literally + --fix EXPERIMENTAL - may create horrible results + If correctable single-line errors exist, create + "<inputfile>.EXPERIMENTAL-checkpatch-fixes" + with potential errors corrected to the preferred + checkpatch style + --fix-inplace EXPERIMENTAL - may create horrible results + Is the same as --fix, but overwrites the input + file. It's your fault if there's no backup or git + --ignore-perl-version override checking of perl version. expect + runtime errors. + --codespell Use the codespell dictionary for spelling/typos + (default:$codespellfile) + --codespellfile Use this codespell dictionary + --typedefsfile Read additional types from this file + --color[=WHEN] Use colors 'always', 'never', or only when output + is a terminal ('auto'). Default is 'auto'. + --kconfig-prefix=WORD use WORD as a prefix for Kconfig symbols (default + ${CONFIG_}) -h, --help, --version display this help and exit When FILE is - read standard input. @@ -69,6 +164,74 @@ sub help { exit($exitcode); } +sub uniq { + my %seen; + return grep { !$seen{$_}++ } @_; +} + +sub list_types { + my ($exitcode) = @_; + + my $count = 0; + + local $/ = undef; + + open(my $script, '<', abs_path($P)) or + die "$P: Can't read '$P' $!\n"; + + my $text = <$script>; + close($script); + + my %types = (); + # Also catch when type or level is passed through a variable + while ($text =~ /(?:(\bCHK|\bWARN|\bERROR|&\{\$msg_level})\s*\(|\$msg_type\s*=)\s*"([^"]+)"/g) { + if (defined($1)) { + if (exists($types{$2})) { + $types{$2} .= ",$1" if ($types{$2} ne $1); + } else { + $types{$2} = $1; + } + } else { + $types{$2} = "UNDETERMINED"; + } + } + + print("#\tMessage type\n\n"); + if ($color) { + print(" ( Color coding: "); + print(RED . "ERROR" . RESET); + print(" | "); + print(YELLOW . "WARNING" . RESET); + print(" | "); + print(GREEN . "CHECK" . RESET); + print(" | "); + print("Multiple levels / Undetermined"); + print(" )\n\n"); + } + + foreach my $type (sort keys %types) { + my $orig_type = $type; + if ($color) { + my $level = $types{$type}; + if ($level eq "ERROR") { + $type = RED . $type . RESET; + } elsif ($level eq "WARN") { + $type = YELLOW . $type . RESET; + } elsif ($level eq "CHK") { + $type = GREEN . $type . RESET; + } + } + print(++$count . "\t" . $type . "\n"); + if ($verbose && exists($verbose_messages{$orig_type})) { + my $message = $verbose_messages{$orig_type}; + $message =~ s/\n/\n\t/g; + print("\t" . $message . "\n\n"); + } + } + + exit($exitcode); +} + my $conf = which_conf($configuration_file); if (-f $conf) { my @conf_args; @@ -95,51 +258,189 @@ sub help { unshift(@ARGV, @conf_args) if @conf_args; } +sub load_docs { + open(my $docs, '<', "$docsfile") + or warn "$P: Can't read the documentation file $docsfile $!\n"; + + my $type = ''; + my $desc = ''; + my $in_desc = 0; + + while (<$docs>) { + chomp; + my $line = $_; + $line =~ s/\s+$//; + + if ($line =~ /^\s*\*\*(.+)\*\*$/) { + if ($desc ne '') { + $verbose_messages{$type} = trim($desc); + } + $type = $1; + $desc = ''; + $in_desc = 1; + } elsif ($in_desc) { + if ($line =~ /^(?:\s{4,}|$)/) { + $line =~ s/^\s{4}//; + $desc .= $line; + $desc .= "\n"; + } else { + $verbose_messages{$type} = trim($desc); + $type = ''; + $desc = ''; + $in_desc = 0; + } + } + } + + if ($desc ne '') { + $verbose_messages{$type} = trim($desc); + } + close($docs); +} + +# Perl's Getopt::Long allows options to take optional arguments after a space. +# Prevent --color by itself from consuming other arguments +foreach (@ARGV) { + if ($_ eq "--color" || $_ eq "-color") { + $_ = "--color=$color"; + } +} + GetOptions( 'q|quiet+' => \$quiet, + 'v|verbose!' => \$verbose, 'tree!' => \$tree, 'signoff!' => \$chk_signoff, 'patch!' => \$chk_patch, 'emacs!' => \$emacs, 'terse!' => \$terse, + 'showfile!' => \$showfile, 'f|file!' => \$file, + 'g|git!' => \$git, 'subjective!' => \$check, 'strict!' => \$check, 'ignore=s' => \@ignore, + 'types=s' => \@use, 'show-types!' => \$show_types, + 'list-types!' => \$list_types, + 'max-line-length=i' => \$max_line_length, + 'min-conf-desc-length=i' => \$min_conf_desc_length, + 'tab-size=i' => \$tabsize, 'root=s' => \$root, 'summary!' => \$summary, 'mailback!' => \$mailback, 'summary-file!' => \$summary_file, - + 'fix!' => \$fix, + 'fix-inplace!' => \$fix_inplace, + 'ignore-perl-version!' => \$ignore_perl_version, 'debug=s' => \%debug, 'test-only=s' => \$tst_only, + 'codespell!' => \$codespell, + 'codespellfile=s' => \$user_codespellfile, + 'typedefsfile=s' => \$typedefsfile, + 'color=s' => \$color, + 'no-color' => \$color, #keep old behaviors of -nocolor + 'nocolor' => \$color, #keep old behaviors of -nocolor + 'kconfig-prefix=s' => \${CONFIG_}, 'h|help' => \$help, 'version' => \$help -) or help(1); +) or $help = 2; + +if ($user_codespellfile) { + # Use the user provided codespell file unconditionally + $codespellfile = $user_codespellfile; +} elsif (!(-f $codespellfile)) { + # If /usr/share/codespell/dictionary.txt is not present, try to find it + # under codespell's install directory: <codespell_root>/data/dictionary.txt + if (($codespell || $help) && which("python3") ne "") { + my $python_codespell_dict = << "EOF"; + +import os.path as op +import codespell_lib +codespell_dir = op.dirname(codespell_lib.__file__) +codespell_file = op.join(codespell_dir, 'data', 'dictionary.txt') +print(codespell_file, end='') +EOF + + my $codespell_dict = `python3 -c "$python_codespell_dict" 2> /dev/null`; + $codespellfile = $codespell_dict if (-f $codespell_dict); + } +} + +# $help is 1 if either -h, --help or --version is passed as option - exitcode: 0 +# $help is 2 if invalid option is passed - exitcode: 1 +help($help - 1) if ($help); + +die "$P: --git cannot be used with --file or --fix\n" if ($git && ($file || $fix)); +die "$P: --verbose cannot be used with --terse\n" if ($verbose && $terse); + +if ($color =~ /^[01]$/) { + $color = !$color; +} elsif ($color =~ /^always$/i) { + $color = 1; +} elsif ($color =~ /^never$/i) { + $color = 0; +} elsif ($color =~ /^auto$/i) { + $color = (-t STDOUT); +} else { + die "$P: Invalid color mode: $color\n"; +} + +load_docs() if ($verbose); +list_types(0) if ($list_types); -help(0) if ($help); +$fix = 1 if ($fix_inplace); +$check_orig = $check; my $exit = 0; +my $perl_version_ok = 1; +if ($^V && $^V lt $minimum_perl_version) { + $perl_version_ok = 0; + printf "$P: requires at least perl version %vd\n", $minimum_perl_version; + exit(1) if (!$ignore_perl_version); +} + +#if no filenames are given, push '-' to read patch from stdin if ($#ARGV < 0) { - print "$P: no input files\n"; - exit(1); + push(@ARGV, '-'); } -@ignore = split(/,/, join(',',@ignore)); -foreach my $word (@ignore) { - $word =~ s/\s*\n?$//g; - $word =~ s/^\s*//g; - $word =~ s/\s+/ /g; - $word =~ tr/[a-z]/[A-Z]/; +# skip TAB size 1 to avoid additional checks on $tabsize - 1 +die "$P: Invalid TAB size: $tabsize\n" if ($tabsize < 2); + +sub hash_save_array_words { + my ($hashRef, $arrayRef) = @_; + + my @array = split(/,/, join(',', @$arrayRef)); + foreach my $word (@array) { + $word =~ s/\s*\n?$//g; + $word =~ s/^\s*//g; + $word =~ s/\s+/ /g; + $word =~ tr/[a-z]/[A-Z]/; - next if ($word =~ m/^\s*#/); - next if ($word =~ m/^\s*$/); + next if ($word =~ m/^\s*#/); + next if ($word =~ m/^\s*$/); - $ignore_type{$word}++; + $hashRef->{$word}++; + } +} + +sub hash_show_words { + my ($hashRef, $prefix) = @_; + + if (keys %$hashRef) { + print "\nNOTE: $prefix message types:"; + foreach my $word (sort keys %$hashRef) { + print " $word"; + } + print "\n"; + } } +hash_save_array_words(\%ignore_type, \@ignore); +hash_save_array_words(\%use_type, \@use); + my $dbg_values = 0; my $dbg_possible = 0; my $dbg_type = 0; @@ -165,14 +466,16 @@ sub help { } else { if (top_of_kernel_tree('.')) { $root = '.'; + # OpenOCD specific: Begin: replace s"/scripts/"/tools/scripts/" } elsif ($0 =~ m@(.*)/tools/scripts/[^/]*$@ && top_of_kernel_tree($1)) { $root = $1; } + # OpenOCD specific: End } if (!defined $root) { - print "Must be run from the top-level dir. of a openocd tree\n"; + print "Must be run from the top-level dir. of an OpenOCD tree\n"; exit(2); } } @@ -190,20 +493,28 @@ sub help { __force| __iomem| __must_check| - __init_refok| __kprobes| __ref| - __rcu + __refconst| + __refdata| + __rcu| + __private }x; +our $InitAttributePrefix = qr{__(?:mem|cpu|dev|net_|)}; +our $InitAttributeData = qr{$InitAttributePrefix(?:initdata\b)}; +our $InitAttributeConst = qr{$InitAttributePrefix(?:initconst\b)}; +our $InitAttributeInit = qr{$InitAttributePrefix(?:init\b)}; +our $InitAttribute = qr{$InitAttributeData|$InitAttributeConst|$InitAttributeInit}; # Notes to $Attribute: # We need \b after 'init' otherwise 'initconst' will cause a false positive in a check our $Attribute = qr{ const| + volatile| __percpu| __nocast| __safe| - __bitwise__| + __bitwise| __packed__| __packed2__| __naked| @@ -212,37 +523,57 @@ sub help { __noreturn| __used| __cold| + __pure| __noclone| __deprecated| __read_mostly| + __ro_after_init| __kprobes| - __(?:mem|cpu|dev|)(?:initdata|initconst|init\b)| + $InitAttribute| ____cacheline_aligned| ____cacheline_aligned_in_smp| ____cacheline_internodealigned_in_smp| - __weak + __weak| + __alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) }x; our $Modifier; -our $Inline = qr{inline|__always_inline|noinline}; +our $Inline = qr{inline|__always_inline|noinline|__inline|__inline__}; our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]}; our $Lval = qr{$Ident(?:$Member)*}; -our $Constant = qr{(?:[0-9]+|0x[0-9a-fA-F]+)[UL]*}; -our $Assignment = qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)}; -our $Compare = qr{<=|>=|==|!=|<|>}; +our $Int_type = qr{(?i)llu|ull|ll|lu|ul|l|u}; +our $Binary = qr{(?i)0b[01]+$Int_type?}; +our $Hex = qr{(?i)0x[0-9a-f]+$Int_type?}; +our $Int = qr{[0-9]+$Int_type?}; +our $Octal = qr{0[0-7]+$Int_type?}; +our $String = qr{(?:\b[Lu])?"[X\t]*"}; +our $Float_hex = qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?}; +our $Float_dec = qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?}; +our $Float_int = qr{(?i)[0-9]+e-?[0-9]+[fl]?}; +our $Float = qr{$Float_hex|$Float_dec|$Float_int}; +our $Constant = qr{$Float|$Binary|$Octal|$Hex|$Int}; +our $Assignment = qr{\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=}; +our $Compare = qr{<=|>=|==|!=|<|(?<!-)>}; +our $Arithmetic = qr{\+|-|\*|\/|%}; our $Operators = qr{ <=|>=|==|!=| =>|->|<<|>>|<|>|!|~| - &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|% + &&|\|\||,|\^|\+\+|--|&|\||$Arithmetic }x; +our $c90_Keywords = qr{do|for|while|if|else|return|goto|continue|switch|default|case|break}x; + +our $BasicType; our $NonptrType; +our $NonptrTypeMisordered; +our $NonptrTypeWithAttr; our $Type; +our $TypeMisordered; our $Declare; +our $DeclareMisordered; -our $UTF8 = qr { - [\x09\x0A\x0D\x20-\x7E] # ASCII - | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte +our $NON_ASCII_UTF8 = qr{ + [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates @@ -251,40 +582,179 @@ sub help { | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 }x; -our $typeTypedefs = qr{(?x: +our $UTF8 = qr{ + [\x09\x0A\x0D\x20-\x7E] # ASCII + | $NON_ASCII_UTF8 +}x; + +our $typeC99Typedefs = qr{(?:__)?(?:[us]_?)?int_?(?:8|16|32|64)_t}; +our $typeOtherOSTypedefs = qr{(?x: + u_(?:char|short|int|long) | # bsd + u(?:nchar|short|int|long) # sysv +)}; +our $typeKernelTypedefs = qr{(?x: (?:__)?(?:u|s|be|le)(?:8|16|32|64)| atomic_t )}; +our $typeTypedefs = qr{(?x: + $typeC99Typedefs\b| + $typeOtherOSTypedefs\b| + $typeKernelTypedefs\b +)}; +our $zero_initializer = qr{(?:(?:0[xX])?0+$Int_type?|NULL|false)\b}; + +if (!$OpenOCD) { our $logFunctions = qr{(?x: - printk(?:_ratelimited|_once|)| - [a-z0-9]+_(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)| + printk(?:_ratelimited|_once|_deferred_once|_deferred|)| + (?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)| + TP_printk| WARN(?:_RATELIMIT|_ONCE|)| panic| MODULE_[A-Z_]+| - LOG_(?:DEBUG|INFO|WARNING|ERROR|USER|USER_N|OUTPUT)+ + seq_vprintf|seq_printf|seq_puts +)}; +} # !$OpenOCD +# OpenOCD specific: Begin: list log functions +our $logFunctions = qr{(?x: + LOG_(?:TARGET_|)(?:DEBUG_IO|DEBUG|INFO|WARNING|ERROR|USER|USER_N|OUTPUT) +)}; +# OpenOCD specific: End + +our $allocFunctions = qr{(?x: + (?:(?:devm_)? + (?:kv|k|v)[czm]alloc(?:_array)?(?:_node)? | + kstrdup(?:_const)? | + kmemdup(?:_nul)?) | + (?:\w+)?alloc_skb(?:_ip_align)? | + # dev_alloc_skb/netdev_alloc_skb, et al + dma_alloc_coherent )}; our $signature_tags = qr{(?xi: Signed-off-by:| + Co-developed-by:| Acked-by:| Tested-by:| Reviewed-by:| Reported-by:| + Suggested-by:| To:| Cc: )}; +our $tracing_logging_tags = qr{(?xi: + [=-]*> | + <[=-]* | + \[ | + \] | + start | + called | + entered | + entry | + enter | + in | + inside | + here | + begin | + exit | + end | + done | + leave | + completed | + out | + return | + [\.\!:\s]* +)}; + +sub edit_distance_min { + my (@arr) = @_; + my $len = scalar @arr; + if ((scalar @arr) < 1) { + # if underflow, return + return; + } + my $min = $arr[0]; + for my $i (0 .. ($len-1)) { + if ($arr[$i] < $min) { + $min = $arr[$i]; + } + } + return $min; +} + +sub get_edit_distance { + my ($str1, $str2) = @_; + $str1 = lc($str1); + $str2 = lc($str2); + $str1 =~ s/-//g; + $str2 =~ s/-//g; + my $len1 = length($str1); + my $len2 = length($str2); + # two dimensional array storing minimum edit distance + my @distance; + for my $i (0 .. $len1) { + for my $j (0 .. $len2) { + if ($i == 0) { + $distance[$i][$j] = $j; + } elsif ($j == 0) { + $distance[$i][$j] = $i; + } elsif (substr($str1, $i-1, 1) eq substr($str2, $j-1, 1)) { + $distance[$i][$j] = $distance[$i - 1][$j - 1]; + } else { + my $dist1 = $distance[$i][$j - 1]; #insert distance + my $dist2 = $distance[$i - 1][$j]; # remove + my $dist3 = $distance[$i - 1][$j - 1]; #replace + $distance[$i][$j] = 1 + edit_distance_min($dist1, $dist2, $dist3); + } + } + } + return $distance[$len1][$len2]; +} + +sub find_standard_signature { + my ($sign_off) = @_; + my @standard_signature_tags = ( + 'Signed-off-by:', 'Co-developed-by:', 'Acked-by:', 'Tested-by:', + 'Reviewed-by:', 'Reported-by:', 'Suggested-by:' + ); + foreach my $signature (@standard_signature_tags) { + return $signature if (get_edit_distance($sign_off, $signature) <= 2); + } + + return ""; +} + +our @typeListMisordered = ( + qr{char\s+(?:un)?signed}, + qr{int\s+(?:(?:un)?signed\s+)?short\s}, + qr{int\s+short(?:\s+(?:un)?signed)}, + qr{short\s+int(?:\s+(?:un)?signed)}, + qr{(?:un)?signed\s+int\s+short}, + qr{short\s+(?:un)?signed}, + qr{long\s+int\s+(?:un)?signed}, + qr{int\s+long\s+(?:un)?signed}, + qr{long\s+(?:un)?signed\s+int}, + qr{int\s+(?:un)?signed\s+long}, + qr{int\s+(?:un)?signed}, + qr{int\s+long\s+long\s+(?:un)?signed}, + qr{long\s+long\s+int\s+(?:un)?signed}, + qr{long\s+long\s+(?:un)?signed\s+int}, + qr{long\s+long\s+(?:un)?signed}, + qr{long\s+(?:un)?signed}, +); + our @typeList = ( qr{void}, - qr{(?:unsigned\s+)?char}, - qr{(?:unsigned\s+)?short}, - qr{(?:unsigned\s+)?int}, - qr{(?:unsigned\s+)?long}, - qr{(?:unsigned\s+)?long\s+int}, - qr{(?:unsigned\s+)?long\s+long}, - qr{(?:unsigned\s+)?long\s+long\s+int}, - qr{unsigned}, + qr{(?:(?:un)?signed\s+)?char}, + qr{(?:(?:un)?signed\s+)?short\s+int}, + qr{(?:(?:un)?signed\s+)?short}, + qr{(?:(?:un)?signed\s+)?int}, + qr{(?:(?:un)?signed\s+)?long\s+int}, + qr{(?:(?:un)?signed\s+)?long\s+long\s+int}, + qr{(?:(?:un)?signed\s+)?long\s+long}, + qr{(?:(?:un)?signed\s+)?long}, + qr{(?:un)?signed}, qr{float}, qr{double}, qr{bool}, @@ -294,82 +764,578 @@ sub help { qr{${Ident}_t}, qr{${Ident}_handler}, qr{${Ident}_handler_fn}, + @typeListMisordered, +); + +our $C90_int_types = qr{(?x: + long\s+long\s+int\s+(?:un)?signed| + long\s+long\s+(?:un)?signed\s+int| + long\s+long\s+(?:un)?signed| + (?:(?:un)?signed\s+)?long\s+long\s+int| + (?:(?:un)?signed\s+)?long\s+long| + int\s+long\s+long\s+(?:un)?signed| + int\s+(?:(?:un)?signed\s+)?long\s+long| + + long\s+int\s+(?:un)?signed| + long\s+(?:un)?signed\s+int| + long\s+(?:un)?signed| + (?:(?:un)?signed\s+)?long\s+int| + (?:(?:un)?signed\s+)?long| + int\s+long\s+(?:un)?signed| + int\s+(?:(?:un)?signed\s+)?long| + + int\s+(?:un)?signed| + (?:(?:un)?signed\s+)?int +)}; + +our @typeListFile = (); +our @typeListWithAttr = ( + @typeList, + qr{struct\s+$InitAttribute\s+$Ident}, + qr{union\s+$InitAttribute\s+$Ident}, ); + our @modifierList = ( qr{fastcall}, ); +our @modifierListFile = (); + +our @mode_permission_funcs = ( + ["module_param", 3], + ["module_param_(?:array|named|string)", 4], + ["module_param_array_named", 5], + ["debugfs_create_(?:file|u8|u16|u32|u64|x8|x16|x32|x64|size_t|atomic_t|bool|blob|regset32|u32_array)", 2], + ["proc_create(?:_data|)", 2], + ["(?:CLASS|DEVICE|SENSOR|SENSOR_DEVICE|IIO_DEVICE)_ATTR", 2], + ["IIO_DEV_ATTR_[A-Z_]+", 1], + ["SENSOR_(?:DEVICE_|)ATTR_2", 2], + ["SENSOR_TEMPLATE(?:_2|)", 3], + ["__ATTR", 2], +); + +my $word_pattern = '\b[A-Z]?[a-z]{2,}\b'; + +#Create a search pattern for all these functions to speed up a loop below +our $mode_perms_search = ""; +foreach my $entry (@mode_permission_funcs) { + $mode_perms_search .= '|' if ($mode_perms_search ne ""); + $mode_perms_search .= $entry->[0]; +} +$mode_perms_search = "(?:${mode_perms_search})"; + +our %deprecated_apis = ( + "synchronize_rcu_bh" => "synchronize_rcu", + "synchronize_rcu_bh_expedited" => "synchronize_rcu_expedited", + "call_rcu_bh" => "call_rcu", + "rcu_barrier_bh" => "rcu_barrier", + "synchronize_sched" => "synchronize_rcu", + "synchronize_sched_expedited" => "synchronize_rcu_expedited", + "call_rcu_sched" => "call_rcu", + "rcu_barrier_sched" => "rcu_barrier", + "get_state_synchronize_sched" => "get_state_synchronize_rcu", + "cond_synchronize_sched" => "cond_synchronize_rcu", +); + +#Create a search pattern for all these strings to speed up a loop below +our $deprecated_apis_search = ""; +foreach my $entry (keys %deprecated_apis) { + $deprecated_apis_search .= '|' if ($deprecated_apis_search ne ""); + $deprecated_apis_search .= $entry; +} +$deprecated_apis_search = "(?:${deprecated_apis_search})"; + +our $mode_perms_world_writable = qr{ + S_IWUGO | + S_IWOTH | + S_IRWXUGO | + S_IALLUGO | + 0[0-7][0-7][2367] +}x; + +our %mode_permission_string_types = ( + "S_IRWXU" => 0700, + "S_IRUSR" => 0400, + "S_IWUSR" => 0200, + "S_IXUSR" => 0100, + "S_IRWXG" => 0070, + "S_IRGRP" => 0040, + "S_IWGRP" => 0020, + "S_IXGRP" => 0010, + "S_IRWXO" => 0007, + "S_IROTH" => 0004, + "S_IWOTH" => 0002, + "S_IXOTH" => 0001, + "S_IRWXUGO" => 0777, + "S_IRUGO" => 0444, + "S_IWUGO" => 0222, + "S_IXUGO" => 0111, +); + +#Create a search pattern for all these strings to speed up a loop below +our $mode_perms_string_search = ""; +foreach my $entry (keys %mode_permission_string_types) { + $mode_perms_string_search .= '|' if ($mode_perms_string_search ne ""); + $mode_perms_string_search .= $entry; +} +our $single_mode_perms_string_search = "(?:${mode_perms_string_search})"; +our $multi_mode_perms_string_search = qr{ + ${single_mode_perms_string_search} + (?:\s*\|\s*${single_mode_perms_string_search})* +}x; + +sub perms_to_octal { + my ($string) = @_; + + return trim($string) if ($string =~ /^\s*0[0-7]{3,3}\s*$/); + + my $val = ""; + my $oval = ""; + my $to = 0; + my $curpos = 0; + my $lastpos = 0; + while ($string =~ /\b(($single_mode_perms_string_search)\b(?:\s*\|\s*)?\s*)/g) { + $curpos = pos($string); + my $match = $2; + my $omatch = $1; + last if ($lastpos > 0 && ($curpos - length($omatch) != $lastpos)); + $lastpos = $curpos; + $to |= $mode_permission_string_types{$match}; + $val .= '\s*\|\s*' if ($val ne ""); + $val .= $match; + $oval .= $omatch; + } + $oval =~ s/^\s*\|\s*//; + $oval =~ s/\s*\|\s*$//; + return sprintf("%04o", $to); +} our $allowed_asm_includes = qr{(?x: irq| - memory + memory| + time| + reboot )}; # memory.h: ARM has a custom one +# Load common spelling mistakes and build regular expression list. +my $misspellings; +my %spelling_fix; + +if (open(my $spelling, '<', $spelling_file)) { + while (<$spelling>) { + my $line = $_; + + $line =~ s/\s*\n?$//g; + $line =~ s/^\s*//g; + + next if ($line =~ m/^\s*#/); + next if ($line =~ m/^\s*$/); + + my ($suspect, $fix) = split(/\|\|/, $line); + + $spelling_fix{$suspect} = $fix; + } + close($spelling); +} else { + warn "No typos will be found - file '$spelling_file': $!\n"; +} + +if ($codespell) { + if (open(my $spelling, '<', $codespellfile)) { + while (<$spelling>) { + my $line = $_; + + $line =~ s/\s*\n?$//g; + $line =~ s/^\s*//g; + + next if ($line =~ m/^\s*#/); + next if ($line =~ m/^\s*$/); + next if ($line =~ m/, disabled/i); + + $line =~ s/,.*$//; + + my ($suspect, $fix) = split(/->/, $line); + + $spelling_fix{$suspect} = $fix; + } + close($spelling); + } else { + warn "No codespell typos will be found - file '$codespellfile': $!\n"; + } +} + +$misspellings = join("|", sort keys %spelling_fix) if keys %spelling_fix; + +sub read_words { + my ($wordsRef, $file) = @_; + + if (open(my $words, '<', $file)) { + while (<$words>) { + my $line = $_; + + $line =~ s/\s*\n?$//g; + $line =~ s/^\s*//g; + + next if ($line =~ m/^\s*#/); + next if ($line =~ m/^\s*$/); + if ($line =~ /\s/) { + print("$file: '$line' invalid - ignored\n"); + next; + } + + $$wordsRef .= '|' if (defined $$wordsRef); + $$wordsRef .= $line; + } + close($file); + return 1; + } + + return 0; +} + +# OpenOCD specific: Begin: Load list of allowed CamelCase symbols +if (show_type("CAMELCASE")) { + my $allowed_camelcase_file = "tools/scripts/camelcase.txt"; + if (!$root) { + warn "Ignore list of allowed camelcase symbols.\n"; + } elsif (open(my $words, '<', "$root/$allowed_camelcase_file")) { + while (<$words>) { + my $line = $_; + + $line =~ s/\s*\n?$//g; + $line =~ s/^\s*//g; + + next if ($line =~ m/^\s*#/); + next if ($line =~ m/^\s*$/); + if ($line =~ /\s/) { + print("$allowed_camelcase_file: '$line' invalid - ignored\n"); + next; + } + + $camelcase{$line} = 1; + } + close("$root/$allowed_camelcase_file"); + } else { + warn "Failed opening file '$root/$allowed_camelcase_file': $!\n"; + } +} +# OpenOCD specific: End + +my $const_structs; +if (show_type("CONST_STRUCT")) { + read_words(\$const_structs, $conststructsfile) + or warn "No structs that should be const will be found - file '$conststructsfile': $!\n"; +} + +if (defined($typedefsfile)) { + my $typeOtherTypedefs; + read_words(\$typeOtherTypedefs, $typedefsfile) + or warn "No additional types will be considered - file '$typedefsfile': $!\n"; + $typeTypedefs .= '|' . $typeOtherTypedefs if (defined $typeOtherTypedefs); +} + sub build_types { - my $mods = "(?x: \n" . join("|\n ", @modifierList) . "\n)"; - my $all = "(?x: \n" . join("|\n ", @typeList) . "\n)"; + my $mods = "(?x: \n" . join("|\n ", (@modifierList, @modifierListFile)) . "\n)"; + my $all = "(?x: \n" . join("|\n ", (@typeList, @typeListFile)) . "\n)"; + my $Misordered = "(?x: \n" . join("|\n ", @typeListMisordered) . "\n)"; + my $allWithAttr = "(?x: \n" . join("|\n ", @typeListWithAttr) . "\n)"; $Modifier = qr{(?:$Attribute|$Sparse|$mods)}; + $BasicType = qr{ + (?:$typeTypedefs\b)| + (?:${all}\b) + }x; $NonptrType = qr{ (?:$Modifier\s+|const\s+)* (?: - (?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)| + (?:typeof|__typeof__)\s*\([^\)]*\)| (?:$typeTypedefs\b)| (?:${all}\b) ) (?:\s+$Modifier|\s+const)* }x; + $NonptrTypeMisordered = qr{ + (?:$Modifier\s+|const\s+)* + (?: + (?:${Misordered}\b) + ) + (?:\s+$Modifier|\s+const)* + }x; + $NonptrTypeWithAttr = qr{ + (?:$Modifier\s+|const\s+)* + (?: + (?:typeof|__typeof__)\s*\([^\)]*\)| + (?:$typeTypedefs\b)| + (?:${allWithAttr}\b) + ) + (?:\s+$Modifier|\s+const)* + }x; $Type = qr{ $NonptrType - (?:[\s\*]+\s*const|[\s\*]+|(?:\s*\[\s*\])+)? + (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+){0,4} + (?:\s+$Inline|\s+$Modifier)* + }x; + $TypeMisordered = qr{ + $NonptrTypeMisordered + (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+){0,4} (?:\s+$Inline|\s+$Modifier)* }x; - $Declare = qr{(?:$Storage\s+)?$Type}; + $Declare = qr{(?:$Storage\s+(?:$Inline\s+)?)?$Type}; + $DeclareMisordered = qr{(?:$Storage\s+(?:$Inline\s+)?)?$TypeMisordered}; } build_types(); -our $match_balanced_parentheses = qr/(\((?:[^\(\)]+|(-1))*\))/; - our $Typecast = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*}; -our $LvalOrFunc = qr{($Lval)\s*($match_balanced_parentheses{0,1})\s*}; + +# Using $balanced_parens, $LvalOrFunc, or $FuncArg +# requires at least perl version v5.10.0 +# Any use must be runtime checked with $^V + +our $balanced_parens = qr/(\((?:[^\(\)]++|(?-1))*\))/; +our $LvalOrFunc = qr{((?:[\&\*]\s*)?$Lval)\s*($balanced_parens{0,1})\s*}; +our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant|$String)}; + +our $declaration_macros = qr{(?x: + (?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(| + (?:$Storage\s+)?[HLP]?LIST_HEAD\s*\(| + (?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\(| + (?:$Storage\s+)?(?:XA_STATE|XA_STATE_ORDER)\s*\( +)}; + +our %allow_repeated_words = ( + add => '', + added => '', + bad => '', + be => '', +); sub deparenthesize { my ($string) = @_; return "" if (!defined($string)); - $string =~ s@^\s*\(\s*@@g; - $string =~ s@\s*\)\s*$@@g; + + while ($string =~ /^\s*\(.*\)\s*$/) { + $string =~ s@^\s*\(\s*@@; + $string =~ s@\s*\)\s*$@@; + } + $string =~ s@\s+@ @g; + return $string; } -$chk_signoff = 0 if ($file); +sub seed_camelcase_file { + my ($file) = @_; -my @dep_includes = (); -my @dep_functions = (); -my $removal = "Documentation/feature-removal-schedule.txt"; -if ($tree && -f "$root/$removal") { - open(my $REMOVE, '<', "$root/$removal") || - die "$P: $removal: open failed - $!\n"; - while (<$REMOVE>) { - if (/^Check:\s+(.*\S)/) { - for my $entry (split(/[, ]+/, $1)) { - if ($entry =~ m@include/(.*)@) { - push(@dep_includes, $1); + return if (!(-f $file)); - } elsif ($entry !~ m@/@) { - push(@dep_functions, $entry); - } - } + local $/; + + open(my $include_file, '<', "$file") + or warn "$P: Can't read '$file' $!\n"; + my $text = <$include_file>; + close($include_file); + + my @lines = split('\n', $text); + + foreach my $line (@lines) { + if (!$OpenOCD) { + next if ($line !~ /(?:[A-Z][a-z]|[a-z][A-Z])/); + if ($line =~ /^[ \t]*(?:#[ \t]*define|typedef\s+$Type)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)/) { + $camelcase{$1} = 1; + } elsif ($line =~ /^\s*$Declare\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[\(\[,;]/) { + $camelcase{$1} = 1; + } elsif ($line =~ /^\s*(?:union|struct|enum)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[;\{]/) { + $camelcase{$1} = 1; + } + } # !$OpenOCD + # OpenOCD Specific: Begin: extend to camel[0-9_]*CASE + next if ($line !~ /(?:[A-Z][0-9_]*[a-z]|[a-z][0-9_]*[A-Z])/); + if ($line =~ /^[ \t]*(?:#[ \t]*define|typedef\s+$Type)\s+(\w*(?:[A-Z][0-9_]*[a-z]|[a-z][0-9_]*[A-Z])\w*)/) { + $camelcase{$1} = 1; + } elsif ($line =~ /^\s*$Declare\s+(\w*(?:[A-Z][0-9_]*[a-z]|[a-z][0-9_]*[A-Z])\w*)\s*[\(\[,;]/) { + $camelcase{$1} = 1; + } elsif ($line =~ /^\s*(?:union|struct|enum)\s+(\w*(?:[A-Z][0-9_]*[a-z]|[a-z][0-9_]*[A-Z])\w*)\s*[;\{]/) { + $camelcase{$1} = 1; + } + # OpenOCD Specific: End + } +} + +our %maintained_status = (); + +sub is_maintained_obsolete { + my ($filename) = @_; + + return 0 if (!$tree || !(-e "$root/scripts/get_maintainer.pl")); + + if (!exists($maintained_status{$filename})) { + $maintained_status{$filename} = `perl $root/scripts/get_maintainer.pl --status --nom --nol --nogit --nogit-fallback -f $filename 2>&1`; + } + + return $maintained_status{$filename} =~ /obsolete/i; +} + +sub is_SPDX_License_valid { + my ($license) = @_; + + # OpenOCD specific: Begin: replace s"scripts"tools/scripts" + return 1 if (!$tree || which("python3") eq "" || !(-x "$root/tools/scripts/spdxcheck.py") || !(-e "$gitroot")); + + my $root_path = abs_path($root); + my $status = `cd "$root_path"; echo "$license" | tools/scripts/spdxcheck.py -`; + # OpenOCD specific: End + return 0 if ($status ne ""); + return 1; +} + +my $camelcase_seeded = 0; +sub seed_camelcase_includes { + return if ($camelcase_seeded); + + my $files; + my $camelcase_cache = ""; + my @include_files = (); + + $camelcase_seeded = 1; + + if (-e "$gitroot") { + my $git_last_include_commit = `${git_command} log --no-merges --pretty=format:"%h%n" -1 -- include`; + chomp $git_last_include_commit; + $camelcase_cache = ".checkpatch-camelcase.git.$git_last_include_commit"; + } else { + my $last_mod_date = 0; + $files = `find $root/include -name "*.h"`; + @include_files = split('\n', $files); + foreach my $file (@include_files) { + my $date = POSIX::strftime("%Y%m%d%H%M", + localtime((stat $file)[9])); + $last_mod_date = $date if ($last_mod_date < $date); + } + $camelcase_cache = ".checkpatch-camelcase.date.$last_mod_date"; + } + + if ($camelcase_cache ne "" && -f $camelcase_cache) { + open(my $camelcase_file, '<', "$camelcase_cache") + or warn "$P: Can't read '$camelcase_cache' $!\n"; + while (<$camelcase_file>) { + chomp; + $camelcase{$_} = 1; + } + close($camelcase_file); + + return; + } + + if (-e "$gitroot") { + $files = `${git_command} ls-files "include/*.h"`; + @include_files = split('\n', $files); + } + + foreach my $file (@include_files) { + seed_camelcase_file($file); + } + + if ($camelcase_cache ne "") { + unlink glob ".checkpatch-camelcase.*"; + open(my $camelcase_file, '>', "$camelcase_cache") + or warn "$P: Can't write '$camelcase_cache' $!\n"; + foreach (sort { lc($a) cmp lc($b) } keys(%camelcase)) { + print $camelcase_file ("$_\n"); } + close($camelcase_file); + } +} + +sub git_is_single_file { + my ($filename) = @_; + + return 0 if ((which("git") eq "") || !(-e "$gitroot")); + + my $output = `${git_command} ls-files -- $filename 2>/dev/null`; + my $count = $output =~ tr/\n//; + return $count eq 1 && $output =~ m{^${filename}$}; +} + +sub git_commit_info { + my ($commit, $id, $desc) = @_; + + return ($id, $desc) if ((which("git") eq "") || !(-e "$gitroot")); + + my $output = `${git_command} log --no-color --format='%H %s' -1 $commit 2>&1`; + $output =~ s/^\s*//gm; + my @lines = split("\n", $output); + + return ($id, $desc) if ($#lines < 0); + + if ($lines[0] =~ /^error: short SHA1 $commit is ambiguous/) { +# Maybe one day convert this block of bash into something that returns +# all matching commit ids, but it's very slow... +# +# echo "checking commits $1..." +# git rev-list --remotes | grep -i "^$1" | +# while read line ; do +# git log --format='%H %s' -1 $line | +# echo "commit $(cut -c 1-12,41-)" +# done + } elsif ($lines[0] =~ /^fatal: ambiguous argument '$commit': unknown revision or path not in the working tree\./ || + $lines[0] =~ /^fatal: bad object $commit/) { + $id = undef; + } else { + $id = substr($lines[0], 0, 12); + $desc = substr($lines[0], 41); } - close($REMOVE); + + return ($id, $desc); } +$chk_signoff = 0 if ($file); + my @rawlines = (); my @lines = (); +my @fixed = (); +my @fixed_inserted = (); +my @fixed_deleted = (); +my $fixlinenr = -1; + +# If input is git commits, extract all commits from the commit expressions. +# For example, HEAD-3 means we need check 'HEAD, HEAD~1, HEAD~2'. +die "$P: No git repository found\n" if ($git && !-e "$gitroot"); + +if ($git) { + my @commits = (); + foreach my $commit_expr (@ARGV) { + my $git_range; + if ($commit_expr =~ m/^(.*)-(\d+)$/) { + $git_range = "-$2 $1"; + } elsif ($commit_expr =~ m/\.\./) { + $git_range = "$commit_expr"; + } else { + $git_range = "-1 $commit_expr"; + } + my $lines = `${git_command} log --no-color --no-merges --pretty=format:'%H %s' $git_range`; + foreach my $line (split(/\n/, $lines)) { + $line =~ /^([0-9a-fA-F]{40,40}) (.*)$/; + next if (!defined($1) || !defined($2)); + my $sha1 = $1; + my $subject = $2; + unshift(@commits, $sha1); + $git_commits{$sha1} = $subject; + } + } + die "$P: no git commits after extraction!\n" if (@commits == 0); + @ARGV = @commits; +} + my $vname; +$allow_c99_comments = !defined $ignore_type{"C99_COMMENT_TOLERANCE"}; for my $filename (@ARGV) { my $FILE; - if ($file) { + my $is_git_file = git_is_single_file($filename); + my $oldfile = $file; + $file = 1 if ($is_git_file); + if ($git) { + open($FILE, '-|', "git format-patch -M --stdout -1 $filename") || + die "$P: $filename: git format-patch failed - $!\n"; + } elsif ($file) { open($FILE, '-|', "diff -u /dev/null $filename") || die "$P: $filename: diff failed - $!\n"; } elsif ($filename eq '-') { @@ -380,30 +1346,87 @@ sub deparenthesize { } if ($filename eq '-') { $vname = 'Your patch'; + } elsif ($git) { + $vname = "Commit " . substr($filename, 0, 12) . ' ("' . $git_commits{$filename} . '")'; } else { $vname = $filename; } while (<$FILE>) { chomp; push(@rawlines, $_); + $vname = qq("$1") if ($filename eq '-' && $_ =~ m/^Subject:\s+(.+)/i); } close($FILE); + + if ($#ARGV > 0 && $quiet == 0) { + print '-' x length($vname) . "\n"; + print "$vname\n"; + print '-' x length($vname) . "\n"; + } + if (!process($filename)) { $exit = 1; } @rawlines = (); @lines = (); + @fixed = (); + @fixed_inserted = (); + @fixed_deleted = (); + $fixlinenr = -1; + @modifierListFile = (); + @typeListFile = (); + build_types(); + $file = $oldfile if ($is_git_file); } -exit($exit); +if (!$quiet) { + hash_show_words(\%use_type, "Used"); + hash_show_words(\%ignore_type, "Ignored"); + + if (!$perl_version_ok) { + print << "EOM" + +NOTE: perl $^V is not modern enough to detect all possible issues. + An upgrade to at least perl $minimum_perl_version is suggested. +EOM + } + if ($exit) { + if (!$OpenOCD) { + print << "EOM" + +NOTE: If any of the errors are false positives, please report + them to the maintainer, see CHECKPATCH in MAINTAINERS. +EOM + } # !$OpenOCD + # OpenOCD specific: Begin + print << "EOM" + +NOTE: If any of the errors are false positives, please report + them to the openocd-devel mailing list or prepare a patch + and send it to Gerrit for review. +EOM + # OpenOCD specific: End + } +} + +exit($exit); sub top_of_kernel_tree { my ($root) = @_; + if (!$OpenOCD) { + my @tree_check = ( + "COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile", + "README", "Documentation", "arch", "include", "drivers", + "fs", "init", "ipc", "kernel", "lib", "scripts", + ); + } # !$OpenOCD + # OpenOCD specific: Begin my @tree_check = ( "AUTHORS", "BUGS", "COPYING", "HACKING", "Makefile.am", "README", "contrib", "doc", "src", "tcl", "testing", "tools", ); + # OpenOCD specific: End foreach my $check (@tree_check) { if (! -e $root . '/' . $check) { @@ -411,12 +1434,14 @@ sub top_of_kernel_tree { } } return 1; - } +} sub parse_email { my ($formatted_email) = @_; my $name = ""; + my $quoted = ""; + my $name_comment = ""; my $address = ""; my $comment = ""; @@ -430,9 +1455,9 @@ sub parse_email { } elsif ($formatted_email =~ /(\S+\@\S+)(.*)$/) { $address = $1; $comment = $2 if defined $2; - $formatted_email =~ s/$address.*$//; + $formatted_email =~ s/\Q$address\E.*$//; $name = $formatted_email; - $name =~ s/^\s+|\s+$//g; + $name = trim($name); $name =~ s/^\"|\"$//g; # If there's a name left after stripping spaces and # leading quotes, and the address doesn't have both @@ -445,46 +1470,94 @@ sub parse_email { $address = ""; $comment = ""; } + # OpenOCD specific: Begin: handle jenkins as valid email } elsif ($formatted_email eq "jenkins") { - $address = "jenkins" + $address = "jenkins"; + # OpenOCD specific: End + } + + # Extract comments from names excluding quoted parts + # "John D. (Doe)" - Do not extract + if ($name =~ s/\"(.+)\"//) { + $quoted = $1; + } + while ($name =~ s/\s*($balanced_parens)\s*/ /) { + $name_comment .= trim($1); } + $name =~ s/^[ \"]+|[ \"]+$//g; + $name = trim("$quoted $name"); - $name =~ s/^\s+|\s+$//g; - $name =~ s/^\"|\"$//g; - $address =~ s/^\s+|\s+$//g; + $address = trim($address); $address =~ s/^\<|\>$//g; + $comment = trim($comment); if ($name =~ /[^\w \-]/i) { ##has "must quote" chars $name =~ s/(?<!\\)"/\\"/g; ##escape quotes $name = "\"$name\""; } - return ($name, $address, $comment); + return ($name, $name_comment, $address, $comment); } sub format_email { - my ($name, $address) = @_; + my ($name, $name_comment, $address, $comment) = @_; my $formatted_email; - $name =~ s/^\s+|\s+$//g; - $name =~ s/^\"|\"$//g; - $address =~ s/^\s+|\s+$//g; + $name =~ s/^[ \"]+|[ \"]+$//g; + $address = trim($address); + $address =~ s/(?:\.|\,|\")+$//; ##trailing commas, dots or quotes if ($name =~ /[^\w \-]/i) { ##has "must quote" chars $name =~ s/(?<!\\)"/\\"/g; ##escape quotes $name = "\"$name\""; } + $name_comment = trim($name_comment); + $name_comment = " $name_comment" if ($name_comment ne ""); + $comment = trim($comment); + $comment = " $comment" if ($comment ne ""); + if ("$name" eq "") { $formatted_email = "$address"; } else { - $formatted_email = "$name <$address>"; + $formatted_email = "$name$name_comment <$address>"; } - + $formatted_email .= "$comment"; return $formatted_email; } +sub reformat_email { + my ($email) = @_; + + my ($email_name, $name_comment, $email_address, $comment) = parse_email($email); + return format_email($email_name, $name_comment, $email_address, $comment); +} + +sub same_email_addresses { + my ($email1, $email2) = @_; + + my ($email1_name, $name1_comment, $email1_address, $comment1) = parse_email($email1); + my ($email2_name, $name2_comment, $email2_address, $comment2) = parse_email($email2); + + return $email1_name eq $email2_name && + $email1_address eq $email2_address && + $name1_comment eq $name2_comment && + $comment1 eq $comment2; +} + +sub which { + my ($bin) = @_; + + foreach my $path (split(/:/, $ENV{PATH})) { + if (-e "$path/$bin") { + return "$path/$bin"; + } + } + + return ""; +} + sub which_conf { my ($conf) = @_; @@ -506,7 +1579,7 @@ sub expand_tabs { if ($c eq "\t") { $res .= ' '; $n++; - for (; ($n % 4) != 0; $n++) { + for (; ($n % $tabsize) != 0; $n++) { $res .= ' '; } next; @@ -562,7 +1635,7 @@ sub sanitise_line { for ($off = 1; $off < length($line); $off++) { $c = substr($line, $off, 1); - # Comments we are wacking completly including the begin + # Comments we are whacking completely including the begin # and end, all to $;. if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') { $sanitise_quote = '*/'; @@ -631,9 +1704,22 @@ sub sanitise_line { $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@; } + if ($allow_c99_comments && $res =~ m@(//.*$)@) { + my $match = $1; + $res =~ s/\Q$match\E/"$;" x length($match)/e; + } + return $res; } +sub get_quoted_string { + my ($line, $rawline) = @_; + + return "" if (!defined($line) || !defined($rawline)); + return "" if ($line !~ m/($String)/g); + return substr($rawline, $-[0], $+[0] - $-[0]); +} + sub ctx_statement_block { my ($linenr, $remain, $off) = @_; my $line = $linenr - 1; @@ -674,6 +1760,10 @@ sub ctx_statement_block { if ($off >= $len) { last; } + if ($level == 0 && substr($blk, $off) =~ /^.\s*#\s*define/) { + $level++; + $type = '#'; + } } $p = $c; $c = substr($blk, $off, 1); @@ -699,7 +1789,7 @@ sub ctx_statement_block { # An else is really a conditional as long as its not else if if ($level == 0 && $coff_set == 0 && (!defined($p) || $p =~ /(?:\s|\}|\+)/) && - $remainder =~ /^(else)(?:\s|\{)/ && + $remainder =~ /^(else)(?:\s|{)/ && $remainder !~ /^else\s+if\b/) { $coff = $off + length($1) - 1; $coff_set = 1; @@ -736,6 +1826,13 @@ sub ctx_statement_block { last; } } + # Preprocessor commands end at the newline unless escaped. + if ($type eq '#' && $c eq "\n" && $p ne "\\") { + $level--; + $type = ''; + $off++; + last; + } $off++; } # We are truly at the end, so shuffle to the next line. @@ -782,7 +1879,7 @@ sub statement_block_size { my ($stmt) = @_; $stmt =~ s/(^|\n)./$1/g; - $stmt =~ s/^\s*\{//; + $stmt =~ s/^\s*{//; $stmt =~ s/}\s*$//; $stmt =~ s/^\s*//; $stmt =~ s/\s*$//; @@ -911,8 +2008,16 @@ sub ctx_statement_level { sub ctx_locate_comment { my ($first_line, $end_line) = @_; + # If c99 comment on the current line, or the line before or after + my ($current_comment) = ($rawlines[$end_line - 1] =~ m@^\+.*(//.*$)@); + return $current_comment if (defined $current_comment); + ($current_comment) = ($rawlines[$end_line - 2] =~ m@^[\+ ].*(//.*$)@); + return $current_comment if (defined $current_comment); + ($current_comment) = ($rawlines[$end_line] =~ m@^[\+ ].*(//.*$)@); + return $current_comment if (defined $current_comment); + # Catch a comment on the end of the line itself. - my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@); + ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@); return $current_comment if (defined $current_comment); # Look through the context and try and figure out if there is a @@ -966,6 +2071,28 @@ sub raw_line { return $line; } +sub get_stat_real { + my ($linenr, $lc) = @_; + + my $stat_real = raw_line($linenr, 0); + for (my $count = $linenr + 1; $count <= $lc; $count++) { + $stat_real = $stat_real . "\n" . raw_line($count, 0); + } + + return $stat_real; +} + +sub get_stat_here { + my ($linenr, $cnt, $here) = @_; + + my $herectx = $here . "\n"; + for (my $n = 0; $n < $cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n"; + } + + return $herectx; +} + sub cat_vet { my ($vet) = @_; my ($res, $coded); @@ -1018,7 +2145,7 @@ sub annotate_values { } elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') { print "CAST($1)\n" if ($dbg_values > 1); push(@av_paren_type, $type); - $type = 'C'; + $type = 'c'; } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) { print "DECLARE($1)\n" if ($dbg_values > 1); @@ -1136,7 +2263,7 @@ sub annotate_values { print "ASSIGN($1)\n" if ($dbg_values > 1); $type = 'N'; - } elsif ($cur =~/^(;|\{|})/) { + } elsif ($cur =~/^(;|{|})/) { print "END($1)\n" if ($dbg_values > 1); $type = 'E'; $av_pend_colon = 'O'; @@ -1210,7 +2337,9 @@ sub possible { case| else| asm|__asm__| - do + do| + \#| + \#\#| )(?:\s|$)| ^(?:typedef|struct|enum)\b )}x; @@ -1226,13 +2355,13 @@ sub possible { for my $modifier (split(' ', $possible)) { if ($modifier !~ $notPermitted) { warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible); - push(@modifierList, $modifier); + push(@modifierListFile, $modifier); } } } else { warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible); - push(@typeList, $possible); + push(@typeListFile, $possible); } build_types(); } else { @@ -1243,47 +2372,178 @@ sub possible { my $prefix = ''; sub show_type { - return !defined $ignore_type{$_[0]}; + my ($type) = @_; + + $type =~ tr/[a-z]/[A-Z]/; + + return defined $use_type{$type} if (scalar keys %use_type > 0); + + return !defined $ignore_type{$type}; } sub report { - if (!show_type($_[1]) || - (defined $tst_only && $_[2] !~ /\Q$tst_only\E/)) { + my ($level, $type, $msg) = @_; + + if (!show_type($type) || + (defined $tst_only && $msg !~ /\Q$tst_only\E/)) { return 0; } - my $line; + my $output = ''; + if ($color) { + if ($level eq 'ERROR') { + $output .= RED; + } elsif ($level eq 'WARNING') { + $output .= YELLOW; + } else { + $output .= GREEN; + } + } + $output .= $prefix . $level . ':'; if ($show_types) { - $line = "$prefix$_[0]:$_[1]: $_[2]\n"; - } else { - $line = "$prefix$_[0]: $_[2]\n"; + $output .= BLUE if ($color); + $output .= "$type:"; + } + $output .= RESET if ($color); + $output .= ' ' . $msg . "\n"; + + if ($showfile) { + my @lines = split("\n", $output, -1); + splice(@lines, 1, 1); + $output = join("\n", @lines); + } + + if ($terse) { + $output = (split('\n', $output))[0] . "\n"; + } + + if ($verbose && exists($verbose_messages{$type}) && + !exists($verbose_emitted{$type})) { + $output .= $verbose_messages{$type} . "\n\n"; + $verbose_emitted{$type} = 1; } - $line = (split('\n', $line))[0] . "\n" if ($terse); - push(our @report, $line); + push(our @report, $output); return 1; } + sub report_dump { our @report; } +sub fixup_current_range { + my ($lineRef, $offset, $length) = @_; + + if ($$lineRef =~ /^\@\@ -\d+,\d+ \+(\d+),(\d+) \@\@/) { + my $o = $1; + my $l = $2; + my $no = $o + $offset; + my $nl = $l + $length; + $$lineRef =~ s/\+$o,$l \@\@/\+$no,$nl \@\@/; + } +} + +sub fix_inserted_deleted_lines { + my ($linesRef, $insertedRef, $deletedRef) = @_; + + my $range_last_linenr = 0; + my $delta_offset = 0; + + my $old_linenr = 0; + my $new_linenr = 0; + + my $next_insert = 0; + my $next_delete = 0; + + my @lines = (); + + my $inserted = @{$insertedRef}[$next_insert++]; + my $deleted = @{$deletedRef}[$next_delete++]; + + foreach my $old_line (@{$linesRef}) { + my $save_line = 1; + my $line = $old_line; #don't modify the array + if ($line =~ /^(?:\+\+\+|\-\-\-)\s+\S+/) { #new filename + $delta_offset = 0; + } elsif ($line =~ /^\@\@ -\d+,\d+ \+\d+,\d+ \@\@/) { #new hunk + $range_last_linenr = $new_linenr; + fixup_current_range(\$line, $delta_offset, 0); + } + + while (defined($deleted) && ${$deleted}{'LINENR'} == $old_linenr) { + $deleted = @{$deletedRef}[$next_delete++]; + $save_line = 0; + fixup_current_range(\$lines[$range_last_linenr], $delta_offset--, -1); + } + + while (defined($inserted) && ${$inserted}{'LINENR'} == $old_linenr) { + push(@lines, ${$inserted}{'LINE'}); + $inserted = @{$insertedRef}[$next_insert++]; + $new_linenr++; + fixup_current_range(\$lines[$range_last_linenr], $delta_offset++, 1); + } + + if ($save_line) { + push(@lines, $line); + $new_linenr++; + } + + $old_linenr++; + } + + return @lines; +} + +sub fix_insert_line { + my ($linenr, $line) = @_; + + my $inserted = { + LINENR => $linenr, + LINE => $line, + }; + push(@fixed_inserted, $inserted); +} + +sub fix_delete_line { + my ($linenr, $line) = @_; + + my $deleted = { + LINENR => $linenr, + LINE => $line, + }; + + push(@fixed_deleted, $deleted); +} + sub ERROR { - if (report("ERROR", $_[0], $_[1])) { + my ($type, $msg) = @_; + + if (report("ERROR", $type, $msg)) { our $clean = 0; our $cnt_error++; + return 1; } + return 0; } sub WARN { - if (report("WARNING", $_[0], $_[1])) { + my ($type, $msg) = @_; + + if (report("WARNING", $type, $msg)) { our $clean = 0; our $cnt_warn++; + return 1; } + return 0; } sub CHK { - if ($check && report("CHECK", $_[0], $_[1])) { + my ($type, $msg) = @_; + + if ($check && report("CHECK", $type, $msg)) { our $clean = 0; our $cnt_chk++; + return 1; } + return 0; } sub check_absolute_file { @@ -1314,6 +2574,105 @@ sub check_absolute_file { } } +sub trim { + my ($string) = @_; + + $string =~ s/^\s+|\s+$//g; + + return $string; +} + +sub ltrim { + my ($string) = @_; + + $string =~ s/^\s+//; + + return $string; +} + +sub rtrim { + my ($string) = @_; + + $string =~ s/\s+$//; + + return $string; +} + +sub string_find_replace { + my ($string, $find, $replace) = @_; + + $string =~ s/$find/$replace/g; + + return $string; +} + +sub tabify { + my ($leading) = @_; + + my $source_indent = $tabsize; + my $max_spaces_before_tab = $source_indent - 1; + my $spaces_to_tab = " " x $source_indent; + + #convert leading spaces to tabs + 1 while $leading =~ s@^([\t]*)$spaces_to_tab@$1\t@g; + #Remove spaces before a tab + 1 while $leading =~ s@^([\t]*)( {1,$max_spaces_before_tab})\t@$1\t@g; + + return "$leading"; +} + +sub pos_last_openparen { + my ($line) = @_; + + my $pos = 0; + + my $opens = $line =~ tr/\(/\(/; + my $closes = $line =~ tr/\)/\)/; + + my $last_openparen = 0; + + if (($opens == 0) || ($closes >= $opens)) { + return -1; + } + + my $len = length($line); + + for ($pos = 0; $pos < $len; $pos++) { + my $string = substr($line, $pos); + if ($string =~ /^($FuncArg|$balanced_parens)/) { + $pos += length($1) - 1; + } elsif (substr($line, $pos, 1) eq '(') { + $last_openparen = $pos; + } elsif (index($string, '(') == -1) { + last; + } + } + + return length(expand_tabs(substr($line, 0, $last_openparen))) + 1; +} + +sub get_raw_comment { + my ($line, $rawline) = @_; + my $comment = ''; + + for my $i (0 .. (length($line) - 1)) { + if (substr($line, $i, 1) eq "$;") { + $comment .= substr($rawline, $i, 1); + } + } + + return $comment; +} + +sub exclude_global_initialisers { + my ($realfile) = @_; + + # Do not check for BPF programs (tools/testing/selftests/bpf/progs/*.c, samples/bpf/*_kern.c, *.bpf.c). + return $realfile =~ m@^tools/testing/selftests/bpf/progs/.*\.c$@ || + $realfile =~ m@^samples/bpf/.*_kern\.c$@ || + $realfile =~ m@/bpf/.*\.bpf\.c$@; +} + sub process { my $filename = shift; @@ -1330,7 +2689,26 @@ sub process { our $clean = 1; my $signoff = 0; + my $author = ''; + my $authorsignoff = 0; + my $author_sob = ''; my $is_patch = 0; + my $is_binding_patch = -1; + my $in_header_lines = $file ? 0 : 1; + my $in_commit_log = 0; #Scanning lines before patch + my $has_patch_separator = 0; #Found a --- line + my $has_commit_log = 0; #Encountered lines before patch + my $commit_log_lines = 0; #Number of commit log lines + my $commit_log_possible_stack_dump = 0; + my $commit_log_long_line = 0; + my $commit_log_has_diff = 0; + my $reported_maintainer_file = 0; + my $non_utf8_charset = 0; + + my $last_git_commit_id_linenr = -1; + + my $last_blank_line = 0; + my $last_coalesced_string_linenr = -1; our @report = (); our $cnt_lines = 0; @@ -1343,6 +2721,7 @@ sub process { my $realline = 0; my $realcnt = 0; my $here = ''; + my $context_function; #undef'd unless there's a known function my $in_comment = 0; my $comment_edge = 0; my $first_line = 0; @@ -1354,6 +2733,9 @@ sub process { my %suppress_ifbraces; my %suppress_whiletrailers; my %suppress_export; + my $suppress_statement = 0; + + my %signatures = (); # Pre-scan the patch sanitizing the lines. # Pre-scan the patch looking for any __setup documentation. @@ -1361,20 +2743,26 @@ sub process { my @setup_docs = (); my $setup_docs = 0; + my $camelcase_file_seeded = 0; + + my $checklicenseline = 1; + sanitise_line_reset(); my $line; foreach my $rawline (@rawlines) { $linenr++; $line = $rawline; + push(@fixed, $rawline) if ($fix); + if ($rawline=~/^\+\+\+\s+(\S+)/) { $setup_docs = 0; - if ($1 =~ m@Documentation/kernel-parameters.txt$@) { + if ($1 =~ m@Documentation/admin-guide/kernel-parameters.txt$@) { $setup_docs = 1; } #next; } - if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { + if ($rawline =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { $realline=$1-1; if (defined $2) { $realcnt=$3+1; @@ -1442,13 +2830,28 @@ sub process { $realcnt = 0; $linenr = 0; + $fixlinenr = -1; foreach my $line (@lines) { $linenr++; + $fixlinenr++; + my $sline = $line; #copy of $line + $sline =~ s/$;/ /g; #with comments as spaces my $rawline = $rawlines[$linenr - 1]; + my $raw_comment = get_raw_comment($line, $rawline); + +# check if it's a mode change, rename or start of a patch + if (!$in_commit_log && + ($line =~ /^ mode change [0-7]+ => [0-7]+ \S+\s*$/ || + ($line =~ /^rename (?:from|to) \S+\s*$/ || + $line =~ /^diff --git a\/[\w\/\.\_\-]+ b\/\S+\s*$/))) { + $is_patch = 1; + } #extract the line range in the file after the patch is applied - if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { + if (!$in_commit_log && + $line =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@(.*)/) { + my $context = $4; $is_patch = 1; $first_line = $linenr + 1; $realline=$1-1; @@ -1463,6 +2866,12 @@ sub process { %suppress_ifbraces = (); %suppress_whiletrailers = (); %suppress_export = (); + $suppress_statement = 0; + if ($context =~ /\b(\w+)\s*\(/) { + $context_function = $1; + } else { + undef $context_function; + } next; # track the line number as we move through the hunk, note that @@ -1488,21 +2897,20 @@ sub process { my $hunk_line = ($realcnt != 0); -#make up the handle for any error we report on this line - $prefix = "$filename:$realline: " if ($emacs && $file); - $prefix = "$filename:$linenr: " if ($emacs && !$file); - $here = "#$linenr: " if (!$file); $here = "#$realline: " if ($file); + my $found_file = 0; # extract the filename as it passes if ($line =~ /^diff --git.*?(\S+)$/) { $realfile = $1; - $realfile =~ s@^([^/]*)/@@; - + $realfile =~ s@^([^/]*)/@@ if (!$file); + $in_commit_log = 0; + $found_file = 1; } elsif ($line =~ /^\+\+\+\s+(\S+)/) { $realfile = $1; - $realfile =~ s@^([^/]*)/@@; + $realfile =~ s@^([^/]*)/@@ if (!$file); + $in_commit_log = 0; $p1_prefix = $1; if (!$file && $tree && $p1_prefix ne '' && @@ -1515,6 +2923,44 @@ sub process { ERROR("MODIFIED_INCLUDE_ASM", "do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n"); } + $found_file = 1; + } + +#make up the handle for any error we report on this line + if ($showfile) { + $prefix = "$realfile:$realline: " + } elsif ($emacs) { + if ($file) { + $prefix = "$filename:$realline: "; + } else { + $prefix = "$filename:$linenr: "; + } + } + + if ($found_file) { + if (is_maintained_obsolete($realfile)) { + WARN("OBSOLETE", + "$realfile is marked as 'obsolete' in the MAINTAINERS hierarchy. No unnecessary modifications please.\n"); + } + if ($realfile =~ m@^(?:drivers/net/|net/|drivers/staging/)@) { + $check = 1; + } else { + $check = $check_orig; + } + $checklicenseline = 1; + + if ($realfile !~ /^MAINTAINERS/) { + my $last_binding_patch = $is_binding_patch; + + $is_binding_patch = () = $realfile =~ m@^(?:Documentation/devicetree/|include/dt-bindings/)@; + + if (($last_binding_patch != -1) && + ($last_binding_patch ^ $is_binding_patch)) { + WARN("DT_SPLIT_BINDING_PATCH", + "DT binding docs and includes should be a separate patch. See: Documentation/devicetree/bindings/submitting-patches.rst\n"); + } + } + next; } @@ -1526,43 +2972,159 @@ sub process { $cnt_lines++ if ($realcnt != 0); +# Verify the existence of a commit log if appropriate +# 2 is used because a $signature is counted in $commit_log_lines + if ($in_commit_log) { + if ($line !~ /^\s*$/) { + $commit_log_lines++; #could be a $signature + } + } elsif ($has_commit_log && $commit_log_lines < 2) { + WARN("COMMIT_MESSAGE", + "Missing commit description - Add an appropriate one\n"); + $commit_log_lines = 2; #warn only once + } + +# Check if the commit log has what seems like a diff which can confuse patch + if ($in_commit_log && !$commit_log_has_diff && + (($line =~ m@^\s+diff\b.*a/([\w/]+)@ && + $line =~ m@^\s+diff\b.*a/[\w/]+\s+b/$1\b@) || + $line =~ m@^\s*(?:\-\-\-\s+a/|\+\+\+\s+b/)@ || + $line =~ m/^\s*\@\@ \-\d+,\d+ \+\d+,\d+ \@\@/)) { + ERROR("DIFF_IN_COMMIT_MSG", + "Avoid using diff content in the commit message - patch(1) might not work\n" . $herecurr); + $commit_log_has_diff = 1; + } + # Check for incorrect file permissions if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) { my $permhere = $here . "FILE: $realfile\n"; - if ($realfile =~ /(Makefile|Kconfig|\.c|\.h|\.S|\.tmpl)$/) { + if ($realfile !~ m@scripts/@ && + $realfile !~ /\.(py|pl|awk|sh)$/) { ERROR("EXECUTE_PERMISSIONS", "do not set execute permissions for source files\n" . $permhere); } } +# Check the patch for a From: + if (decode("MIME-Header", $line) =~ /^From:\s*(.*)/) { + $author = $1; + my $curline = $linenr; + while(defined($rawlines[$curline]) && ($rawlines[$curline++] =~ /^[ \t]\s*(.*)/)) { + $author .= $1; + } + $author = encode("utf8", $author) if ($line =~ /=\?utf-8\?/i); + $author =~ s/"//g; + $author = reformat_email($author); + } + # Check the patch for a signoff: - if ($line =~ /^\s*signed-off-by:/i) { + if ($line =~ /^\s*signed-off-by:\s*(.*)/i) { $signoff++; + $in_commit_log = 0; + if ($author ne '' && $authorsignoff != 1) { + if (same_email_addresses($1, $author)) { + $authorsignoff = 1; + } else { + my $ctx = $1; + my ($email_name, $email_comment, $email_address, $comment1) = parse_email($ctx); + my ($author_name, $author_comment, $author_address, $comment2) = parse_email($author); + + if (lc $email_address eq lc $author_address && $email_name eq $author_name) { + $author_sob = $ctx; + $authorsignoff = 2; + } elsif (lc $email_address eq lc $author_address) { + $author_sob = $ctx; + $authorsignoff = 3; + } elsif ($email_name eq $author_name) { + $author_sob = $ctx; + $authorsignoff = 4; + + my $address1 = $email_address; + my $address2 = $author_address; + + if ($address1 =~ /(\S+)\+\S+(\@.*)/) { + $address1 = "$1$2"; + } + if ($address2 =~ /(\S+)\+\S+(\@.*)/) { + $address2 = "$1$2"; + } + if ($address1 eq $address2) { + $authorsignoff = 5; + } + } + } + } + } + +# OpenOCD specific: Begin: Extend list of checkpatch tests to ignore + if ($in_commit_log && $line =~ /^\s*Checkpatch-ignore:\s*(.*)/) { + my @array = split(/[\s,]+/, $1); + hash_save_array_words(\%ignore_type, \@array); + } +# OpenOCD specific: End + +# Check for patch separator + if ($line =~ /^---$/) { + $has_patch_separator = 1; + $in_commit_log = 0; + } + +# Check if MAINTAINERS is being updated. If so, there's probably no need to +# emit the "does MAINTAINERS need updating?" message on file add/move/delete + if ($line =~ /^\s*MAINTAINERS\s*\|/) { + $reported_maintainer_file = 1; } # Check signature styles - if ($line =~ /^(\s*)($signature_tags)(\s*)(.*)/) { + if (!$in_header_lines && + $line =~ /^(\s*)([a-z0-9_-]+by:|$signature_tags)(\s*)(.*)/i) { my $space_before = $1; my $sign_off = $2; my $space_after = $3; my $email = $4; my $ucfirst_sign_off = ucfirst(lc($sign_off)); + if ($sign_off !~ /$signature_tags/) { + my $suggested_signature = find_standard_signature($sign_off); + if ($suggested_signature eq "") { + WARN("BAD_SIGN_OFF", + "Non-standard signature: $sign_off\n" . $herecurr); + } else { + if (WARN("BAD_SIGN_OFF", + "Non-standard signature: '$sign_off' - perhaps '$suggested_signature'?\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/$sign_off/$suggested_signature/; + } + } + } if (defined $space_before && $space_before ne "") { - WARN("BAD_SIGN_OFF", - "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr); + if (WARN("BAD_SIGN_OFF", + "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] = + "$ucfirst_sign_off $email"; + } } if ($sign_off =~ /-by:$/i && $sign_off ne $ucfirst_sign_off) { - WARN("BAD_SIGN_OFF", - "'$ucfirst_sign_off' is the preferred signature form\n" . $herecurr); + if (WARN("BAD_SIGN_OFF", + "'$ucfirst_sign_off' is the preferred signature form\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] = + "$ucfirst_sign_off $email"; + } + } if (!defined $space_after || $space_after ne " ") { - WARN("BAD_SIGN_OFF", - "Use a single space after $ucfirst_sign_off\n" . $herecurr); + if (WARN("BAD_SIGN_OFF", + "Use a single space after $ucfirst_sign_off\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] = + "$ucfirst_sign_off $email"; + } } - my ($email_name, $email_address, $comment) = parse_email($email); - my $suggested_email = format_email(($email_name, $email_address)); + my ($email_name, $name_comment, $email_address, $comment) = parse_email($email); + my $suggested_email = format_email(($email_name, $name_comment, $email_address, $comment)); if ($suggested_email eq "") { ERROR("BAD_SIGN_OFF", "Unrecognized email address: '$email'\n" . $herecurr); @@ -1572,36 +3134,271 @@ sub process { $dequoted =~ s/" </ </; # Don't force email to have quotes # Allow just an angle bracketed address - if ("$dequoted$comment" ne $email && - "<$email_address>$comment" ne $email && - "$suggested_email$comment" ne $email) { + if (!same_email_addresses($email, $suggested_email)) { + if (WARN("BAD_SIGN_OFF", + "email address '$email' might be better as '$suggested_email'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\Q$email\E/$suggested_email/; + } + } + + # Address part shouldn't have comments + my $stripped_address = $email_address; + $stripped_address =~ s/\([^\(\)]*\)//g; + if ($email_address ne $stripped_address) { + if (WARN("BAD_SIGN_OFF", + "address part of email should not have comments: '$email_address'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\Q$email_address\E/$stripped_address/; + } + } + + # Only one name comment should be allowed + my $comment_count = () = $name_comment =~ /\([^\)]+\)/g; + if ($comment_count > 1) { WARN("BAD_SIGN_OFF", - "email address '$email' might be better as '$suggested_email$comment'\n" . $herecurr); + "Use a single name comment in email: '$email'\n" . $herecurr); + } + + + # stable@vger.kernel.org or stable@kernel.org shouldn't + # have an email name. In addition comments should strictly + # begin with a # + if ($email =~ /^.*stable\@(?:vger\.)?kernel\.org/i) { + if (($comment ne "" && $comment !~ /^#.+/) || + ($email_name ne "")) { + my $cur_name = $email_name; + my $new_comment = $comment; + $cur_name =~ s/[a-zA-Z\s\-\"]+//g; + + # Remove brackets enclosing comment text + # and # from start of comments to get comment text + $new_comment =~ s/^\((.*)\)$/$1/; + $new_comment =~ s/^\[(.*)\]$/$1/; + $new_comment =~ s/^[\s\#]+|\s+$//g; + + $new_comment = trim("$new_comment $cur_name") if ($cur_name ne $new_comment); + $new_comment = " # $new_comment" if ($new_comment ne ""); + my $new_email = "$email_address$new_comment"; + + if (WARN("BAD_STABLE_ADDRESS_STYLE", + "Invalid email format for stable: '$email', prefer '$new_email'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\Q$email\E/$new_email/; + } + } + } elsif ($comment ne "" && $comment !~ /^(?:#.+|\(.+\))$/) { + my $new_comment = $comment; + + # Extract comment text from within brackets or + # c89 style /*...*/ comments + $new_comment =~ s/^\[(.*)\]$/$1/; + $new_comment =~ s/^\/\*(.*)\*\/$/$1/; + + $new_comment = trim($new_comment); + $new_comment =~ s/^[^\w]$//; # Single lettered comment with non word character is usually a typo + $new_comment = "($new_comment)" if ($new_comment ne ""); + my $new_email = format_email($email_name, $name_comment, $email_address, $new_comment); + + if (WARN("BAD_SIGN_OFF", + "Unexpected content after email: '$email', should be: '$new_email'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\Q$email\E/$new_email/; + } + } + } + +# Check for duplicate signatures + my $sig_nospace = $line; + $sig_nospace =~ s/\s//g; + $sig_nospace = lc($sig_nospace); + if (defined $signatures{$sig_nospace}) { + WARN("BAD_SIGN_OFF", + "Duplicate signature\n" . $herecurr); + } else { + $signatures{$sig_nospace} = 1; + } + +# Check Co-developed-by: immediately followed by Signed-off-by: with same name and email + if ($sign_off =~ /^co-developed-by:$/i) { + if ($email eq $author) { + WARN("BAD_SIGN_OFF", + "Co-developed-by: should not be used to attribute nominal patch author '$author'\n" . "$here\n" . $rawline); + } + if (!defined $lines[$linenr]) { + WARN("BAD_SIGN_OFF", + "Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $rawline); + } elsif ($rawlines[$linenr] !~ /^\s*signed-off-by:\s*(.*)/i) { + WARN("BAD_SIGN_OFF", + "Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $rawline . "\n" .$rawlines[$linenr]); + } elsif ($1 ne $email) { + WARN("BAD_SIGN_OFF", + "Co-developed-by and Signed-off-by: name/email do not match \n" . "$here\n" . $rawline . "\n" .$rawlines[$linenr]); } } } -# Check for wrappage within a valid hunk of the file - if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) { - ERROR("CORRUPTED_PATCH", - "patch seems to be corrupt (line wrapped?)\n" . - $herecurr) if (!$emitted_corrupt++); +# Check email subject for common tools that don't need to be mentioned + if ($in_header_lines && + $line =~ /^Subject:.*\b(?:checkpatch|sparse|smatch)\b[^:]/i) { + WARN("EMAIL_SUBJECT", + "A patch subject line should describe the change not the tool that found it\n" . $herecurr); } -# Check for absolute kernel paths. - if ($tree && $line =~ /^[^-]/) { - while ($line =~ m{(?:^|\s)(/\S*)}g) { - my $file = $1; +# Check for Gerrit Change-Ids not in any patch context + if ($realfile eq '' && !$has_patch_separator && $line =~ /^\s*change-id:/i) { + if (ERROR("GERRIT_CHANGE_ID", + "Remove Gerrit Change-Id's before submitting upstream\n" . $herecurr) && + $fix) { + fix_delete_line($fixlinenr, $rawline); + } + } - if ($file =~ m{^(.*?)(?::\d+)+:?$} && - check_absolute_file($1, $herecurr)) { - # - } else { - check_absolute_file($file, $herecurr); - } +# Check if the commit log is in a possible stack dump + if ($in_commit_log && !$commit_log_possible_stack_dump && + ($line =~ /^\s*(?:WARNING:|BUG:)/ || + $line =~ /^\s*\[\s*\d+\.\d{6,6}\s*\]/ || + # timestamp + $line =~ /^\s*\[\<[0-9a-fA-F]{8,}\>\]/) || + $line =~ /^(?:\s+\w+:\s+[0-9a-fA-F]+){3,3}/ || + $line =~ /^\s*\#\d+\s*\[[0-9a-fA-F]+\]\s*\w+ at [0-9a-fA-F]+/) { + # stack dump address styles + $commit_log_possible_stack_dump = 1; + } + +# Check for line lengths > 75 in commit log, warn once + if ($in_commit_log && !$commit_log_long_line && + length($line) > 75 && + !($line =~ /^\s*[a-zA-Z0-9_\/\.]+\s+\|\s+\d+/ || + # file delta changes + $line =~ /^\s*(?:[\w\.\-\+]*\/)++[\w\.\-\+]+:/ || + # filename then : + $line =~ /^\s*(?:Fixes:|Link:|$signature_tags)/i || + # A Fixes: or Link: line or signature tag line + $commit_log_possible_stack_dump)) { + WARN("COMMIT_LOG_LONG_LINE", + "Possible unwrapped commit description (prefer a maximum 75 chars per line)\n" . $herecurr); + $commit_log_long_line = 1; + } + +# Reset possible stack dump if a blank line is found + if ($in_commit_log && $commit_log_possible_stack_dump && + $line =~ /^\s*$/) { + $commit_log_possible_stack_dump = 0; + } + +# Check for lines starting with a # + if ($in_commit_log && $line =~ /^#/) { + if (WARN("COMMIT_COMMENT_SYMBOL", + "Commit log lines starting with '#' are dropped by git as comments\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/^/ /; } } +# Check for git id commit length and improperly formed commit descriptions +# A correctly formed commit description is: +# commit <SHA-1 hash length 12+ chars> ("Complete commit subject") +# with the commit subject '("' prefix and '")' suffix +# This is a fairly compilicated block as it tests for what appears to be +# bare SHA-1 hash with minimum length of 5. It also avoids several types of +# possible SHA-1 matches. +# A commit match can span multiple lines so this block attempts to find a +# complete typical commit on a maximum of 3 lines + if ($perl_version_ok && + $in_commit_log && !$commit_log_possible_stack_dump && + $line !~ /^\s*(?:Link|Patchwork|http|https|BugLink|base-commit):/i && + $line !~ /^This reverts commit [0-9a-f]{7,40}/ && + (($line =~ /\bcommit\s+[0-9a-f]{5,}\b/i || + ($line =~ /\bcommit\s*$/i && defined($rawlines[$linenr]) && $rawlines[$linenr] =~ /^\s*[0-9a-f]{5,}\b/i)) || + ($line =~ /(?:\s|^)[0-9a-f]{12,40}(?:[\s"'\(\[]|$)/i && + $line !~ /[\<\[][0-9a-f]{12,40}[\>\]]/i && + $line !~ /\bfixes:\s*[0-9a-f]{12,40}/i))) { + my $init_char = "c"; + my $orig_commit = ""; + my $short = 1; + my $long = 0; + my $case = 1; + my $space = 1; + my $id = '0123456789ab'; + my $orig_desc = "commit description"; + my $description = ""; + my $herectx = $herecurr; + my $has_parens = 0; + my $has_quotes = 0; + + my $input = $line; + if ($line =~ /(?:\bcommit\s+[0-9a-f]{5,}|\bcommit\s*$)/i) { + for (my $n = 0; $n < 2; $n++) { + if ($input =~ /\bcommit\s+[0-9a-f]{5,}\s*($balanced_parens)/i) { + $orig_desc = $1; + $has_parens = 1; + # Always strip leading/trailing parens then double quotes if existing + $orig_desc = substr($orig_desc, 1, -1); + if ($orig_desc =~ /^".*"$/) { + $orig_desc = substr($orig_desc, 1, -1); + $has_quotes = 1; + } + last; + } + last if ($#lines < $linenr + $n); + $input .= " " . trim($rawlines[$linenr + $n]); + $herectx .= "$rawlines[$linenr + $n]\n"; + } + $herectx = $herecurr if (!$has_parens); + } + + if ($input =~ /\b(c)ommit\s+([0-9a-f]{5,})\b/i) { + $init_char = $1; + $orig_commit = lc($2); + $short = 0 if ($input =~ /\bcommit\s+[0-9a-f]{12,40}/i); + $long = 1 if ($input =~ /\bcommit\s+[0-9a-f]{41,}/i); + $space = 0 if ($input =~ /\bcommit [0-9a-f]/i); + $case = 0 if ($input =~ /\b[Cc]ommit\s+[0-9a-f]{5,40}[^A-F]/); + } elsif ($input =~ /\b([0-9a-f]{12,40})\b/i) { + $orig_commit = lc($1); + } + + ($id, $description) = git_commit_info($orig_commit, + $id, $orig_desc); + + if (defined($id) && + ($short || $long || $space || $case || ($orig_desc ne $description) || !$has_quotes) && + $last_git_commit_id_linenr != $linenr - 1) { + ERROR("GIT_COMMIT_ID", + "Please use git commit description style 'commit <12+ chars of sha1> (\"<title line>\")' - ie: '${init_char}ommit $id (\"$description\")'\n" . $herectx); + } + #don't report the next line if this line ends in commit and the sha1 hash is the next line + $last_git_commit_id_linenr = $linenr if ($line =~ /\bcommit\s*$/i); + } + +# Check for added, moved or deleted files + if (!$reported_maintainer_file && !$in_commit_log && + ($line =~ /^(?:new|deleted) file mode\s*\d+\s*$/ || + $line =~ /^rename (?:from|to) [\w\/\.\-]+\s*$/ || + ($line =~ /\{\s*([\w\/\.\-]*)\s*\=\>\s*([\w\/\.\-]*)\s*\}/ && + (defined($1) || defined($2))))) { + $is_patch = 1; + $reported_maintainer_file = 1; + WARN("FILE_PATH_CHANGES", + "added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr); + } + +# Check for adding new DT bindings not in schema format + if (!$in_commit_log && + ($line =~ /^new file mode\s*\d+\s*$/) && + ($realfile =~ m@^Documentation/devicetree/bindings/.*\.txt$@)) { + WARN("DT_SCHEMA_BINDING_PATCH", + "DT bindings should be in DT schema format. See: Documentation/devicetree/bindings/writing-schema.rst\n"); + } + +# Check for wrappage within a valid hunk of the file + if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) { + ERROR("CORRUPTED_PATCH", + "patch seems to be corrupt (line wrapped?)\n" . + $herecurr) if (!$emitted_corrupt++); + } + # UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php if (($realfile =~ /^$/ || $line =~ /^\+/) && $rawline !~ m/^$UTF8*$/) { @@ -1615,137 +3412,760 @@ sub process { "Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr); } +# Check if it's the start of a commit log +# (not a header line and we haven't seen the patch filename) + if ($in_header_lines && $realfile =~ /^$/ && + !($rawline =~ /^\s+(?:\S|$)/ || + $rawline =~ /^(?:commit\b|from\b|[\w-]+:)/i)) { + $in_header_lines = 0; + $in_commit_log = 1; + $has_commit_log = 1; + } + +# Check if there is UTF-8 in a commit log when a mail header has explicitly +# declined it, i.e defined some charset where it is missing. + if ($in_header_lines && + $rawline =~ /^Content-Type:.+charset="(.+)".*$/ && + $1 !~ /utf-8/i) { + $non_utf8_charset = 1; + } + + if ($in_commit_log && $non_utf8_charset && $realfile =~ /^$/ && + $rawline =~ /$NON_ASCII_UTF8/) { + WARN("UTF8_BEFORE_PATCH", + "8-bit UTF-8 used in possible commit log\n" . $herecurr); + } + +# Check for absolute kernel paths in commit message + if ($tree && $in_commit_log) { + while ($line =~ m{(?:^|\s)(/\S*)}g) { + my $file = $1; + + if ($file =~ m{^(.*?)(?::\d+)+:?$} && + check_absolute_file($1, $herecurr)) { + # + } else { + check_absolute_file($file, $herecurr); + } + } + } + +# Check for various typo / spelling mistakes + if (defined($misspellings) && + # OpenOCD specific: Begin: don't check spelling on spelling_file + index($spelling_file, $realfile) + length($realfile) != length($spelling_file) && + # OpenOCD specific: End + ($in_commit_log || $line =~ /^(?:\+|Subject:)/i)) { + while ($rawline =~ /(?:^|[^\w\-'`])($misspellings)(?:[^\w\-'`]|$)/gi) { + my $typo = $1; + my $blank = copy_spacing($rawline); + my $ptr = substr($blank, 0, $-[1]) . "^" x length($typo); + my $hereptr = "$hereline$ptr\n"; + my $typo_fix = $spelling_fix{lc($typo)}; + $typo_fix = ucfirst($typo_fix) if ($typo =~ /^[A-Z]/); + $typo_fix = uc($typo_fix) if ($typo =~ /^[A-Z]+$/); + my $msg_level = \&WARN; + $msg_level = \&CHK if ($file); + if (&{$msg_level}("TYPO_SPELLING", + "'$typo' may be misspelled - perhaps '$typo_fix'?\n" . $hereptr) && + $fix) { + $fixed[$fixlinenr] =~ s/(^|[^A-Za-z@])($typo)($|[^A-Za-z@])/$1$typo_fix$3/; + } + } + } + +# check for invalid commit id + if ($in_commit_log && $line =~ /(^fixes:|\bcommit)\s+([0-9a-f]{6,40})\b/i) { + my $id; + my $description; + ($id, $description) = git_commit_info($2, undef, undef); + if (!defined($id)) { + WARN("UNKNOWN_COMMIT_ID", + "Unknown commit id '$2', maybe rebased or not pulled?\n" . $herecurr); + } + } + +# check for repeated words separated by a single space +# avoid false positive from list command eg, '-rw-r--r-- 1 root root' + if (($rawline =~ /^\+/ || $in_commit_log) && + $rawline !~ /[bcCdDlMnpPs\?-][rwxsStT-]{9}/) { + pos($rawline) = 1 if (!$in_commit_log); + while ($rawline =~ /\b($word_pattern) (?=($word_pattern))/g) { + + my $first = $1; + my $second = $2; + my $start_pos = $-[1]; + my $end_pos = $+[2]; + if ($first =~ /(?:struct|union|enum)/) { + pos($rawline) += length($first) + length($second) + 1; + next; + } + + next if (lc($first) ne lc($second)); + next if ($first eq 'long'); + + # check for character before and after the word matches + my $start_char = ''; + my $end_char = ''; + $start_char = substr($rawline, $start_pos - 1, 1) if ($start_pos > ($in_commit_log ? 0 : 1)); + $end_char = substr($rawline, $end_pos, 1) if ($end_pos < length($rawline)); + + next if ($start_char =~ /^\S$/); + next if (index(" \t.,;?!", $end_char) == -1); + + # avoid repeating hex occurrences like 'ff ff fe 09 ...' + if ($first =~ /\b[0-9a-f]{2,}\b/i) { + next if (!exists($allow_repeated_words{lc($first)})); + } + + if (WARN("REPEATED_WORD", + "Possible repeated word: '$first'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b$first $second\b/$first/; + } + } + + # if it's a repeated word on consecutive lines in a comment block + if ($prevline =~ /$;+\s*$/ && + $prevrawline =~ /($word_pattern)\s*$/) { + my $last_word = $1; + if ($rawline =~ /^\+\s*\*\s*$last_word /) { + if (WARN("REPEATED_WORD", + "Possible repeated word: '$last_word'\n" . $hereprev) && + $fix) { + $fixed[$fixlinenr] =~ s/(\+\s*\*\s*)$last_word /$1/; + } + } + } + } + # ignore non-hunk lines and lines being removed next if (!$hunk_line || $line =~ /^-/); #trailing whitespace if ($line =~ /^\+.*\015/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - ERROR("DOS_LINE_ENDINGS", - "DOS line endings\n" . $herevet); - + if (ERROR("DOS_LINE_ENDINGS", + "DOS line endings\n" . $herevet) && + $fix) { + $fixed[$fixlinenr] =~ s/[\s\015]+$//; + } } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - ERROR("TRAILING_WHITESPACE", - "trailing whitespace\n" . $herevet); + if (ERROR("TRAILING_WHITESPACE", + "trailing whitespace\n" . $herevet) && + $fix) { + $fixed[$fixlinenr] =~ s/\s+$//; + } + $rpt_cleaners = 1; } - # Don't care in this branch. This always messes up when we merge changes down. - #if ($rawline =~ /\bwrite to the Free/i || - # $rawline =~ /\b59\s+Temple\s+Pl/i || - # $rawline =~ /\b51\s+Franklin\s+St/i) { - # my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - # ERROR("FSF_MAILING_ADDRESS", - # "Do not include the paragraph about writing to the Free Software Foundation's mailing address " . - # "from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. " . - # "OpenOCD already includes a copy of the GPL.\n" . $herevet) - #} +# Check for FSF mailing addresses. + if ($rawline =~ /\bwrite to the Free/i || + $rawline =~ /\b675\s+Mass\s+Ave/i || + $rawline =~ /\b59\s+Temple\s+Pl/i || + $rawline =~ /\b51\s+Franklin\s+St/i) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + my $msg_level = \&ERROR; + $msg_level = \&CHK if ($file); + &{$msg_level}("FSF_MAILING_ADDRESS", + "Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. OpenOCD already includes a copy of the GPL.\n" . $herevet) + } # check for Kconfig help text having a real description # Only applies when adding the entry originally, after that we do not have # sufficient context to determine whether it is indeed long enough. if ($realfile =~ /Kconfig/ && - $line =~ /\+\s*(?:---)?help(?:---)?$/) { - my $length = 0; - my $cnt = $realcnt; - my $ln = $linenr + 1; - my $f; - my $is_end = 0; - while ($cnt > 0 && defined $lines[$ln - 1]) { - $f = $lines[$ln - 1]; - $cnt-- if ($lines[$ln - 1] !~ /^-/); - $is_end = $lines[$ln - 1] =~ /^\+/; - $ln++; + # 'choice' is usually the last thing on the line (though + # Kconfig supports named choices), so use a word boundary + # (\b) rather than a whitespace character (\s) + $line =~ /^\+\s*(?:config|menuconfig|choice)\b/) { + my $ln = $linenr; + my $needs_help = 0; + my $has_help = 0; + my $help_length = 0; + while (defined $lines[$ln]) { + my $f = $lines[$ln++]; next if ($f =~ /^-/); - $f =~ s/^.//; - $f =~ s/#.*//; - $f =~ s/^\s+//; - next if ($f =~ /^$/); - if ($f =~ /^\s*config\s/) { - $is_end = 1; + last if ($f !~ /^[\+ ]/); # !patch context + + if ($f =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) { + $needs_help = 1; + next; + } + if ($f =~ /^\+\s*help\s*$/) { + $has_help = 1; + next; + } + + $f =~ s/^.//; # strip patch context [+ ] + $f =~ s/#.*//; # strip # directives + $f =~ s/^\s+//; # strip leading blanks + next if ($f =~ /^$/); # skip blank lines + + # At the end of this Kconfig block: + # This only checks context lines in the patch + # and so hopefully shouldn't trigger false + # positives, even though some of these are + # common words in help texts + if ($f =~ /^(?:config|menuconfig|choice|endchoice| + if|endif|menu|endmenu|source)\b/x) { last; } - $length++; + $help_length++ if ($has_help); + } + if ($needs_help && + $help_length < $min_conf_desc_length) { + my $stat_real = get_stat_real($linenr, $ln - 1); + WARN("CONFIG_DESCRIPTION", + "please write a help paragraph that fully describes the config symbol\n" . "$here\n$stat_real\n"); + } + } + +# check MAINTAINERS entries + if ($realfile =~ /^MAINTAINERS$/) { +# check MAINTAINERS entries for the right form + if ($rawline =~ /^\+[A-Z]:/ && + $rawline !~ /^\+[A-Z]:\t\S/) { + if (WARN("MAINTAINERS_STYLE", + "MAINTAINERS entries use one tab after TYPE:\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/^(\+[A-Z]):\s*/$1:\t/; + } + } +# check MAINTAINERS entries for the right ordering too + my $preferred_order = 'MRLSWQBCPTFXNK'; + if ($rawline =~ /^\+[A-Z]:/ && + $prevrawline =~ /^[\+ ][A-Z]:/) { + $rawline =~ /^\+([A-Z]):\s*(.*)/; + my $cur = $1; + my $curval = $2; + $prevrawline =~ /^[\+ ]([A-Z]):\s*(.*)/; + my $prev = $1; + my $prevval = $2; + my $curindex = index($preferred_order, $cur); + my $previndex = index($preferred_order, $prev); + if ($curindex < 0) { + WARN("MAINTAINERS_STYLE", + "Unknown MAINTAINERS entry type: '$cur'\n" . $herecurr); + } else { + if ($previndex >= 0 && $curindex < $previndex) { + WARN("MAINTAINERS_STYLE", + "Misordered MAINTAINERS entry - list '$cur:' before '$prev:'\n" . $hereprev); + } elsif ((($prev eq 'F' && $cur eq 'F') || + ($prev eq 'X' && $cur eq 'X')) && + ($prevval cmp $curval) > 0) { + WARN("MAINTAINERS_STYLE", + "Misordered MAINTAINERS entry - list file patterns in alphabetic order\n" . $hereprev); + } + } + } + } + + if (($realfile =~ /Makefile.*/ || $realfile =~ /Kbuild.*/) && + ($line =~ /\+(EXTRA_[A-Z]+FLAGS).*/)) { + my $flag = $1; + my $replacement = { + 'EXTRA_AFLAGS' => 'asflags-y', + 'EXTRA_CFLAGS' => 'ccflags-y', + 'EXTRA_CPPFLAGS' => 'cppflags-y', + 'EXTRA_LDFLAGS' => 'ldflags-y', + }; + + WARN("DEPRECATED_VARIABLE", + "Use of $flag is deprecated, please use \`$replacement->{$flag} instead.\n" . $herecurr) if ($replacement->{$flag}); + } + +# check for DT compatible documentation + if (defined $root && + (($realfile =~ /\.dtsi?$/ && $line =~ /^\+\s*compatible\s*=\s*\"/) || + ($realfile =~ /\.[ch]$/ && $line =~ /^\+.*\.compatible\s*=\s*\"/))) { + + my @compats = $rawline =~ /\"([a-zA-Z0-9\-\,\.\+_]+)\"/g; + + my $dt_path = $root . "/Documentation/devicetree/bindings/"; + my $vp_file = $dt_path . "vendor-prefixes.yaml"; + + foreach my $compat (@compats) { + my $compat2 = $compat; + $compat2 =~ s/\,[a-zA-Z0-9]*\-/\,<\.\*>\-/; + my $compat3 = $compat; + $compat3 =~ s/\,([a-z]*)[0-9]*\-/\,$1<\.\*>\-/; + `grep -Erq "$compat|$compat2|$compat3" $dt_path`; + if ( $? >> 8 ) { + WARN("UNDOCUMENTED_DT_STRING", + "DT compatible string \"$compat\" appears un-documented -- check $dt_path\n" . $herecurr); + } + + next if $compat !~ /^([a-zA-Z0-9\-]+)\,/; + my $vendor = $1; + `grep -Eq "\\"\\^\Q$vendor\E,\\.\\*\\":" $vp_file`; + if ( $? >> 8 ) { + WARN("UNDOCUMENTED_DT_STRING", + "DT compatible string vendor \"$vendor\" appears un-documented -- check $vp_file\n" . $herecurr); + } } - WARN("CONFIG_DESCRIPTION", - "please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($is_end && $length < 4); - #print "is_end<$is_end> length<$length>\n"; + } + +# check for using SPDX license tag at beginning of files + if ($realline == $checklicenseline) { + if ($rawline =~ /^[ \+]\s*\#\!\s*\//) { + $checklicenseline = 2; + } elsif ($rawline =~ /^\+/) { + my $comment = ""; + if ($realfile =~ /\.(h|s|S)$/) { + $comment = '/*'; + } elsif ($realfile =~ /\.(c|dts|dtsi)$/) { + $comment = '//'; + } elsif (($checklicenseline == 2) || $realfile =~ /\.(sh|pl|py|awk|tc|yaml)$/) { + $comment = '#'; + } elsif ($realfile =~ /\.rst$/) { + $comment = '..'; + # OpenOCD specific: Begin + } elsif ($realfile =~ /\.(am|cfg|tcl)$/) { + $comment = '#'; + # OpenOCD specific: End + } + +# check SPDX comment style for .[chsS] files + if ($realfile =~ /\.[chsS]$/ && + $rawline =~ /SPDX-License-Identifier:/ && + $rawline !~ m@^\+\s*\Q$comment\E\s*@) { + WARN("SPDX_LICENSE_TAG", + "Improper SPDX comment style for '$realfile', please use '$comment' instead\n" . $herecurr); + } + + if ($comment !~ /^$/ && + $rawline !~ m@^\+\Q$comment\E SPDX-License-Identifier: @) { + WARN("SPDX_LICENSE_TAG", + "Missing or malformed SPDX-License-Identifier tag in line $checklicenseline\n" . $herecurr); + } elsif ($rawline =~ /(SPDX-License-Identifier: .*)/) { + my $spdx_license = $1; + if (!is_SPDX_License_valid($spdx_license)) { + WARN("SPDX_LICENSE_TAG", + "'$spdx_license' is not supported in LICENSES/...\n" . $herecurr); + } + if ($realfile =~ m@^Documentation/devicetree/bindings/@ && + not $spdx_license =~ /GPL-2\.0.*BSD-2-Clause/) { + my $msg_level = \&WARN; + $msg_level = \&CHK if ($file); + if (&{$msg_level}("SPDX_LICENSE_TAG", + + "DT binding documents should be licensed (GPL-2.0-only OR BSD-2-Clause)\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/SPDX-License-Identifier: .*/SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)/; + } + } + } + } + } + +# check for embedded filenames + if ($rawline =~ /^\+.*\Q$realfile\E/) { + WARN("EMBEDDED_FILENAME", + "It's generally not useful to have the filename in the file\n" . $herecurr); } # check we are in a valid source file if not then ignore this hunk - next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/); - -#120 column limit - if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ && - $rawline !~ /^.\s*\*\s*\@$Ident\s/ && - !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:|,|\)\s*;)\s*$/ || - $line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) && - $length > 120) - { - WARN("LONG_LINE", - "line over 120 characters\n" . $herecurr); + next if ($realfile !~ /\.(h|c|s|S|sh|dtsi|dts)$/); + +# check for using SPDX-License-Identifier on the wrong line number + if ($realline != $checklicenseline && + $rawline =~ /\bSPDX-License-Identifier:/ && + substr($line, @-, @+ - @-) eq "$;" x (@+ - @-)) { + WARN("SPDX_LICENSE_TAG", + "Misplaced SPDX-License-Identifier tag - use line $checklicenseline instead\n" . $herecurr); } -# check for spaces before a quoted newline - if ($rawline =~ /^.*\".*\s\\n/) { - WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE", - "unnecessary whitespace before a quoted newline\n" . $herecurr); +# line length limit (with some exclusions) +# +# There are a few types of lines that may extend beyond $max_line_length: +# logging functions like pr_info that end in a string +# lines with a single string +# #defines that are a single string +# lines with an RFC3986 like URL +# +# There are 3 different line length message types: +# LONG_LINE_COMMENT a comment starts before but extends beyond $max_line_length +# LONG_LINE_STRING a string starts before but extends beyond $max_line_length +# LONG_LINE all other lines longer than $max_line_length +# +# if LONG_LINE is ignored, the other 2 types are also ignored +# + + if ($line =~ /^\+/ && $length > $max_line_length) { + my $msg_type = "LONG_LINE"; + + # Check the allowed long line types first + + # logging functions that end in a string that starts + # before $max_line_length + if ($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(?:KERN_\S+\s*|[^"]*))?($String\s*(?:|,|\)\s*;)\s*)$/ && + length(expand_tabs(substr($line, 1, length($line) - length($1) - 1))) <= $max_line_length) { + $msg_type = ""; + + # lines with only strings (w/ possible termination) + # #defines with only strings + } elsif ($line =~ /^\+\s*$String\s*(?:\s*|,|\)\s*;)\s*$/ || + $line =~ /^\+\s*#\s*define\s+\w+\s+$String$/) { + $msg_type = ""; + + # More special cases + } elsif ($line =~ /^\+.*\bEFI_GUID\s*\(/ || + $line =~ /^\+\s*(?:\w+)?\s*DEFINE_PER_CPU/) { + $msg_type = ""; + + # URL ($rawline is used in case the URL is in a comment) + } elsif ($rawline =~ /^\+.*\b[a-z][\w\.\+\-]*:\/\/\S+/i) { + $msg_type = ""; + + # Otherwise set the alternate message types + + # a comment starts before $max_line_length + } elsif ($line =~ /($;[\s$;]*)$/ && + length(expand_tabs(substr($line, 1, length($line) - length($1) - 1))) <= $max_line_length) { + $msg_type = "LONG_LINE_COMMENT" + + # a quoted string starts before $max_line_length + } elsif ($sline =~ /\s*($String(?:\s*(?:\\|,\s*|\)\s*;\s*))?)$/ && + length(expand_tabs(substr($line, 1, length($line) - length($1) - 1))) <= $max_line_length) { + $msg_type = "LONG_LINE_STRING" + } + + if ($msg_type ne "" && + (show_type("LONG_LINE") || show_type($msg_type))) { + my $msg_level = \&WARN; + $msg_level = \&CHK if ($file); + &{$msg_level}($msg_type, + "line length of $length exceeds $max_line_length columns\n" . $herecurr); + } } # check for adding lines without a newline. if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) { - WARN("MISSING_EOF_NEWLINE", - "adding a line without newline at end of file\n" . $herecurr); + if (WARN("MISSING_EOF_NEWLINE", + "adding a line without newline at end of file\n" . $herecurr) && + $fix) { + fix_delete_line($fixlinenr+1, "No newline at end of file"); + } } -# Blackfin: use hi/lo macros - if ($realfile =~ m@arch/blackfin/.*\.S$@) { - if ($line =~ /\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("LO_MACRO", - "use the LO() macro, not (... & 0xFFFF)\n" . $herevet); - } - if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("HI_MACRO", - "use the HI() macro, not (... >> 16)\n" . $herevet); - } +# check for .L prefix local symbols in .S files + if ($realfile =~ /\.S$/ && + $line =~ /^\+\s*(?:[A-Z]+_)?SYM_[A-Z]+_(?:START|END)(?:_[A-Z_]+)?\s*\(\s*\.L/) { + WARN("AVOID_L_PREFIX", + "Avoid using '.L' prefixed local symbol names for denoting a range of code via 'SYM_*_START/END' annotations; see Documentation/asm-annotations.rst\n" . $herecurr); } # check we are in a valid source file C or perl if not then ignore this hunk - next if ($realfile !~ /\.(h|c|pl)$/); + next if ($realfile !~ /\.(h|c|pl|dtsi|dts)$/); # at the beginning of a line any tabs must come first and anything -# more than 8 must use tabs. +# more than $tabsize must use tabs. if ($rawline =~ /^\+\s* \t\s*\S/ || $rawline =~ /^\+\s* \s*/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - ERROR("CODE_INDENT", - "code indent should use tabs where possible\n" . $herevet); $rpt_cleaners = 1; + if (ERROR("CODE_INDENT", + "code indent should use tabs where possible\n" . $herevet) && + $fix) { + $fixed[$fixlinenr] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e; + } } # check for space before tabs. if ($rawline =~ /^\+/ && $rawline =~ / \t/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - WARN("SPACE_BEFORE_TAB", - "please, no space before tabs\n" . $herevet); + if (WARN("SPACE_BEFORE_TAB", + "please, no space before tabs\n" . $herevet) && + $fix) { + while ($fixed[$fixlinenr] =~ + s/(^\+.*) {$tabsize,$tabsize}\t/$1\t\t/) {} + while ($fixed[$fixlinenr] =~ + s/(^\+.*) +\t/$1\t/) {} + } } -# check we are in a valid C source file if not then ignore this hunk - next if ($realfile !~ /\.(h|c)$/); +# check for assignments on the start of a line + if ($sline =~ /^\+\s+($Assignment)[^=]/) { + my $operator = $1; + if (CHK("ASSIGNMENT_CONTINUATIONS", + "Assignment operator '$1' should be on the previous line\n" . $hereprev) && + $fix && $prevrawline =~ /^\+/) { + # add assignment operator to the previous line, remove from current line + $fixed[$fixlinenr - 1] .= " $operator"; + $fixed[$fixlinenr] =~ s/\Q$operator\E\s*//; + } + } + +# check for && or || at the start of a line + if ($rawline =~ /^\+\s*(&&|\|\|)/) { + my $operator = $1; + if (CHK("LOGICAL_CONTINUATIONS", + "Logical continuations should be on the previous line\n" . $hereprev) && + $fix && $prevrawline =~ /^\+/) { + # insert logical operator at last non-comment, non-whitepsace char on previous line + $prevline =~ /[\s$;]*$/; + my $line_end = substr($prevrawline, $-[0]); + $fixed[$fixlinenr - 1] =~ s/\Q$line_end\E$/ $operator$line_end/; + $fixed[$fixlinenr] =~ s/\Q$operator\E\s*//; + } + } + +# check indentation starts on a tab stop + if ($perl_version_ok && + $sline =~ /^\+\t+( +)(?:$c90_Keywords\b|\{\s*$|\}\s*(?:else\b|while\b|\s*$)|$Declare\s*$Ident\s*[;=])/) { + my $indent = length($1); + if ($indent % $tabsize) { + if (WARN("TABSTOP", + "Statements should start on a tabstop\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s@(^\+\t+) +@$1 . "\t" x ($indent/$tabsize)@e; + } + } + } + +# check multi-line statement indentation matches previous line + if ($perl_version_ok && + $prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|(?:\*\s*)*$Lval\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) { + $prevline =~ /^\+(\t*)(.*)$/; + my $oldindent = $1; + my $rest = $2; + + my $pos = pos_last_openparen($rest); + if ($pos >= 0) { + $line =~ /^(\+| )([ \t]*)/; + my $newindent = $2; + + my $goodtabindent = $oldindent . + "\t" x ($pos / $tabsize) . + " " x ($pos % $tabsize); + my $goodspaceindent = $oldindent . " " x $pos; + + if ($newindent ne $goodtabindent && + $newindent ne $goodspaceindent) { + + if (CHK("PARENTHESIS_ALIGNMENT", + "Alignment should match open parenthesis\n" . $hereprev) && + $fix && $line =~ /^\+/) { + $fixed[$fixlinenr] =~ + s/^\+[ \t]*/\+$goodtabindent/; + } + } + } + } + +# check for space after cast like "(int) foo" or "(struct foo) bar" +# avoid checking a few false positives: +# "sizeof(<type>)" or "__alignof__(<type>)" +# function pointer declarations like "(*foo)(int) = bar;" +# structure definitions like "(struct foo) { 0 };" +# multiline macros that define functions +# known attributes or the __attribute__ keyword + if ($line =~ /^\+(.*)\(\s*$Type\s*\)([ \t]++)((?![={]|\\$|$Attribute|__attribute__))/ && + (!defined($1) || $1 !~ /\b(?:sizeof|__alignof__)\s*$/)) { + if (CHK("SPACING", + "No space is necessary after a cast\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/(\(\s*$Type\s*\))[ \t]+/$1/; + } + } + +# Block comment styles +# Networking with an initial /* + if ($realfile =~ m@^(drivers/net/|net/)@ && + $prevrawline =~ /^\+[ \t]*\/\*[ \t]*$/ && + $rawline =~ /^\+[ \t]*\*/ && + $realline > 3) { # Do not warn about the initial copyright comment block after SPDX-License-Identifier + WARN("NETWORKING_BLOCK_COMMENT_STYLE", + "networking block comments don't use an empty /* line, use /* Comment...\n" . $hereprev); + } + +# Block comments use * on subsequent lines + if ($prevline =~ /$;[ \t]*$/ && #ends in comment + $prevrawline =~ /^\+.*?\/\*/ && #starting /* + $prevrawline !~ /\*\/[ \t]*$/ && #no trailing */ + $rawline =~ /^\+/ && #line is new + $rawline !~ /^\+[ \t]*\*/) { #no leading * + WARN("BLOCK_COMMENT_STYLE", + "Block comments use * on subsequent lines\n" . $hereprev); + } + +# Block comments use */ on trailing lines + if ($rawline !~ m@^\+[ \t]*\*/[ \t]*$@ && #trailing */ + $rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ && #inline /*...*/ + $rawline !~ m@^\+.*\*{2,}/[ \t]*$@ && #trailing **/ + $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) { #non blank */ + WARN("BLOCK_COMMENT_STYLE", + "Block comments use a trailing */ on a separate line\n" . $herecurr); + } + +# Block comment * alignment + if ($prevline =~ /$;[ \t]*$/ && #ends in comment + $line =~ /^\+[ \t]*$;/ && #leading comment + $rawline =~ /^\+[ \t]*\*/ && #leading * + (($prevrawline =~ /^\+.*?\/\*/ && #leading /* + $prevrawline !~ /\*\/[ \t]*$/) || #no trailing */ + $prevrawline =~ /^\+[ \t]*\*/)) { #leading * + my $oldindent; + $prevrawline =~ m@^\+([ \t]*/?)\*@; + if (defined($1)) { + $oldindent = expand_tabs($1); + } else { + $prevrawline =~ m@^\+(.*/?)\*@; + $oldindent = expand_tabs($1); + } + $rawline =~ m@^\+([ \t]*)\*@; + my $newindent = $1; + $newindent = expand_tabs($newindent); + if (length($oldindent) ne length($newindent)) { + WARN("BLOCK_COMMENT_STYLE", + "Block comments should align the * on each line\n" . $hereprev); + } + } + +# check for missing blank lines after struct/union declarations +# with exceptions for various attributes and macros + if ($prevline =~ /^[\+ ]};?\s*$/ && + $line =~ /^\+/ && + !($line =~ /^\+\s*$/ || + $line =~ /^\+\s*(?:EXPORT_SYMBOL|early_param)/ || + $line =~ /^\+\s*MODULE_/i || + $line =~ /^\+\s*\#\s*(?:end|elif|else)/ || + $line =~ /^\+[a-z_]*init/ || + $line =~ /^\+\s*(?:static\s+)?[A-Z_]*ATTR/ || + $line =~ /^\+\s*DECLARE/ || + $line =~ /^\+\s*builtin_[\w_]*driver/ || + $line =~ /^\+\s*__setup/)) { + if (CHK("LINE_SPACING", + "Please use a blank line after function/struct/union/enum declarations\n" . $hereprev) && + $fix) { + fix_insert_line($fixlinenr, "\+"); + } + } + +# check for multiple consecutive blank lines + if ($prevline =~ /^[\+ ]\s*$/ && + $line =~ /^\+\s*$/ && + $last_blank_line != ($linenr - 1)) { + if (CHK("LINE_SPACING", + "Please don't use multiple blank lines\n" . $hereprev) && + $fix) { + fix_delete_line($fixlinenr, $rawline); + } + + $last_blank_line = $linenr; + } + +# check for missing blank lines after declarations +# (declarations must have the same indentation and not be at the start of line) + if (($prevline =~ /\+(\s+)\S/) && $sline =~ /^\+$1\S/) { + # use temporaries + my $sl = $sline; + my $pl = $prevline; + # remove $Attribute/$Sparse uses to simplify comparisons + $sl =~ s/\b(?:$Attribute|$Sparse)\b//g; + $pl =~ s/\b(?:$Attribute|$Sparse)\b//g; + if (($pl =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ || + # function pointer declarations + $pl =~ /^\+\s+$Declare\s*\(\s*\*\s*$Ident\s*\)\s*[=,;:\[\(]/ || + # foo bar; where foo is some local typedef or #define + $pl =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ || + # known declaration macros + $pl =~ /^\+\s+$declaration_macros/) && + # for "else if" which can look like "$Ident $Ident" + !($pl =~ /^\+\s+$c90_Keywords\b/ || + # other possible extensions of declaration lines + $pl =~ /(?:$Compare|$Assignment|$Operators)\s*$/ || + # not starting a section or a macro "\" extended line + $pl =~ /(?:\{\s*|\\)$/) && + # looks like a declaration + !($sl =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ || + # function pointer declarations + $sl =~ /^\+\s+$Declare\s*\(\s*\*\s*$Ident\s*\)\s*[=,;:\[\(]/ || + # foo bar; where foo is some local typedef or #define + $sl =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ || + # known declaration macros + $sl =~ /^\+\s+$declaration_macros/ || + # start of struct or union or enum + $sl =~ /^\+\s+(?:static\s+)?(?:const\s+)?(?:union|struct|enum|typedef)\b/ || + # start or end of block or continuation of declaration + $sl =~ /^\+\s+(?:$|[\{\}\.\#\"\?\:\(\[])/ || + # bitfield continuation + $sl =~ /^\+\s+$Ident\s*:\s*\d+\s*[,;]/ || + # other possible extensions of declaration lines + $sl =~ /^\+\s+\(?\s*(?:$Compare|$Assignment|$Operators)/)) { + if (WARN("LINE_SPACING", + "Missing a blank line after declarations\n" . $hereprev) && + $fix) { + fix_insert_line($fixlinenr, "\+"); + } + } + } # check for spaces at the beginning of a line. # Exceptions: # 1) within comments # 2) indented preprocessor commands # 3) hanging labels - if ($rawline =~ /^\+ / && $line !~ /\+ *(?:$;|#|$Ident:)/) { + if ($rawline =~ /^\+ / && $line !~ /^\+ *(?:$;|#|$Ident:)/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - WARN("LEADING_SPACE", - "please, no spaces at the start of a line\n" . $herevet); + if (WARN("LEADING_SPACE", + "please, no spaces at the start of a line\n" . $herevet) && + $fix) { + $fixed[$fixlinenr] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e; + } + } + +# check we are in a valid C source file if not then ignore this hunk + next if ($realfile !~ /\.(h|c)$/); + +# check for unusual line ending [ or ( + if ($line =~ /^\+.*([\[\(])\s*$/) { + CHK("OPEN_ENDED_LINE", + "Lines should not end with a '$1'\n" . $herecurr); + } + +# check if this appears to be the start function declaration, save the name + if ($sline =~ /^\+\{\s*$/ && + $prevline =~ /^\+(?:(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*)?($Ident)\(/) { + $context_function = $1; + } + +# check if this appears to be the end of function declaration + if ($sline =~ /^\+\}\s*$/) { + undef $context_function; + } + +# check indentation of any line with a bare else +# (but not if it is a multiple line "if (foo) return bar; else return baz;") +# if the previous line is a break or return and is indented 1 tab more... + if ($sline =~ /^\+([\t]+)(?:}[ \t]*)?else(?:[ \t]*{)?\s*$/) { + my $tabs = length($1) + 1; + if ($prevline =~ /^\+\t{$tabs,$tabs}break\b/ || + ($prevline =~ /^\+\t{$tabs,$tabs}return\b/ && + defined $lines[$linenr] && + $lines[$linenr] !~ /^[ \+]\t{$tabs,$tabs}return/)) { + WARN("UNNECESSARY_ELSE", + "else is not generally useful after a break or return\n" . $hereprev); + } + } + +# check indentation of a line with a break; +# if the previous line is a goto, return or break +# and is indented the same # of tabs + if ($sline =~ /^\+([\t]+)break\s*;\s*$/) { + my $tabs = $1; + if ($prevline =~ /^\+$tabs(goto|return|break)\b/) { + if (WARN("UNNECESSARY_BREAK", + "break is not useful after a $1\n" . $hereprev) && + $fix) { + fix_delete_line($fixlinenr, $rawline); + } + } } # check for RCS/CVS revision markers @@ -1754,27 +4174,33 @@ sub process { "CVS style keyword markers, these will _not_ be updated\n". $herecurr); } -# Blackfin: don't use __builtin_bfin_[cs]sync - if ($line =~ /__builtin_bfin_csync/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("CSYNC", - "use the CSYNC() macro in asm/blackfin.h\n" . $herevet); - } - if ($line =~ /__builtin_bfin_ssync/) { - my $herevet = "$here\n" . cat_vet($line) . "\n"; - ERROR("SSYNC", - "use the SSYNC() macro in asm/blackfin.h\n" . $herevet); +# check for old HOTPLUG __dev<foo> section markings + if ($line =~ /\b(__dev(init|exit)(data|const|))\b/) { + WARN("HOTPLUG_SECTION", + "Using $1 is unnecessary\n" . $herecurr); } # Check for potential 'bare' types my ($stat, $cond, $line_nr_next, $remain_next, $off_next, $realline_next); - if ($realcnt && $line =~ /.\s*\S/) { +#print "LINE<$line>\n"; + if ($linenr > $suppress_statement && + $realcnt && $sline =~ /.\s*\S/) { ($stat, $cond, $line_nr_next, $remain_next, $off_next) = ctx_statement_block($linenr, $realcnt, 0); $stat =~ s/\n./\n /g; $cond =~ s/\n./\n /g; +#print "linenr<$linenr> <$stat>\n"; + # If this statement has no statement boundaries within + # it there is no point in retrying a statement scan + # until we hit end of it. + my $frag = $stat; $frag =~ s/;+\s*$//; + if ($frag !~ /(?:{|;)/) { +#print "skip<$line_nr_next>\n"; + $suppress_statement = $line_nr_next; + } + # Find the real next line. $realline_next = $line_nr_next; if (defined $realline_next && @@ -1784,7 +4210,7 @@ sub process { } my $s = $stat; - $s =~ s/\{.*$//s; + $s =~ s/{.*$//s; # Ignore goto labels. if ($s =~ /$Ident:\*$/s) { @@ -1836,33 +4262,41 @@ sub process { # Check for switch () and associated case and default # statements should be at the same indent. -# if ($line=~/\bswitch\s*\(.*\)/) { -# my $err = ''; -# my $sep = ''; -# my @ctx = ctx_block_outer($linenr, $realcnt); -# shift(@ctx); -# for my $ctx (@ctx) { -# my ($clen, $cindent) = line_stats($ctx); -# if ($ctx =~ /^\+\s*(case\s+|default:)/ && -# $indent != $cindent) { -# $err .= "$sep$ctx\n"; -# $sep = ''; -# } else { -# $sep = "[...]\n"; -# } -# } -# if ($err ne '') { -# ERROR("SWITCH_CASE_INDENT_LEVEL", -# "switch and case should be at the same indent\n$hereline$err"); -# } -# } + if ($line=~/\bswitch\s*\(.*\)/) { + my $err = ''; + my $sep = ''; + my @ctx = ctx_block_outer($linenr, $realcnt); + shift(@ctx); + for my $ctx (@ctx) { + my ($clen, $cindent) = line_stats($ctx); + if ($ctx =~ /^\+\s*(case\s+|default:)/ && + $indent != $cindent) { + $err .= "$sep$ctx\n"; + $sep = ''; + } else { + $sep = "[...]\n"; + } + } + if ($err ne '') { + ERROR("SWITCH_CASE_INDENT_LEVEL", + "switch and case should be at the same indent\n$hereline$err"); + } + } # if/while/etc brace do not go on next line, unless defining a do while loop, # or if that brace on the next line is for something else - if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) { + if ($line =~ /(.*)\b((?:if|while|for|switch|(?:[a-z_]+|)for_each[a-z_]+)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) { my $pre_ctx = "$1$2"; my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0); + + # OpenOCD specific: Begin: replace s/6/10/ + if ($line =~ /^\+\t{10,}/) { + # OpenOCD specific: End + WARN("DEEP_INDENTATION", + "Too many leading tabs - consider code refactoring\n" . $herecurr); + } + my $ctx_cnt = $realcnt - $#ctx - 1; my $ctx = join("\n", @ctx); @@ -1880,7 +4314,7 @@ sub process { #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n"; #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n"; - if ($ctx !~ /\{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*\{/) { + if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln - 1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) { ERROR("OPEN_BRACE", "that open brace { should be on the previous line\n" . "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); @@ -1899,20 +4333,30 @@ sub process { } # Check relative indent for conditionals and blocks. - if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) { + if ($line =~ /\b(?:(?:if|while|for|(?:[a-z_]+|)for_each[a-z_]+)\s*\(|(?:do|else)\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) { + ($stat, $cond, $line_nr_next, $remain_next, $off_next) = + ctx_statement_block($linenr, $realcnt, 0) + if (!defined $stat); my ($s, $c) = ($stat, $cond); substr($s, 0, length($c), ''); - # Make sure we remove the line prefixes as we have - # none on the first line, and are going to readd them - # where necessary. - $s =~ s/\n./\n/gs; + # remove inline comments + $s =~ s/$;/ /g; + $c =~ s/$;/ /g; # Find out how long the conditional actually is. my @newlines = ($c =~ /\n/gs); my $cond_lines = 1 + $#newlines; + # Make sure we remove the line prefixes as we have + # none on the first line, and are going to readd them + # where necessary. + $s =~ s/\n./\n/gs; + while ($s =~ /\n\s+\\\n/) { + $cond_lines += $s =~ s/\n\s+\\\n/\n/g; + } + # We want to check the first line inside the block # starting at the end of the conditional, so remove: # 1) any blank line termination @@ -1921,7 +4365,7 @@ sub process { my $continuation = 0; my $check = 0; $s =~ s/^.*\bdo\b//; - $s =~ s/^\s*\{//; + $s =~ s/^\s*{//; if ($s =~ s/^\s*\\//) { $continuation = 1; } @@ -1978,8 +4422,12 @@ sub process { #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n"; - if ($check && (($sindent % 4) != 0 || - ($sindent <= $indent && $s ne ''))) { + if ($check && $s ne '' && + (($sindent % $tabsize) != 0 || + ($sindent < $indent) || + ($sindent == $indent && + ($s !~ /^\s*(?:\}|\{|else\b)/)) || + ($sindent > $indent + $tabsize))) { WARN("SUSPECT_CODE_INDENT", "suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n"); } @@ -1999,7 +4447,54 @@ sub process { $prev_values = substr($curr_values, -1); #ignore lines not being added - if ($line=~/^[^\+]/) {next;} + next if ($line =~ /^[^\+]/); + +# check for self assignments used to avoid compiler warnings +# e.g.: int foo = foo, *bar = NULL; +# struct foo bar = *(&(bar)); + if ($line =~ /^\+\s*(?:$Declare)?([A-Za-z_][A-Za-z\d_]*)\s*=/) { + my $var = $1; + if ($line =~ /^\+\s*(?:$Declare)?$var\s*=\s*(?:$var|\*\s*\(?\s*&\s*\(?\s*$var\s*\)?\s*\)?)\s*[;,]/) { + WARN("SELF_ASSIGNMENT", + "Do not use self-assignments to avoid compiler warnings\n" . $herecurr); + } + } + +# check for dereferences that span multiple lines + if ($prevline =~ /^\+.*$Lval\s*(?:\.|->)\s*$/ && + $line =~ /^\+\s*(?!\#\s*(?!define\s+|if))\s*$Lval/) { + $prevline =~ /($Lval\s*(?:\.|->))\s*$/; + my $ref = $1; + $line =~ /^.\s*($Lval)/; + $ref .= $1; + $ref =~ s/\s//g; + WARN("MULTILINE_DEREFERENCE", + "Avoid multiple line dereference - prefer '$ref'\n" . $hereprev); + } + +# check for declarations of signed or unsigned without int + while ($line =~ m{\b($Declare)\s*(?!char\b|short\b|int\b|long\b)\s*($Ident)?\s*[=,;\[\)\(]}g) { + my $type = $1; + my $var = $2; + $var = "" if (!defined $var); + if ($type =~ /^(?:(?:$Storage|$Inline|$Attribute)\s+)*((?:un)?signed)((?:\s*\*)*)\s*$/) { + my $sign = $1; + my $pointer = $2; + + $pointer = "" if (!defined $pointer); + + if (WARN("UNSPECIFIED_INT", + "Prefer '" . trim($sign) . " int" . rtrim($pointer) . "' to bare use of '$sign" . rtrim($pointer) . "'\n" . $herecurr) && + $fix) { + my $decl = trim($sign) . " int "; + my $comp_pointer = $pointer; + $comp_pointer =~ s/\s//g; + $decl .= $comp_pointer; + $decl = rtrim($decl) if ($var eq ""); + $fixed[$fixlinenr] =~ s@\b$sign\s*\Q$pointer\E\s*$var\b@$decl$var@; + } + } + } # TEST: allow direct testing of the type matcher. if ($dbg_type) { @@ -2025,10 +4520,20 @@ sub process { } # check for initialisation to aggregates open brace on the next line - if ($line =~ /^.\s*\{/ && + if ($line =~ /^.\s*{/ && $prevline =~ /(?:^|[^=])=\s*$/) { - ERROR("OPEN_BRACE", - "that open brace { should be on the previous line\n" . $hereprev); + if (ERROR("OPEN_BRACE", + "that open brace { should be on the previous line\n" . $hereprev) && + $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { + fix_delete_line($fixlinenr - 1, $prevrawline); + fix_delete_line($fixlinenr, $rawline); + my $fixedline = $prevrawline; + $fixedline =~ s/\s*=\s*$/ = {/; + fix_insert_line($fixlinenr, $fixedline); + $fixedline = $line; + $fixedline =~ s/^(.\s*)\{\s*/$1/; + fix_insert_line($fixlinenr, $fixedline); + } } # @@ -2040,15 +4545,25 @@ sub process { my $path = $1; if ($path =~ m{//}) { ERROR("MALFORMED_INCLUDE", - "malformed #include filename\n" . - $herecurr); + "malformed #include filename\n" . $herecurr); + } + if ($path =~ "^uapi/" && $realfile =~ m@\binclude/uapi/@) { + ERROR("UAPI_INCLUDE", + "No #include in ...include/uapi/... should use a uapi/ path prefix\n" . $herecurr); } } # no C99 // comments if ($line =~ m{//}) { - ERROR("C99_COMMENTS", - "do not use C99 // comments\n" . $herecurr); + if (ERROR("C99_COMMENTS", + "do not use C99 // comments\n" . $herecurr) && + $fix) { + my $line = $fixed[$fixlinenr]; + if ($line =~ /\/\/(.*)$/) { + my $comment = trim($1); + $fixed[$fixlinenr] =~ s@\/\/(.*)$@/\* $comment \*/@; + } + } } # Remove C99 comments. $line =~ s@//.*@@; @@ -2060,14 +4575,14 @@ sub process { if (defined $realline_next && exists $lines[$realline_next - 1] && !defined $suppress_export{$realline_next} && - ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ || - $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { + ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/)) { # Handle definitions which produce identifiers with # a prefix: # XXX(foo); # EXPORT_SYMBOL(something_foo); my $name = $1; - if ($stat =~ /^.([A-Z_]+)\s*\(\s*($Ident)/ && + $name =~ s/^\s*($Ident).*/$1/; + if ($stat =~ /^(?:.\s*}\s*\n)?.([A-Z_]+)\s*\(\s*($Ident)/ && $name =~ /^${Ident}_$2/) { #print "FOO C name<$name>\n"; $suppress_export{$realline_next} = 1; @@ -2088,8 +4603,7 @@ sub process { } if (!defined $suppress_export{$linenr} && $prevline =~ /^.\s*$/ && - ($line =~ /EXPORT_SYMBOL.*\((.*)\)/ || - $line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { + ($line =~ /EXPORT_SYMBOL.*\((.*)\)/)) { #print "FOO B <$lines[$linenr - 1]>\n"; $suppress_export{$linenr} = 2; } @@ -2100,16 +4614,49 @@ sub process { } # check for global initialisers. - if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) { - ERROR("GLOBAL_INITIALISERS", - "do not initialise globals to 0 or NULL\n" . - $herecurr); + if ($line =~ /^\+$Type\s*$Ident(?:\s+$Modifier)*\s*=\s*($zero_initializer)\s*;/ && + !exclude_global_initialisers($realfile)) { + if (ERROR("GLOBAL_INITIALISERS", + "do not initialise globals to $1\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(^.$Type\s*$Ident(?:\s+$Modifier)*)\s*=\s*$zero_initializer\s*;/$1;/; + } } # check for static initialisers. - if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) { - ERROR("INITIALISED_STATIC", - "do not initialise statics to 0 or NULL\n" . - $herecurr); + if ($line =~ /^\+.*\bstatic\s.*=\s*($zero_initializer)\s*;/) { + if (ERROR("INITIALISED_STATIC", + "do not initialise statics to $1\n" . + $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(\bstatic\s.*?)\s*=\s*$zero_initializer\s*;/$1;/; + } + } + +# check for misordered declarations of char/short/int/long with signed/unsigned + while ($sline =~ m{(\b$TypeMisordered\b)}g) { + my $tmp = trim($1); + WARN("MISORDERED_TYPE", + "type '$tmp' should be specified in [[un]signed] [short|int|long|long long] order\n" . $herecurr); + } + +# check for unnecessary <signed> int declarations of short/long/long long + while ($sline =~ m{\b($TypeMisordered(\s*\*)*|$C90_int_types)\b}g) { + my $type = trim($1); + next if ($type !~ /\bint\b/); + next if ($type !~ /\b(?:short|long\s+long|long)\b/); + my $new_type = $type; + $new_type =~ s/\b\s*int\s*\b/ /; + $new_type =~ s/\b\s*(?:un)?signed\b\s*/ /; + $new_type =~ s/^const\s+//; + $new_type = "unsigned $new_type" if ($type =~ /\bunsigned\b/); + $new_type = "const $new_type" if ($type =~ /^const\b/); + $new_type =~ s/\s+/ /g; + $new_type = trim($new_type); + if (WARN("UNNECESSARY_INT", + "Prefer '$new_type' over '$type' as the int is unnecessary\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b\Q$type\E\b/$new_type/; + } } # check for static const char * arrays. @@ -2117,36 +4664,93 @@ sub process { WARN("STATIC_CONST_CHAR_ARRAY", "static const char * array should probably be static const char * const\n" . $herecurr); - } + } + +# check for initialized const char arrays that should be static const + if ($line =~ /^\+\s*const\s+(char|unsigned\s+char|_*u8|(?:[us]_)?int8_t)\s+\w+\s*\[\s*(?:\w+\s*)?\]\s*=\s*"/) { + if (WARN("STATIC_CONST_CHAR_ARRAY", + "const array should probably be static const\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(^.\s*)const\b/${1}static const/; + } + } # check for static char foo[] = "bar" declarations. if ($line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/) { WARN("STATIC_CONST_CHAR_ARRAY", "static char array declaration should probably be static const char\n" . $herecurr); - } + } + +# check for const <foo> const where <foo> is not a pointer or array type + if ($sline =~ /\bconst\s+($BasicType)\s+const\b/) { + my $found = $1; + if ($sline =~ /\bconst\s+\Q$found\E\s+const\b\s*\*/) { + WARN("CONST_CONST", + "'const $found const *' should probably be 'const $found * const'\n" . $herecurr); + } elsif ($sline !~ /\bconst\s+\Q$found\E\s+const\s+\w+\s*\[/) { + WARN("CONST_CONST", + "'const $found const' should probably be 'const $found'\n" . $herecurr); + } + } + +# check for const static or static <non ptr type> const declarations +# prefer 'static const <foo>' over 'const static <foo>' and 'static <foo> const' + if ($sline =~ /^\+\s*const\s+static\s+($Type)\b/ || + $sline =~ /^\+\s*static\s+($BasicType)\s+const\b/) { + if (WARN("STATIC_CONST", + "Move const after static - use 'static const $1'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bconst\s+static\b/static const/; + $fixed[$fixlinenr] =~ s/\bstatic\s+($BasicType)\s+const\b/static const $1/; + } + } + +# check for non-global char *foo[] = {"bar", ...} declarations. + if ($line =~ /^.\s+(?:static\s+|const\s+)?char\s+\*\s*\w+\s*\[\s*\]\s*=\s*\{/) { + WARN("STATIC_CONST_CHAR_ARRAY", + "char * array declaration might be better as static const\n" . + $herecurr); + } + +# check for sizeof(foo)/sizeof(foo[0]) that could be ARRAY_SIZE(foo) + if ($line =~ m@\bsizeof\s*\(\s*($Lval)\s*\)@) { + my $array = $1; + if ($line =~ m@\b(sizeof\s*\(\s*\Q$array\E\s*\)\s*/\s*sizeof\s*\(\s*\Q$array\E\s*\[\s*0\s*\]\s*\))@) { + my $array_div = $1; + if (WARN("ARRAY_SIZE", + "Prefer ARRAY_SIZE($array)\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\Q$array_div\E/ARRAY_SIZE($array)/; + } + } + } -# check for declarations of struct pci_device_id - if ($line =~ /\bstruct\s+pci_device_id\s+\w+\s*\[\s*\]\s*\=\s*\{/) { - WARN("DEFINE_PCI_DEVICE_TABLE", - "Use DEFINE_PCI_DEVICE_TABLE for struct pci_device_id\n" . $herecurr); +# check for function declarations without arguments like "int foo()" + if ($line =~ /(\b$Type\s*$Ident)\s*\(\s*\)/) { + if (ERROR("FUNCTION_WITHOUT_ARGS", + "Bad function definition - $1() should probably be $1(void)\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(\b($Type)\s+($Ident))\s*\(\s*\)/$2 $3(void)/; + } } # check for new typedefs, only function parameters and sparse annotations # make sense. -# if ($line =~ /\btypedef\s/ && -# $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ && -# $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && -# $line !~ /\b$typeTypedefs\b/ && -# $line !~ /\b__bitwise(?:__|)\b/) { -# WARN("NEW_TYPEDEFS", -# "do not add new typedefs\n" . $herecurr); -# } + if ($line =~ /\btypedef\s/ && + $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ && + $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && + $line !~ /\b$typeTypedefs\b/ && + $line !~ /\b__bitwise\b/) { + WARN("NEW_TYPEDEFS", + "do not add new typedefs\n" . $herecurr); + } # * goes on variable not on type # (char*[ const]) - if ($line =~ m{\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\)}) { - my ($from, $to) = ($1, $1); + while ($line =~ m{(\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\))}g) { + #print "AA<$1>\n"; + my ($ident, $from, $to) = ($1, $2, $2); # Should start with a space. $to =~ s/^(\S)/ $1/; @@ -2156,13 +4760,22 @@ sub process { while ($to =~ s/\*\s+\*/\*\*/) { } - #print "from<$from> to<$to>\n"; +## print "1: from<$from> to<$to> ident<$ident>\n"; if ($from ne $to) { - ERROR("POINTER_LOCATION", - "\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr); + if (ERROR("POINTER_LOCATION", + "\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr) && + $fix) { + my $sub_from = $ident; + my $sub_to = $ident; + $sub_to =~ s/\Q$from\E/$to/; + $fixed[$fixlinenr] =~ + s@\Q$sub_from\E@$sub_to@; + } } - } elsif ($line =~ m{\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident)}) { - my ($from, $to, $ident) = ($1, $1, $2); + } + while ($line =~ m{(\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident))}g) { + #print "BB<$1>\n"; + my ($match, $from, $to, $ident) = ($1, $2, $2, $3); # Should start with a space. $to =~ s/^(\S)/ $1/; @@ -2174,20 +4787,30 @@ sub process { # Modifiers should have spaces. $to =~ s/(\b$Modifier$)/$1 /; - #print "from<$from> to<$to> ident<$ident>\n"; +## print "2: from<$from> to<$to> ident<$ident>\n"; if ($from ne $to && $ident !~ /^$Modifier$/) { - ERROR("POINTER_LOCATION", - "\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr); + if (ERROR("POINTER_LOCATION", + "\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr) && + $fix) { + + my $sub_from = $match; + my $sub_to = $match; + $sub_to =~ s/\Q$from\E/$to/; + $fixed[$fixlinenr] =~ + s@\Q$sub_from\E@$sub_to@; + } } } -# # no BUG() or BUG_ON() -# if ($line =~ /\b(BUG|BUG_ON)\b/) { -# print "Try to use WARN_ON & Recovery code rather than BUG() or BUG_ON()\n"; -# print "$herecurr"; -# $clean = 0; -# } +# avoid BUG() or BUG_ON() + if ($line =~ /\b(?:BUG|BUG_ON)\b/) { + my $msg_level = \&WARN; + $msg_level = \&CHK if ($file); + &{$msg_level}("AVOID_BUG", + "Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()\n" . $herecurr); + } +# avoid LINUX_VERSION_CODE if ($line =~ /\bLINUX_VERSION_CODE\b/) { WARN("LINUX_VERSION_CODE", "LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr); @@ -2196,52 +4819,184 @@ sub process { # check for uses of printk_ratelimit if ($line =~ /\bprintk_ratelimit\s*\(/) { WARN("PRINTK_RATELIMITED", -"Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\n" . $herecurr); - } - -# printk should use KERN_* levels. Note that follow on printk's on the -# same line do not need a level, so we use the current block context -# to try and find and validate the current printk. In summary the current -# printk includes all preceding printk's which have no newline on the end. -# we assume the first bad printk is the one to report. - if ($line =~ /\bprintk\((?!KERN_)\s*"/) { - my $ok = 0; - for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) { - #print "CHECK<$lines[$ln - 1]\n"; - # we have a preceding printk if it ends - # with "\n" ignore it, else it is to blame - if ($lines[$ln - 1] =~ m{\bprintk\(}) { - if ($rawlines[$ln - 1] !~ m{\\n"}) { - $ok = 1; - } - last; - } - } - if ($ok == 0) { - WARN("PRINTK_WITHOUT_KERN_LEVEL", - "printk() should include KERN_ facility level\n" . $herecurr); + "Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\n" . $herecurr); + } + +# printk should use KERN_* levels + if ($line =~ /\bprintk\s*\(\s*(?!KERN_[A-Z]+\b)/) { + WARN("PRINTK_WITHOUT_KERN_LEVEL", + "printk() should include KERN_<LEVEL> facility level\n" . $herecurr); + } + +# prefer variants of (subsystem|netdev|dev|pr)_<level> to printk(KERN_<LEVEL> + if ($line =~ /\b(printk(_once|_ratelimited)?)\s*\(\s*KERN_([A-Z]+)/) { + my $printk = $1; + my $modifier = $2; + my $orig = $3; + $modifier = "" if (!defined($modifier)); + my $level = lc($orig); + $level = "warn" if ($level eq "warning"); + my $level2 = $level; + $level2 = "dbg" if ($level eq "debug"); + $level .= $modifier; + $level2 .= $modifier; + WARN("PREFER_PR_LEVEL", + "Prefer [subsystem eg: netdev]_$level2([subsystem]dev, ... then dev_$level2(dev, ... then pr_$level(... to $printk(KERN_$orig ...\n" . $herecurr); + } + +# prefer dev_<level> to dev_printk(KERN_<LEVEL> + if ($line =~ /\bdev_printk\s*\(\s*KERN_([A-Z]+)/) { + my $orig = $1; + my $level = lc($orig); + $level = "warn" if ($level eq "warning"); + $level = "dbg" if ($level eq "debug"); + WARN("PREFER_DEV_LEVEL", + "Prefer dev_$level(... to dev_printk(KERN_$orig, ...\n" . $herecurr); + } + +# trace_printk should not be used in production code. + if ($line =~ /\b(trace_printk|trace_puts|ftrace_vprintk)\s*\(/) { + WARN("TRACE_PRINTK", + "Do not use $1() in production code (this can be ignored if built only with a debug config option)\n" . $herecurr); + } + +# ENOSYS means "bad syscall nr" and nothing else. This will have a small +# number of false positives, but assembly files are not checked, so at +# least the arch entry code will not trigger this warning. + if ($line =~ /\bENOSYS\b/) { + WARN("ENOSYS", + "ENOSYS means 'invalid syscall nr' and nothing else\n" . $herecurr); + } + +# ENOTSUPP is not a standard error code and should be avoided in new patches. +# Folks usually mean EOPNOTSUPP (also called ENOTSUP), when they type ENOTSUPP. +# Similarly to ENOSYS warning a small number of false positives is expected. + if (!$file && $line =~ /\bENOTSUPP\b/) { + if (WARN("ENOTSUPP", + "ENOTSUPP is not a SUSV4 error code, prefer EOPNOTSUPP\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bENOTSUPP\b/EOPNOTSUPP/; } } # function brace can't be on same line, except for #defines of do while, # or if closed on same line - if (($line=~/$Type\s*$Ident\(.*\).*\s\{/) and - !($line=~/\#\s*define.*do\s\{/) and !($line=~/}/)) { - ERROR("OPEN_BRACE", - "open brace '{' following function declarations go on the next line\n" . $herecurr); + if ($perl_version_ok && + $sline =~ /$Type\s*$Ident\s*$balanced_parens\s*\{/ && + $sline !~ /\#\s*define\b.*do\s*\{/ && + $sline !~ /}/) { + if (ERROR("OPEN_BRACE", + "open brace '{' following function definitions go on the next line\n" . $herecurr) && + $fix) { + fix_delete_line($fixlinenr, $rawline); + my $fixed_line = $rawline; + $fixed_line =~ /(^..*$Type\s*$Ident\(.*\)\s*)\{(.*)$/; + my $line1 = $1; + my $line2 = $2; + fix_insert_line($fixlinenr, ltrim($line1)); + fix_insert_line($fixlinenr, "\+{"); + if ($line2 !~ /^\s*$/) { + fix_insert_line($fixlinenr, "\+\t" . trim($line2)); + } + } } # open braces for enum, union and struct go on the same line. - if ($line =~ /^.\s*\{/ && + if ($line =~ /^.\s*{/ && $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) { - ERROR("OPEN_BRACE", - "open brace '{' following $1 go on the same line\n" . $hereprev); + if (ERROR("OPEN_BRACE", + "open brace '{' following $1 go on the same line\n" . $hereprev) && + $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { + fix_delete_line($fixlinenr - 1, $prevrawline); + fix_delete_line($fixlinenr, $rawline); + my $fixedline = rtrim($prevrawline) . " {"; + fix_insert_line($fixlinenr, $fixedline); + $fixedline = $rawline; + $fixedline =~ s/^(.\s*)\{\s*/$1\t/; + if ($fixedline !~ /^\+\s*$/) { + fix_insert_line($fixlinenr, $fixedline); + } + } } # missing space after union, struct or enum definition - if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) { - WARN("SPACING", - "missing space after $1 definition\n" . $herecurr); + if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident){1,2}[=\{]/) { + if (WARN("SPACING", + "missing space after $1 definition\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/^(.\s*(?:typedef\s+)?(?:enum|union|struct)(?:\s+$Ident){1,2})([=\{])/$1 $2/; + } + } + +# Function pointer declarations +# check spacing between type, funcptr, and args +# canonical declaration is "type (*funcptr)(args...)" + if ($line =~ /^.\s*($Declare)\((\s*)\*(\s*)($Ident)(\s*)\)(\s*)\(/) { + my $declare = $1; + my $pre_pointer_space = $2; + my $post_pointer_space = $3; + my $funcname = $4; + my $post_funcname_space = $5; + my $pre_args_space = $6; + +# the $Declare variable will capture all spaces after the type +# so check it for a missing trailing missing space but pointer return types +# don't need a space so don't warn for those. + my $post_declare_space = ""; + if ($declare =~ /(\s+)$/) { + $post_declare_space = $1; + $declare = rtrim($declare); + } + if ($declare !~ /\*$/ && $post_declare_space =~ /^$/) { + WARN("SPACING", + "missing space after return type\n" . $herecurr); + $post_declare_space = " "; + } + +# unnecessary space "type (*funcptr)(args...)" +# This test is not currently implemented because these declarations are +# equivalent to +# int foo(int bar, ...) +# and this is form shouldn't/doesn't generate a checkpatch warning. +# +# elsif ($declare =~ /\s{2,}$/) { +# WARN("SPACING", +# "Multiple spaces after return type\n" . $herecurr); +# } + +# unnecessary space "type ( *funcptr)(args...)" + if (defined $pre_pointer_space && + $pre_pointer_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space after function pointer open parenthesis\n" . $herecurr); + } + +# unnecessary space "type (* funcptr)(args...)" + if (defined $post_pointer_space && + $post_pointer_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space before function pointer name\n" . $herecurr); + } + +# unnecessary space "type (*funcptr )(args...)" + if (defined $post_funcname_space && + $post_funcname_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space after function pointer name\n" . $herecurr); + } + +# unnecessary space "type (*funcptr) (args...)" + if (defined $pre_args_space && + $pre_args_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space before function pointer arguments\n" . $herecurr); + } + + if (show_type("SPACING") && $fix) { + $fixed[$fixlinenr] =~ + s/^(.\s*)$Declare\s*\(\s*\*\s*$Ident\s*\)\s*\(/$1 . $declare . $post_declare_space . '(*' . $funcname . ')('/ex; + } } # check for spacing round square brackets; allowed: @@ -2252,9 +5007,13 @@ sub process { my ($where, $prefix) = ($-[1], $1); if ($prefix !~ /$Type\s+$/ && ($where != 0 || $prefix !~ /^.\s+$/) && - $prefix !~ /\{\s+$/) { - ERROR("BRACKET_SPACE", - "space prohibited before open square bracket '['\n" . $herecurr); + $prefix !~ /[{,:]\s+$/) { + if (ERROR("BRACKET_SPACE", + "space prohibited before open square bracket '['\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/^(\+.*?)\s+\[/$1\[/; + } } } @@ -2271,7 +5030,6 @@ sub process { __attribute__|format|__extension__| asm|__asm__)$/x) { - # cpp #define statements have non-optional spaces, ie # if there is a space between the name and the open # parenthesis it is simply not a parameter group. @@ -2285,25 +5043,53 @@ sub process { } elsif ($ctx =~ /$Type$/) { } else { - WARN("SPACING", - "space prohibited between function name and open parenthesis '('\n" . $herecurr); + if (WARN("SPACING", + "space prohibited between function name and open parenthesis '('\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\b$name\s+\(/$name\(/; + } } } + # Check operator spacing. if (!($line=~/\#\s*include/)) { + my $fixed_line = ""; + my $line_fixed = 0; + my $ops = qr{ <<=|>>=|<=|>=|==|!=| \+=|-=|\*=|\/=|%=|\^=|\|=|&=| =>|->|<<|>>|<|>|=|!|~| &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%| - \?|: + \?:|\?|: }x; my @elements = split(/($ops|;)/, $opline); + +## print("element count: <" . $#elements . ">\n"); +## foreach my $el (@elements) { +## print("el: <$el>\n"); +## } + + my @fix_elements = (); my $off = 0; + foreach my $el (@elements) { + push(@fix_elements, substr($rawline, $off, length($el))); + $off += length($el); + } + + $off = 0; + my $blank = copy_spacing($opline); + my $last_after = -1; for (my $n = 0; $n < $#elements; $n += 2) { + + my $good = $fix_elements[$n] . $fix_elements[$n + 1]; + +## print("n: <$n> good: <$good>\n"); + $off += length($elements[$n]); # Pick up the preceding and succeeding characters. @@ -2351,7 +5137,7 @@ sub process { # Ignore operators passed as parameters. if ($op_type ne 'V' && - $ca =~ /\s$/ && $cc =~ /^\s*,/) { + $ca =~ /\s$/ && $cc =~ /^\s*[,\)]/) { # # Ignore comments # } elsif ($op =~ /^$;+$/) { @@ -2360,27 +5146,62 @@ sub process { } elsif ($op eq ';') { if ($ctx !~ /.x[WEBC]/ && $cc !~ /^\\/ && $cc !~ /^;/) { - ERROR("SPACING", - "space required after that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "space required after that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]) . " "; + $line_fixed = 1; + } } # // is a comment } elsif ($op eq '//') { + # : when part of a bitfield + } elsif ($opv eq ':B') { + # skip the bitfield test for now + # No spaces for: # -> - # : when part of a bitfield - } elsif ($op eq '->' || $opv eq ':B') { + } elsif ($op eq '->') { if ($ctx =~ /Wx.|.xW/) { - ERROR("SPACING", - "spaces prohibited around that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "spaces prohibited around that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } } - # , must have a space on the right. + # , must not have a space before and must have a space on the right. } elsif ($op eq ',') { + my $rtrim_before = 0; + my $space_after = 0; + if ($ctx =~ /Wx./) { + if (ERROR("SPACING", + "space prohibited before that '$op' $at\n" . $hereptr)) { + $line_fixed = 1; + $rtrim_before = 1; + } + } if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) { - ERROR("SPACING", - "space required after that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "space required after that '$op' $at\n" . $hereptr)) { + $line_fixed = 1; + $last_after = $n; + $space_after = 1; + } + } + if ($rtrim_before || $space_after) { + if ($rtrim_before) { + $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); + } else { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]); + } + if ($space_after) { + $good .= " "; + } } # '*' as part of a type definition -- reported already. @@ -2394,34 +5215,56 @@ sub process { $opv eq '*U' || $opv eq '-U' || $opv eq '&U' || $opv eq '&&U') { if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { - ERROR("SPACING", - "space required before that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "space required before that '$op' $at\n" . $hereptr)) { + if ($n != $last_after + 2) { + $good = $fix_elements[$n] . " " . ltrim($fix_elements[$n + 1]); + $line_fixed = 1; + } + } } if ($op eq '*' && $cc =~/\s*$Modifier\b/) { # A unary '*' may be const } elsif ($ctx =~ /.xW/) { - ERROR("SPACING", - "space prohibited after that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "space prohibited after that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . rtrim($fix_elements[$n + 1]); + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } } # unary ++ and unary -- are allowed no space on one side. } elsif ($op eq '++' or $op eq '--') { if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) { - ERROR("SPACING", - "space required one side of that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "space required one side of that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]) . " "; + $line_fixed = 1; + } } if ($ctx =~ /Wx[BE]/ || ($ctx =~ /Wx./ && $cc =~ /^;/)) { - ERROR("SPACING", - "space prohibited before that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "space prohibited before that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); + $line_fixed = 1; + } } if ($ctx =~ /ExW/) { - ERROR("SPACING", - "space prohibited after that '$op' $at\n" . $hereptr); + if (ERROR("SPACING", + "space prohibited after that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]); + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } } - # << and >> may either have or not have spaces both sides } elsif ($op eq '<<' or $op eq '>>' or $op eq '&' or $op eq '^' or $op eq '|' or @@ -2429,18 +5272,41 @@ sub process { $op eq '*' or $op eq '/' or $op eq '%') { - if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) { - ERROR("SPACING", - "need consistent spacing around '$op' $at\n" . - $hereptr); + if ($check) { + if (defined $fix_elements[$n + 2] && $ctx !~ /[EW]x[EW]/) { + if (CHK("SPACING", + "spaces preferred around that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " "; + $fix_elements[$n + 2] =~ s/^\s+//; + $line_fixed = 1; + } + } elsif (!defined $fix_elements[$n + 2] && $ctx !~ /Wx[OE]/) { + if (CHK("SPACING", + "space preferred before that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]); + $line_fixed = 1; + } + } + } elsif ($ctx =~ /Wx[^WCE]|[^WCE]xW/) { + if (ERROR("SPACING", + "need consistent spacing around '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " "; + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } } # A colon needs no spaces before when it is # terminating a case value or a label. } elsif ($opv eq ':C' || $opv eq ':L') { - if ($ctx =~ /Wx./) { - ERROR("SPACING", - "space prohibited before that '$op' $at\n" . $hereptr); + if ($ctx =~ /Wx./ and $realfile !~ m@.*\.lds\.h$@) { + if (ERROR("SPACING", + "space prohibited before that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); + $line_fixed = 1; + } } # All the others need spaces both sides. @@ -2453,21 +5319,57 @@ sub process { ($op eq '>' && $ca =~ /<\S+\@\S+$/)) { - $ok = 1; + $ok = 1; } - # Ignore ?: - if (($opv eq ':O' && $ca =~ /\?$/) || - ($op eq '?' && $cc =~ /^:/)) { - $ok = 1; + # for asm volatile statements + # ignore a colon with another + # colon immediately before or after + if (($op eq ':') && + ($ca =~ /:$/ || $cc =~ /^:/)) { + $ok = 1; } + # messages are ERROR, but ?: are CHK if ($ok == 0) { - ERROR("SPACING", - "spaces required around that '$op' $at\n" . $hereptr); + my $msg_level = \&ERROR; + $msg_level = \&CHK if (($op eq '?:' || $op eq '?' || $op eq ':') && $ctx =~ /VxV/); + + if (&{$msg_level}("SPACING", + "spaces required around that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " "; + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } } } $off += length($elements[$n + 1]); + +## print("n: <$n> GOOD: <$good>\n"); + + $fixed_line = $fixed_line . $good; + } + + if (($#elements % 2) == 0) { + $fixed_line = $fixed_line . $fix_elements[$#elements]; + } + + if ($fix && $line_fixed && $fixed_line ne $fixed[$fixlinenr]) { + $fixed[$fixlinenr] = $fixed_line; + } + + + } + +# check for whitespace before a non-naked semicolon + if ($line =~ /^\+.*\S\s+;\s*$/) { + if (WARN("SPACING", + "space prohibited before semicolon\n" . $herecurr) && + $fix) { + 1 while $fixed[$fixlinenr] =~ + s/^(\+.*\S)\s+;/$1;/; } } @@ -2483,7 +5385,7 @@ sub process { ## $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) { ## ## # Remove any bracketed sections to ensure we do not -## # falsly report the parameters of functions. +## # falsely report the parameters of functions. ## my $ln = $line; ## while ($ln =~ s/\([^\(\)]*\)//g) { ## } @@ -2495,111 +5397,247 @@ sub process { #need space before brace following if, while, etc if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\)\{/) || - $line =~ /do\{/) { - ERROR("SPACING", - "space required before the open brace '{'\n" . $herecurr); + $line =~ /\b(?:else|do)\{/) { + if (ERROR("SPACING", + "space required before the open brace '{'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/^(\+.*(?:do|else|\)))\{/$1 {/; + } } +## # check for blank lines before declarations +## if ($line =~ /^.\t+$Type\s+$Ident(?:\s*=.*)?;/ && +## $prevrawline =~ /^.\s*$/) { +## WARN("SPACING", +## "No blank lines before declarations\n" . $hereprev); +## } +## + # closing brace should have a space following it when it has anything # on the line - if ($line =~ /}(?!(?:,|;|\)))\S/) { - ERROR("SPACING", - "space required after that close brace '}'\n" . $herecurr); + if ($line =~ /}(?!(?:,|;|\)|\}))\S/) { + if (ERROR("SPACING", + "space required after that close brace '}'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/}((?!(?:,|;|\)))\S)/} $1/; + } } # check spacing on square brackets if ($line =~ /\[\s/ && $line !~ /\[\s*$/) { - ERROR("SPACING", - "space prohibited after that open square bracket '['\n" . $herecurr); + if (ERROR("SPACING", + "space prohibited after that open square bracket '['\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\[\s+/\[/; + } } if ($line =~ /\s\]/) { - ERROR("SPACING", - "space prohibited before that close square bracket ']'\n" . $herecurr); + if (ERROR("SPACING", + "space prohibited before that close square bracket ']'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\s+\]/\]/; + } } # check spacing on parentheses if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ && $line !~ /for\s*\(\s+;/) { - ERROR("SPACING", - "space prohibited after that open parenthesis '('\n" . $herecurr); + if (ERROR("SPACING", + "space prohibited after that open parenthesis '('\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\(\s+/\(/; + } } if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ && $line !~ /for\s*\(.*;\s+\)/ && $line !~ /:\s+\)/) { - ERROR("SPACING", - "space prohibited before that close parenthesis ')'\n" . $herecurr); + if (ERROR("SPACING", + "space prohibited before that close parenthesis ')'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\s+\)/\)/; + } } -#goto labels aren't indented, allow a single space however - if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and - !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) { - WARN("INDENTED_LABEL", - "labels should not be indented\n" . $herecurr); +# check unnecessary parentheses around addressof/dereference single $Lvals +# ie: &(foo->bar) should be &foo->bar and *(foo->bar) should be *foo->bar + + while ($line =~ /(?:[^&]&\s*|\*)\(\s*($Ident\s*(?:$Member\s*)+)\s*\)/g) { + my $var = $1; + if (CHK("UNNECESSARY_PARENTHESES", + "Unnecessary parentheses around $var\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\(\s*\Q$var\E\s*\)/$var/; + } } -# Return is not a function. - if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) { - my $spacing = $1; - my $value = $2; - - # Flatten any parentheses - $value =~ s/\(/ \(/g; - $value =~ s/\)/\) /g; - while ($value =~ s/\[[^\{\}]*\]/1/ || - $value !~ /(?:$Ident|-?$Constant)\s* - $Compare\s* - (?:$Ident|-?$Constant)/x && - $value =~ s/\([^\(\)]*\)/1/) { - } -#print "value<$value>\n"; - if ($value =~ /^\s*(?:$Ident|-?$Constant)\s*$/) { - ERROR("RETURN_PARENTHESES", - "return is not a function, parentheses are not required\n" . $herecurr); +# check for unnecessary parentheses around function pointer uses +# ie: (foo->bar)(); should be foo->bar(); +# but not "if (foo->bar) (" to avoid some false positives + if ($line =~ /(\bif\s*|)(\(\s*$Ident\s*(?:$Member\s*)+\))[ \t]*\(/ && $1 !~ /^if/) { + my $var = $2; + if (CHK("UNNECESSARY_PARENTHESES", + "Unnecessary parentheses around function pointer $var\n" . $herecurr) && + $fix) { + my $var2 = deparenthesize($var); + $var2 =~ s/\s//g; + $fixed[$fixlinenr] =~ s/\Q$var\E/$var2/; + } + } + +# check for unnecessary parentheses around comparisons in if uses +# when !drivers/staging or command-line uses --strict + if (($realfile !~ m@^(?:drivers/staging/)@ || $check_orig) && + $perl_version_ok && defined($stat) && + $stat =~ /(^.\s*if\s*($balanced_parens))/) { + my $if_stat = $1; + my $test = substr($2, 1, -1); + my $herectx; + while ($test =~ /(?:^|[^\w\&\!\~])+\s*\(\s*([\&\!\~]?\s*$Lval\s*(?:$Compare\s*$FuncArg)?)\s*\)/g) { + my $match = $1; + # avoid parentheses around potential macro args + next if ($match =~ /^\s*\w+\s*$/); + if (!defined($herectx)) { + $herectx = $here . "\n"; + my $cnt = statement_rawlines($if_stat); + for (my $n = 0; $n < $cnt; $n++) { + my $rl = raw_line($linenr, $n); + $herectx .= $rl . "\n"; + last if $rl =~ /^[ \+].*\{/; + } + } + CHK("UNNECESSARY_PARENTHESES", + "Unnecessary parentheses around '$match'\n" . $herectx); + } + } + +# check that goto labels aren't indented (allow a single space indentation) +# and ignore bitfield definitions like foo:1 +# Strictly, labels can have whitespace after the identifier and before the : +# but this is not allowed here as many ?: uses would appear to be labels + if ($sline =~ /^.\s+[A-Za-z_][A-Za-z\d_]*:(?!\s*\d+)/ && + $sline !~ /^. [A-Za-z\d_][A-Za-z\d_]*:/ && + $sline !~ /^.\s+default:/) { + if (WARN("INDENTED_LABEL", + "labels should not be indented\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/^(.)\s+/$1/; + } + } + +# check if a statement with a comma should be two statements like: +# foo = bar(), /* comma should be semicolon */ +# bar = baz(); + if (defined($stat) && + $stat =~ /^\+\s*(?:$Lval\s*$Assignment\s*)?$FuncArg\s*,\s*(?:$Lval\s*$Assignment\s*)?$FuncArg\s*;\s*$/) { + my $cnt = statement_rawlines($stat); + my $herectx = get_stat_here($linenr, $cnt, $here); + WARN("SUSPECT_COMMA_SEMICOLON", + "Possible comma where semicolon could be used\n" . $herectx); + } +# return is not a function + if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) { + my $spacing = $1; + if ($perl_version_ok && + $stat =~ /^.\s*return\s*($balanced_parens)\s*;\s*$/) { + my $value = $1; + $value = deparenthesize($value); + if ($value =~ m/^\s*$FuncArg\s*(?:\?|$)/) { + ERROR("RETURN_PARENTHESES", + "return is not a function, parentheses are not required\n" . $herecurr); + } } elsif ($spacing !~ /\s+/) { ERROR("SPACING", "space required before the open parenthesis '('\n" . $herecurr); } } -# Return of what appears to be an errno should normally be -'ve - if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) { - my $name = $1; - if ($name ne 'EOF' && $name ne 'ERROR') { - WARN("USE_NEGATIVE_ERRNO", - "return of an errno should typically be -ve (return -$1)\n" . $herecurr); + +# unnecessary return in a void function +# at end-of-function, with the previous line a single leading tab, then return; +# and the line before that not a goto label target like "out:" + if ($sline =~ /^[ \+]}\s*$/ && + $prevline =~ /^\+\treturn\s*;\s*$/ && + $linenr >= 3 && + $lines[$linenr - 3] =~ /^[ +]/ && + $lines[$linenr - 3] !~ /^[ +]\s*$Ident\s*:/) { + WARN("RETURN_VOID", + "void function return statements are not generally useful\n" . $hereprev); + } + +# if statements using unnecessary parentheses - ie: if ((foo == bar)) + if ($perl_version_ok && + $line =~ /\bif\s*((?:\(\s*){2,})/) { + my $openparens = $1; + my $count = $openparens =~ tr@\(@\(@; + my $msg = ""; + if ($line =~ /\bif\s*(?:\(\s*){$count,$count}$LvalOrFunc\s*($Compare)\s*$LvalOrFunc(?:\s*\)){$count,$count}/) { + my $comp = $4; #Not $1 because of $LvalOrFunc + $msg = " - maybe == should be = ?" if ($comp eq "=="); + WARN("UNNECESSARY_PARENTHESES", + "Unnecessary parentheses$msg\n" . $herecurr); } } -# typecasts on min/max could be min_t/max_t - if ($line =~ /^\+(?:.*?)\b(min|max)\s*\($Typecast{0,1}($LvalOrFunc)\s*,\s*$Typecast{0,1}($LvalOrFunc)\s*\)/) { - if (defined $2 || defined $8) { - my $call = $1; - my $cast1 = deparenthesize($2); - my $arg1 = $3; - my $cast2 = deparenthesize($8); - my $arg2 = $9; - my $cast; - - if ($cast1 ne "" && $cast2 ne "") { - $cast = "$cast1 or $cast2"; - } elsif ($cast1 ne "") { - $cast = $cast1; - } else { - $cast = $cast2; +# comparisons with a constant or upper case identifier on the left +# avoid cases like "foo + BAR < baz" +# only fix matches surrounded by parentheses to avoid incorrect +# conversions like "FOO < baz() + 5" being "misfixed" to "baz() > FOO + 5" + if ($perl_version_ok && + $line =~ /^\+(.*)\b($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*($LvalOrFunc)/) { + my $lead = $1; + my $const = $2; + my $comp = $3; + my $to = $4; + my $newcomp = $comp; + if ($lead !~ /(?:$Operators|\.)\s*$/ && + $to !~ /^(?:Constant|[A-Z_][A-Z0-9_]*)$/ && + WARN("CONSTANT_COMPARISON", + "Comparisons should place the constant on the right side of the test\n" . $herecurr) && + $fix) { + if ($comp eq "<") { + $newcomp = ">"; + } elsif ($comp eq "<=") { + $newcomp = ">="; + } elsif ($comp eq ">") { + $newcomp = "<"; + } elsif ($comp eq ">=") { + $newcomp = "<="; } - WARN("MINMAX", - "$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . $herecurr); + $fixed[$fixlinenr] =~ s/\(\s*\Q$const\E\s*$Compare\s*\Q$to\E\s*\)/($to $newcomp $const)/; + } + } + +# Return of what appears to be an errno should normally be negative + if ($sline =~ /\breturn(?:\s*\(+\s*|\s+)(E[A-Z]+)(?:\s*\)+\s*|\s*)[;:,]/) { + my $name = $1; + if ($name ne 'EOF' && $name ne 'ERROR' && $name !~ /^EPOLL/) { + WARN("USE_NEGATIVE_ERRNO", + "return of an errno should typically be negative (ie: return -$1)\n" . $herecurr); } } # Need a space before open parenthesis after if, while etc - if ($line=~/\b(if|while|for|switch)\(/) { - ERROR("SPACING", "space required before the open parenthesis '('\n" . $herecurr); + if ($line =~ /\b(if|while|for|switch)\(/) { + if (ERROR("SPACING", + "space required before the open parenthesis '('\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\b(if|while|for|switch)\(/$1 \(/; + } } # Check for illegal assignment in if conditional -- and check for trailing # statements after the conditional. - if ($line =~ /do\s*(?!\{)/) { + if ($line =~ /do\s*(?!{)/) { + ($stat, $cond, $line_nr_next, $remain_next, $off_next) = + ctx_statement_block($linenr, $realcnt, 0) + if (!defined $stat); my ($stat_next) = ctx_statement_block($line_nr_next, $remain_next, $off_next); $stat_next =~ s/\n./\n /g; @@ -2618,20 +5656,45 @@ sub process { } } if (!defined $suppress_whiletrailers{$linenr} && + defined($stat) && defined($cond) && $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) { my ($s, $c) = ($stat, $cond); + my $fixed_assign_in_if = 0; if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) { - ERROR("ASSIGN_IN_IF", - "do not use assignment in if condition\n" . $herecurr); + if (ERROR("ASSIGN_IN_IF", + "do not use assignment in if condition\n" . $herecurr) && + $fix && $perl_version_ok) { + if ($rawline =~ /^\+(\s+)if\s*\(\s*(\!)?\s*\(\s*(($Lval)\s*=\s*$LvalOrFunc)\s*\)\s*(?:($Compare)\s*($FuncArg))?\s*\)\s*(\{)?\s*$/) { + my $space = $1; + my $not = $2; + my $statement = $3; + my $assigned = $4; + my $test = $8; + my $against = $9; + my $brace = $15; + fix_delete_line($fixlinenr, $rawline); + fix_insert_line($fixlinenr, "$space$statement;"); + my $newline = "${space}if ("; + $newline .= '!' if defined($not); + $newline .= '(' if (defined $not && defined($test) && defined($against)); + $newline .= "$assigned"; + $newline .= " $test $against" if (defined($test) && defined($against)); + $newline .= ')' if (defined $not && defined($test) && defined($against)); + $newline .= ')'; + $newline .= " {" if (defined($brace)); + fix_insert_line($fixlinenr + 1, $newline); + $fixed_assign_in_if = 1; + } + } } # Find out what is on the end of the line after the # conditional. substr($s, 0, length($c), ''); $s =~ s/\n.*//g; - $s =~ s/$;//g; # Remove any comments - if (length($c) && $s !~ /^\s*\{?\s*\\*\s*$/ && + $s =~ s/$;//g; # Remove any comments + if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ && $c !~ /}\s*while\s*/) { # Find out how long the conditional actually is. @@ -2645,8 +5708,20 @@ sub process { $stat_real = "[...]\n$stat_real"; } - ERROR("TRAILING_STATEMENTS", - "trailing statements should be on next line\n" . $herecurr . $stat_real); + if (ERROR("TRAILING_STATEMENTS", + "trailing statements should be on next line\n" . $herecurr . $stat_real) && + !$fixed_assign_in_if && + $cond_lines == 0 && + $fix && $perl_version_ok && + $fixed[$fixlinenr] =~ /^\+(\s*)((?:if|while|for)\s*$balanced_parens)\s*(.*)$/) { + my $indent = $1; + my $test = $2; + my $rest = rtrim($4); + if ($rest =~ /;$/) { + $fixed[$fixlinenr] = "\+$indent$test"; + fix_insert_line($fixlinenr + 1, "$indent\t$rest"); + } + } } } @@ -2669,8 +5744,8 @@ sub process { # if and else should not have general statements after it if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) { my $s = $1; - $s =~ s/$;//g; # Remove any comments - if ($s !~ /^\s*(?:\sif|(?:\{|)\s*\\?\s*$)/) { + $s =~ s/$;//g; # Remove any comments + if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) { ERROR("TRAILING_STATEMENTS", "trailing statements should be on next line\n" . $herecurr); } @@ -2678,7 +5753,7 @@ sub process { # if should not continue a brace if ($line =~ /}\s*if\b/) { ERROR("TRAILING_STATEMENTS", - "trailing statements should be on next line\n" . + "trailing statements should be on next line (or did you mean 'else if'?)\n" . $herecurr); } # case and default should not have general statements after them @@ -2694,14 +5769,26 @@ sub process { # Check for }<nl>else {, these must be at the same # indent level to be relevant to each other. - if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and - $previndent == $indent) { - ERROR("ELSE_AFTER_BRACE", - "else should follow close brace '}'\n" . $hereprev); + if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ && + $previndent == $indent) { + if (ERROR("ELSE_AFTER_BRACE", + "else should follow close brace '}'\n" . $hereprev) && + $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { + fix_delete_line($fixlinenr - 1, $prevrawline); + fix_delete_line($fixlinenr, $rawline); + my $fixedline = $prevrawline; + $fixedline =~ s/}\s*$//; + if ($fixedline !~ /^\+\s*$/) { + fix_insert_line($fixlinenr, $fixedline); + } + $fixedline = $rawline; + $fixedline =~ s/^(.\s*)else/$1} else/; + fix_insert_line($fixlinenr, $fixedline); + } } - if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ and - $previndent == $indent) { + if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ && + $previndent == $indent) { my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0); # Find out what is on the end of the line after the @@ -2710,25 +5797,84 @@ sub process { $s =~ s/\n.*//g; if ($s =~ /^\s*;/) { - ERROR("WHILE_AFTER_BRACE", - "while should follow close brace '}'\n" . $hereprev); + if (ERROR("WHILE_AFTER_BRACE", + "while should follow close brace '}'\n" . $hereprev) && + $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { + fix_delete_line($fixlinenr - 1, $prevrawline); + fix_delete_line($fixlinenr, $rawline); + my $fixedline = $prevrawline; + my $trailing = $rawline; + $trailing =~ s/^\+//; + $trailing = trim($trailing); + $fixedline =~ s/}\s*$/} $trailing/; + fix_insert_line($fixlinenr, $fixedline); + } } } -#studly caps, commented out until figure out how to distinguish between use of existing and adding new -# if (($line=~/[\w_][a-z\d]+[A-Z]/) and !($line=~/print/)) { -# print "No studly caps, use _\n"; -# print "$herecurr"; -# $clean = 0; -# } +#Specific variable tests + while ($line =~ m{($Constant|$Lval)}g) { + my $var = $1; + +#CamelCase + if (!$OpenOCD) { + if ($var !~ /^$Constant$/ && + $var =~ /[A-Z][a-z]|[a-z][A-Z]/ && +#Ignore some autogenerated defines and enum values + $var !~ /^(?:[A-Z]+_){1,5}[A-Z]{1,3}[a-z]/ && +#Ignore Page<foo> variants + $var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ && +#Ignore SI style variants like nS, mV and dB +#(ie: max_uV, regulator_min_uA_show, RANGE_mA_VALUE) + $var !~ /^(?:[a-z0-9_]*|[A-Z0-9_]*)?_?[a-z][A-Z](?:_[a-z0-9_]+|_[A-Z0-9_]+)?$/ && +#Ignore some three character SI units explicitly, like MiB and KHz + $var !~ /^(?:[a-z_]*?)_?(?:[KMGT]iB|[KMGT]?Hz)(?:_[a-z_]+)?$/) { + } + } # !$OpenOCD + # OpenOCD Specific: Begin: remove Linux exceptions, extend to camel[0-9_]*CASE + if ($var !~ /^$Constant$/ && + $var =~ /[A-Z][0-9_]*[a-z]|[a-z][0-9_]*[A-Z]/) { + # OpenOCD Specific: End + while ($var =~ m{\b($Ident)}g) { + my $word = $1; + if (!$OpenOCD) { + next if ($word !~ /[A-Z][a-z]|[a-z][A-Z]/); + } # !$OpenOCD + # OpenOCD Specific: Begin: extend to camel[0-9_]*CASE + next if ($word !~ /[A-Z][0-9_]*[a-z]|[a-z][0-9_]*[A-Z]/); + # OpenOCD Specific: End + if (!$OpenOCD) { + # This will not work for OpenOCD jenkins because it runs + # checkpatch from a tree already patched. Any new camelcase + # in include file will be ignored as it was pre-existing. + if ($check) { + seed_camelcase_includes(); + if (!$file && !$camelcase_file_seeded) { + seed_camelcase_file($realfile); + $camelcase_file_seeded = 1; + } + } + } # !$OpenOCD + if (!defined $camelcase{$word}) { + $camelcase{$word} = 1; + CHK("CAMELCASE", + "Avoid CamelCase: <$word>\n" . $herecurr); + } + } + } + } #no spaces allowed after \ in define - if ($line=~/\#\s*define.*\\\s$/) { - WARN("WHITESPACE_AFTER_LINE_CONTINUATION", - "Whitepspace after \\ makes next lines useless\n" . $herecurr); + if ($line =~ /\#\s*define.*\\\s+$/) { + if (WARN("WHITESPACE_AFTER_LINE_CONTINUATION", + "Whitespace after \\ makes next lines useless\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\s+$//; + } } -#warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line) +# warn if <asm/foo.h> is #included and <linux/foo.h> is available and includes +# itself <asm/foo.h> (uses RAW line) if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) { my $file = "$1.h"; my $checkfile = "include/linux/$file"; @@ -2736,12 +5882,15 @@ sub process { $realfile ne $checkfile && $1 !~ /$allowed_asm_includes/) { - if ($realfile =~ m{^arch/}) { - CHK("ARCH_INCLUDE_LINUX", - "Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr); - } else { - WARN("INCLUDE_LINUX", - "Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr); + my $asminclude = `grep -Ec "#include\\s+<asm/$file>" $root/$checkfile`; + if ($asminclude > 0) { + if ($realfile =~ m{^arch/}) { + CHK("ARCH_INCLUDE_LINUX", + "Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr); + } else { + WARN("INCLUDE_LINUX", + "Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr); + } } } } @@ -2755,101 +5904,201 @@ sub process { my $cnt = $realcnt; my ($off, $dstat, $dcond, $rest); my $ctx = ''; - - my $args = defined($1); - - # Find the end of the macro and limit our statement - # search to that. - while ($cnt > 0 && defined $lines[$ln - 1] && - $lines[$ln - 1] =~ /^(?:-|..*\\$)/) - { - $ctx .= $rawlines[$ln - 1] . "\n"; - $cnt-- if ($lines[$ln - 1] !~ /^-/); - $ln++; - } - $ctx .= $rawlines[$ln - 1]; - + my $has_flow_statement = 0; + my $has_arg_concat = 0; ($dstat, $dcond, $ln, $cnt, $off) = - ctx_statement_block($linenr, $ln - $linenr + 1, 0); + ctx_statement_block($linenr, $realcnt, 0); + $ctx = $dstat; #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n"; #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n"; - # Extract the remainder of the define (if any) and - # rip off surrounding spaces, and trailing \'s. - $rest = ''; - while ($off != 0 || ($cnt > 0 && $rest =~ /\\\s*$/)) { - #print "ADDING cnt<$cnt> $off <" . substr($lines[$ln - 1], $off) . "> rest<$rest>\n"; - if ($off != 0 || $lines[$ln - 1] !~ /^-/) { - $rest .= substr($lines[$ln - 1], $off) . "\n"; - $cnt--; - } - $ln++; - $off = 0; - } - $rest =~ s/\\\n.//g; - $rest =~ s/^\s*//s; - $rest =~ s/\s*$//s; - - # Clean up the original statement. - if ($args) { - substr($dstat, 0, length($dcond), ''); - } else { - $dstat =~ s/^.\s*\#\s*define\s+$Ident\s*//; + $has_flow_statement = 1 if ($ctx =~ /\b(goto|return)\b/); + $has_arg_concat = 1 if ($ctx =~ /\#\#/ && $ctx !~ /\#\#\s*(?:__VA_ARGS__|args)\b/); + + $dstat =~ s/^.\s*\#\s*define\s+$Ident(\([^\)]*\))?\s*//; + my $define_args = $1; + my $define_stmt = $dstat; + my @def_args = (); + + if (defined $define_args && $define_args ne "") { + $define_args = substr($define_args, 1, length($define_args) - 2); + $define_args =~ s/\s*//g; + $define_args =~ s/\\\+?//g; + @def_args = split(",", $define_args); } + $dstat =~ s/$;//g; $dstat =~ s/\\\n.//g; $dstat =~ s/^\s*//s; $dstat =~ s/\s*$//s; # Flatten any parentheses and braces - while ($dstat =~ s/\([^\(\)]*\)/1/ || - $dstat =~ s/\{[^\{\}]*\}/1/ || - $dstat =~ s/\[[^\{\}]*\]/1/) + while ($dstat =~ s/\([^\(\)]*\)/1u/ || + $dstat =~ s/\{[^\{\}]*\}/1u/ || + $dstat =~ s/.\[[^\[\]]*\]/1u/) + { + } + + # Flatten any obvious string concatenation. + while ($dstat =~ s/($String)\s*$Ident/$1/ || + $dstat =~ s/$Ident\s*($String)/$1/) { } + # Make asm volatile uses seem like a generic function + $dstat =~ s/\b_*asm_*\s+_*volatile_*\b/asm_volatile/g; + my $exceptions = qr{ $Declare| module_param_named| - MODULE_PARAM_DESC| + MODULE_PARM_DESC| DECLARE_PER_CPU| DEFINE_PER_CPU| __typeof__\(| union| struct| \.$Ident\s*=\s*| - ^\"|\"$ + ^\"|\"$| + ^\[ }x; #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n"; - if ($rest ne '' && $rest ne ',') { - if ($rest !~ /while\s*\(/ && - $dstat !~ /$exceptions/) - { + + $ctx =~ s/\n*$//; + my $stmt_cnt = statement_rawlines($ctx); + my $herectx = get_stat_here($linenr, $stmt_cnt, $here); + + if ($dstat ne '' && + $dstat !~ /^(?:$Ident|-?$Constant),$/ && # 10, // foo(), + $dstat !~ /^(?:$Ident|-?$Constant);$/ && # foo(); + $dstat !~ /^[!~-]?(?:$Lval|$Constant)$/ && # 10 // foo() // !foo // ~foo // -foo // foo->bar // foo.bar->baz + $dstat !~ /^'X'$/ && $dstat !~ /^'XX'$/ && # character constants + $dstat !~ /$exceptions/ && + $dstat !~ /^\.$Ident\s*=/ && # .foo = + $dstat !~ /^(?:\#\s*$Ident|\#\s*$Constant)\s*$/ && # stringification #foo + $dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ && # do {...} while (...); // do {...} while (...) + $dstat !~ /^while\s*$Constant\s*$Constant\s*$/ && # while (...) {...} + $dstat !~ /^for\s*$Constant$/ && # for (...) + $dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ && # for (...) bar() + $dstat !~ /^do\s*{/ && # do {... + $dstat !~ /^\(\{/ && # ({... + $ctx !~ /^.\s*#\s*define\s+TRACE_(?:SYSTEM|INCLUDE_FILE|INCLUDE_PATH)\b/) + { + if ($dstat =~ /^\s*if\b/) { ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE", - "Macros with multiple statements should be enclosed in a do - while loop\n" . "$here\n$ctx\n"); + "Macros starting with if should be enclosed by a do - while loop to avoid possible if/else logic defects\n" . "$herectx"); + } elsif ($dstat =~ /;/) { + ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE", + "Macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx"); + } else { + ERROR("COMPLEX_MACRO", + "Macros with complex values should be enclosed in parentheses\n" . "$herectx"); } - } elsif ($ctx !~ /;/) { - if ($dstat ne '' && - $dstat !~ /^(?:$Ident|-?$Constant)$/ && - $dstat !~ /$exceptions/ && - $dstat !~ /^\.$Ident\s*=/ && - $dstat =~ /$Operators/) - { - ERROR("COMPLEX_MACRO", - "Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n"); + } + + # Make $define_stmt single line, comment-free, etc + my @stmt_array = split('\n', $define_stmt); + my $first = 1; + $define_stmt = ""; + foreach my $l (@stmt_array) { + $l =~ s/\\$//; + if ($first) { + $define_stmt = $l; + $first = 0; + } elsif ($l =~ /^[\+ ]/) { + $define_stmt .= substr($l, 1); } } + $define_stmt =~ s/$;//g; + $define_stmt =~ s/\s+/ /g; + $define_stmt = trim($define_stmt); + +# check if any macro arguments are reused (ignore '...' and 'type') + foreach my $arg (@def_args) { + next if ($arg =~ /\.\.\./); + next if ($arg =~ /^type$/i); + my $tmp_stmt = $define_stmt; + $tmp_stmt =~ s/\b(__must_be_array|offsetof|sizeof|sizeof_field|__stringify|typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g; + $tmp_stmt =~ s/\#+\s*$arg\b//g; + $tmp_stmt =~ s/\b$arg\s*\#\#//g; + my $use_cnt = () = $tmp_stmt =~ /\b$arg\b/g; + if ($use_cnt > 1) { + CHK("MACRO_ARG_REUSE", + "Macro argument reuse '$arg' - possible side-effects?\n" . "$herectx"); + } +# check if any macro arguments may have other precedence issues + if ($tmp_stmt =~ m/($Operators)?\s*\b$arg\b\s*($Operators)?/m && + ((defined($1) && $1 ne ',') || + (defined($2) && $2 ne ','))) { + CHK("MACRO_ARG_PRECEDENCE", + "Macro argument '$arg' may be better as '($arg)' to avoid precedence issues\n" . "$herectx"); + } + } + +# check for macros with flow control, but without ## concatenation +# ## concatenation is commonly a macro that defines a function so ignore those + if ($has_flow_statement && !$has_arg_concat) { + my $cnt = statement_rawlines($ctx); + my $herectx = get_stat_here($linenr, $cnt, $here); + + WARN("MACRO_WITH_FLOW_CONTROL", + "Macros with flow control statements should be avoided\n" . "$herectx"); + } + +# check for line continuations outside of #defines, preprocessor #, and asm + + } else { + if ($prevline !~ /^..*\\$/ && + $line !~ /^\+\s*\#.*\\$/ && # preprocessor + $line !~ /^\+.*\b(__asm__|asm)\b.*\\$/ && # asm + $line =~ /^\+.*\\$/) { + WARN("LINE_CONTINUATIONS", + "Avoid unnecessary line continuations\n" . $herecurr); + } } -# make sure symbols are always wrapped with VMLINUX_SYMBOL() ... -# all assignments may have only one of the following with an assignment: -# . -# ALIGN(...) -# VMLINUX_SYMBOL(...) - if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) { - WARN("MISSING_VMLINUX_SYMBOL", - "vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr); +# do {} while (0) macro tests: +# single-statement macros do not need to be enclosed in do while (0) loop, +# macro should not end with a semicolon + if ($perl_version_ok && + $realfile !~ m@/vmlinux.lds.h$@ && + $line =~ /^.\s*\#\s*define\s+$Ident(\()?/) { + my $ln = $linenr; + my $cnt = $realcnt; + my ($off, $dstat, $dcond, $rest); + my $ctx = ''; + ($dstat, $dcond, $ln, $cnt, $off) = + ctx_statement_block($linenr, $realcnt, 0); + $ctx = $dstat; + + $dstat =~ s/\\\n.//g; + $dstat =~ s/$;/ /g; + + if ($dstat =~ /^\+\s*#\s*define\s+$Ident\s*${balanced_parens}\s*do\s*{(.*)\s*}\s*while\s*\(\s*0\s*\)\s*([;\s]*)\s*$/) { + my $stmts = $2; + my $semis = $3; + + $ctx =~ s/\n*$//; + my $cnt = statement_rawlines($ctx); + my $herectx = get_stat_here($linenr, $cnt, $here); + + if (($stmts =~ tr/;/;/) == 1 && + $stmts !~ /^\s*(if|while|for|switch)\b/) { + WARN("SINGLE_STATEMENT_DO_WHILE_MACRO", + "Single statement macros should not use a do {} while (0) loop\n" . "$herectx"); + } + if (defined $semis && $semis ne "") { + WARN("DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON", + "do {} while (0) macros should not be semicolon terminated\n" . "$herectx"); + } + } elsif ($dstat =~ /^\+\s*#\s*define\s+$Ident.*;\s*$/) { + $ctx =~ s/\n*$//; + my $cnt = statement_rawlines($ctx); + my $herectx = get_stat_here($linenr, $cnt, $here); + + WARN("TRAILING_SEMICOLON", + "macros should not use a trailing semicolon\n" . "$herectx"); + } } # check for redundant bracing round if etc @@ -2859,7 +6108,8 @@ sub process { #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n"; #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n"; if ($#chunks > 0 && $level == 0) { - my $allowed = 0; + my @allowed = (); + my $allow = 0; my $seen = 0; my $herectx = $here . "\n"; my $ln = $linenr - 1; @@ -2870,6 +6120,7 @@ sub process { my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s); my $offset = statement_rawlines($whitespace) - 1; + $allowed[$allow] = 0; #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n"; # We have looked at and allowed this specific line. @@ -2880,25 +6131,36 @@ sub process { substr($block, 0, length($cond), ''); - $seen++ if ($block =~ /^\s*\{/); + $seen++ if ($block =~ /^\s*{/); - #print "cond<$cond> block<$block> allowed<$allowed>\n"; + #print "cond<$cond> block<$block> allowed<$allowed[$allow]>\n"; if (statement_lines($cond) > 1) { #print "APW: ALLOWED: cond<$cond>\n"; - $allowed = 1; + $allowed[$allow] = 1; } if ($block =~/\b(?:if|for|while)\b/) { #print "APW: ALLOWED: block<$block>\n"; - $allowed = 1; + $allowed[$allow] = 1; } if (statement_block_size($block) > 1) { #print "APW: ALLOWED: lines block<$block>\n"; - $allowed = 1; + $allowed[$allow] = 1; } + $allow++; } - if ($seen && !$allowed) { - WARN("BRACES", - "braces {} are not necessary for any arm of this statement\n" . $herectx); + if ($seen) { + my $sum_allowed = 0; + foreach (@allowed) { + $sum_allowed += $_; + } + if ($sum_allowed == 0) { + WARN("BRACES", + "braces {} are not necessary for any arm of this statement\n" . $herectx); + } elsif ($sum_allowed != $allow && + $seen != $allow) { + CHK("BRACES", + "braces {} should be used on all arms of this statement\n" . $herectx); + } } } } @@ -2945,71 +6207,377 @@ sub process { } } if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) { - my $herectx = $here . "\n"; my $cnt = statement_rawlines($block); - - for (my $n = 0; $n < $cnt; $n++) { - $herectx .= raw_line($linenr, $n) . "\n"; - } + my $herectx = get_stat_here($linenr, $cnt, $here); WARN("BRACES", "braces {} are not necessary for single statement blocks\n" . $herectx); } } -# don't include deprecated include files (uses RAW line) - for my $inc (@dep_includes) { - if ($rawline =~ m@^.\s*\#\s*include\s*\<$inc>@) { - ERROR("DEPRECATED_INCLUDE", - "Don't use <$inc>: see Documentation/feature-removal-schedule.txt\n" . $herecurr); - } +# check for single line unbalanced braces + if ($sline =~ /^.\s*\}\s*else\s*$/ || + $sline =~ /^.\s*else\s*\{\s*$/) { + CHK("BRACES", "Unbalanced braces around else statement\n" . $herecurr); } -# don't use deprecated functions - for my $func (@dep_functions) { - if ($line =~ /\b$func\b/) { - ERROR("DEPRECATED_FUNCTION", - "Don't use $func(): see Documentation/feature-removal-schedule.txt\n" . $herecurr); +# check for unnecessary blank lines around braces + if (($line =~ /^.\s*}\s*$/ && $prevrawline =~ /^.\s*$/)) { + if (CHK("BRACES", + "Blank lines aren't necessary before a close brace '}'\n" . $hereprev) && + $fix && $prevrawline =~ /^\+/) { + fix_delete_line($fixlinenr - 1, $prevrawline); + } + } + if (($rawline =~ /^.\s*$/ && $prevline =~ /^..*{\s*$/)) { + if (CHK("BRACES", + "Blank lines aren't necessary after an open brace '{'\n" . $hereprev) && + $fix) { + fix_delete_line($fixlinenr, $rawline); } } # no volatiles please -# my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b}; -# if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) { -# WARN("VOLATILE", -# "Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr); -# } + my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b}; + if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) { + WARN("VOLATILE", + "Use of volatile is usually wrong: see Documentation/process/volatile-considered-harmful.rst\n" . $herecurr); + } + +# Check for user-visible strings broken across lines, which breaks the ability +# to grep for the string. Make exceptions when the previous string ends in a +# newline (multiple lines in one string constant) or '\t', '\r', ';', or '{' +# (common in inline assembly) or is a octal \123 or hexadecimal \xaf value + if ($line =~ /^\+\s*$String/ && + $prevline =~ /"\s*$/ && + $prevrawline !~ /(?:\\(?:[ntr]|[0-7]{1,3}|x[0-9a-fA-F]{1,2})|;\s*|\{\s*)"\s*$/) { + if (WARN("SPLIT_STRING", + "quoted string split across lines\n" . $hereprev) && + $fix && + $prevrawline =~ /^\+.*"\s*$/ && + $last_coalesced_string_linenr != $linenr - 1) { + my $extracted_string = get_quoted_string($line, $rawline); + my $comma_close = ""; + if ($rawline =~ /\Q$extracted_string\E(\s*\)\s*;\s*$|\s*,\s*)/) { + $comma_close = $1; + } + + fix_delete_line($fixlinenr - 1, $prevrawline); + fix_delete_line($fixlinenr, $rawline); + my $fixedline = $prevrawline; + $fixedline =~ s/"\s*$//; + $fixedline .= substr($extracted_string, 1) . trim($comma_close); + fix_insert_line($fixlinenr - 1, $fixedline); + $fixedline = $rawline; + $fixedline =~ s/\Q$extracted_string\E\Q$comma_close\E//; + if ($fixedline !~ /\+\s*$/) { + fix_insert_line($fixlinenr, $fixedline); + } + $last_coalesced_string_linenr = $linenr; + } + } + +# check for missing a space in a string concatenation + if ($prevrawline =~ /[^\\]\w"$/ && $rawline =~ /^\+[\t ]+"\w/) { + WARN('MISSING_SPACE', + "break quoted strings at a space character\n" . $hereprev); + } + +# check for an embedded function name in a string when the function is known +# This does not work very well for -f --file checking as it depends on patch +# context providing the function name or a single line form for in-file +# function declarations + if ($line =~ /^\+.*$String/ && + defined($context_function) && + get_quoted_string($line, $rawline) =~ /\b$context_function\b/ && + length(get_quoted_string($line, $rawline)) != (length($context_function) + 2)) { + WARN("EMBEDDED_FUNCTION_NAME", + "Prefer using '\"%s...\", __func__' to using '$context_function', this function's name, in a string\n" . $herecurr); + } + +# check for unnecessary function tracing like uses +# This does not use $logFunctions because there are many instances like +# 'dprintk(FOO, "%s()\n", __func__);' which do not match $logFunctions + if ($rawline =~ /^\+.*\([^"]*"$tracing_logging_tags{0,3}%s(?:\s*\(\s*\)\s*)?$tracing_logging_tags{0,3}(?:\\n)?"\s*,\s*__func__\s*\)\s*;/) { + if (WARN("TRACING_LOGGING", + "Unnecessary ftrace-like logging - prefer using ftrace\n" . $herecurr) && + $fix) { + fix_delete_line($fixlinenr, $rawline); + } + } + +# check for spaces before a quoted newline + if ($rawline =~ /^.*\".*\s\\n/) { + if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE", + "unnecessary whitespace before a quoted newline\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/^(\+.*\".*)\s+\\n/$1\\n/; + } + + } + +# concatenated string without spaces between elements + if ($line =~ /$String[A-Z_]/ || + ($line =~ /([A-Za-z0-9_]+)$String/ && $1 !~ /^[Lu]$/)) { + if (CHK("CONCATENATED_STRING", + "Concatenated strings should use spaces between elements\n" . $herecurr) && + $fix) { + while ($line =~ /($String)/g) { + my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]); + $fixed[$fixlinenr] =~ s/\Q$extracted_string\E([A-Za-z0-9_])/$extracted_string $1/; + $fixed[$fixlinenr] =~ s/([A-Za-z0-9_])\Q$extracted_string\E/$1 $extracted_string/; + } + } + } + +# uncoalesced string fragments + if ($line =~ /$String\s*[Lu]?"/) { + if (WARN("STRING_FRAGMENTS", + "Consecutive strings are generally better as a single string\n" . $herecurr) && + $fix) { + while ($line =~ /($String)(?=\s*")/g) { + my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]); + $fixed[$fixlinenr] =~ s/\Q$extracted_string\E\s*"/substr($extracted_string, 0, -1)/e; + } + } + } + +# check for non-standard and hex prefixed decimal printf formats + my $show_L = 1; #don't show the same defect twice + my $show_Z = 1; + while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { + my $string = substr($rawline, $-[1], $+[1] - $-[1]); + $string =~ s/%%/__/g; + # check for %L + if ($show_L && $string =~ /%[\*\d\.\$]*L([diouxX])/) { + WARN("PRINTF_L", + "\%L$1 is non-standard C, use %ll$1\n" . $herecurr); + $show_L = 0; + } + # check for %Z + if ($show_Z && $string =~ /%[\*\d\.\$]*Z([diouxX])/) { + WARN("PRINTF_Z", + "%Z$1 is non-standard C, use %z$1\n" . $herecurr); + $show_Z = 0; + } + # check for 0x<decimal> + if ($string =~ /0x%[\*\d\.\$\Llzth]*[diou]/) { + ERROR("PRINTF_0XDECIMAL", + "Prefixing 0x with decimal output is defective\n" . $herecurr); + } + } + +# check for line continuations in quoted strings with odd counts of " + if ($rawline =~ /\\$/ && $sline =~ tr/"/"/ % 2) { + WARN("LINE_CONTINUATIONS", + "Avoid line continuations in quoted strings\n" . $herecurr); + } # warn about #if 0 if ($line =~ /^.\s*\#\s*if\s+0\b/) { - CHK("REDUNDANT_CODE", - "if this code is redundant consider removing it\n" . - $herecurr); + WARN("IF_0", + "Consider removing the code enclosed by this #if 0 and its #endif\n" . $herecurr); + } + +# warn about #if 1 + if ($line =~ /^.\s*\#\s*if\s+1\b/) { + WARN("IF_1", + "Consider removing the #if 1 and its #endif\n" . $herecurr); + } + +# check for needless "if (<foo>) fn(<foo>)" uses + if ($prevline =~ /\bif\s*\(\s*($Lval)\s*\)/) { + my $tested = quotemeta($1); + my $expr = '\s*\(\s*' . $tested . '\s*\)\s*;'; + if ($line =~ /\b(kfree|usb_free_urb|debugfs_remove(?:_recursive)?|(?:kmem_cache|mempool|dma_pool)_destroy)$expr/) { + my $func = $1; + if (WARN('NEEDLESS_IF', + "$func(NULL) is safe and this check is probably not required\n" . $hereprev) && + $fix) { + my $do_fix = 1; + my $leading_tabs = ""; + my $new_leading_tabs = ""; + if ($lines[$linenr - 2] =~ /^\+(\t*)if\s*\(\s*$tested\s*\)\s*$/) { + $leading_tabs = $1; + } else { + $do_fix = 0; + } + if ($lines[$linenr - 1] =~ /^\+(\t+)$func\s*\(\s*$tested\s*\)\s*;\s*$/) { + $new_leading_tabs = $1; + if (length($leading_tabs) + 1 ne length($new_leading_tabs)) { + $do_fix = 0; + } + } else { + $do_fix = 0; + } + if ($do_fix) { + fix_delete_line($fixlinenr - 1, $prevrawline); + $fixed[$fixlinenr] =~ s/^\+$new_leading_tabs/\+$leading_tabs/; + } + } + } + } + +# check for unnecessary "Out of Memory" messages + if ($line =~ /^\+.*\b$logFunctions\s*\(/ && + $prevline =~ /^[ \+]\s*if\s*\(\s*(\!\s*|NULL\s*==\s*)?($Lval)(\s*==\s*NULL\s*)?\s*\)/ && + (defined $1 || defined $3) && + $linenr > 3) { + my $testval = $2; + my $testline = $lines[$linenr - 3]; + + my ($s, $c) = ctx_statement_block($linenr - 3, $realcnt, 0); +# print("line: <$line>\nprevline: <$prevline>\ns: <$s>\nc: <$c>\n\n\n"); + + if ($s =~ /(?:^|\n)[ \+]\s*(?:$Type\s*)?\Q$testval\E\s*=\s*(?:\([^\)]*\)\s*)?\s*$allocFunctions\s*\(/ && + $s !~ /\b__GFP_NOWARN\b/ ) { + WARN("OOM_MESSAGE", + "Possible unnecessary 'out of memory' message\n" . $hereprev); + } + } + +# check for logging functions with KERN_<LEVEL> + if ($line !~ /printk(?:_ratelimited|_once)?\s*\(/ && + $line =~ /\b$logFunctions\s*\(.*\b(KERN_[A-Z]+)\b/) { + my $level = $1; + if (WARN("UNNECESSARY_KERN_LEVEL", + "Possible unnecessary $level\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\s*$level\s*//; + } + } + +# check for logging continuations + if ($line =~ /\bprintk\s*\(\s*KERN_CONT\b|\bpr_cont\s*\(/) { + WARN("LOGGING_CONTINUATION", + "Avoid logging continuation uses where feasible\n" . $herecurr); + } + +# check for unnecessary use of %h[xudi] and %hh[xudi] in logging functions + if (defined $stat && + $line =~ /\b$logFunctions\s*\(/ && + index($stat, '"') >= 0) { + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + my $stat_real = get_stat_real($linenr, $lc); + pos($stat_real) = index($stat_real, '"'); + while ($stat_real =~ /[^\"%]*(%[\#\d\.\*\-]*(h+)[idux])/g) { + my $pspec = $1; + my $h = $2; + my $lineoff = substr($stat_real, 0, $-[1]) =~ tr@\n@@; + if (WARN("UNNECESSARY_MODIFIER", + "Integer promotion: Using '$h' in '$pspec' is unnecessary\n" . "$here\n$stat_real\n") && + $fix && $fixed[$fixlinenr + $lineoff] =~ /^\+/) { + my $nspec = $pspec; + $nspec =~ s/h//g; + $fixed[$fixlinenr + $lineoff] =~ s/\Q$pspec\E/$nspec/; + } + } + } + +# check for mask then right shift without a parentheses + if ($perl_version_ok && + $line =~ /$LvalOrFunc\s*\&\s*($LvalOrFunc)\s*>>/ && + $4 !~ /^\&/) { # $LvalOrFunc may be &foo, ignore if so + WARN("MASK_THEN_SHIFT", + "Possible precedence defect with mask then right shift - may need parentheses\n" . $herecurr); + } + +# check for pointer comparisons to NULL + if ($perl_version_ok) { + while ($line =~ /\b$LvalOrFunc\s*(==|\!=)\s*NULL\b/g) { + my $val = $1; + my $equal = "!"; + $equal = "" if ($4 eq "!="); + if (CHK("COMPARISON_TO_NULL", + "Comparison to NULL could be written \"${equal}${val}\"\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b\Q$val\E\s*(?:==|\!=)\s*NULL\b/$equal$val/; + } + } + } + +# check for bad placement of section $InitAttribute (e.g.: __initdata) + if ($line =~ /(\b$InitAttribute\b)/) { + my $attr = $1; + if ($line =~ /^\+\s*static\s+(?:const\s+)?(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*[=;]/) { + my $ptr = $1; + my $var = $2; + if ((($ptr =~ /\b(union|struct)\s+$attr\b/ && + ERROR("MISPLACED_INIT", + "$attr should be placed after $var\n" . $herecurr)) || + ($ptr !~ /\b(union|struct)\s+$attr\b/ && + WARN("MISPLACED_INIT", + "$attr should be placed after $var\n" . $herecurr))) && + $fix) { + $fixed[$fixlinenr] =~ s/(\bstatic\s+(?:const\s+)?)(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*([=;])\s*/"$1" . trim(string_find_replace($2, "\\s*$attr\\s*", " ")) . " " . trim(string_find_replace($3, "\\s*$attr\\s*", "")) . " $attr" . ("$4" eq ";" ? ";" : " = ")/e; + } + } + } + +# check for $InitAttributeData (ie: __initdata) with const + if ($line =~ /\bconst\b/ && $line =~ /($InitAttributeData)/) { + my $attr = $1; + $attr =~ /($InitAttributePrefix)(.*)/; + my $attr_prefix = $1; + my $attr_type = $2; + if (ERROR("INIT_ATTRIBUTE", + "Use of const init definition must use ${attr_prefix}initconst\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/$InitAttributeData/${attr_prefix}initconst/; + } + } + +# check for $InitAttributeConst (ie: __initconst) without const + if ($line !~ /\bconst\b/ && $line =~ /($InitAttributeConst)/) { + my $attr = $1; + if (ERROR("INIT_ATTRIBUTE", + "Use of $attr requires a separate use of const\n" . $herecurr) && + $fix) { + my $lead = $fixed[$fixlinenr] =~ + /(^\+\s*(?:static\s+))/; + $lead = rtrim($1); + $lead = "$lead " if ($lead !~ /^\+$/); + $lead = "${lead}const "; + $fixed[$fixlinenr] =~ s/(^\+\s*(?:static\s+))/$lead/; + } } -# check for needless kfree() checks - if ($prevline =~ /\bif\s*\(([^\)]*)\)/) { - my $expr = $1; - if ($line =~ /\bkfree\(\Q$expr\E\);/) { - WARN("NEEDLESS_KFREE", - "kfree(NULL) is safe this check is probably not required\n" . $hereprev); +# check for __read_mostly with const non-pointer (should just be const) + if ($line =~ /\b__read_mostly\b/ && + $line =~ /($Type)\s*$Ident/ && $1 !~ /\*\s*$/ && $1 =~ /\bconst\b/) { + if (ERROR("CONST_READ_MOSTLY", + "Invalid use of __read_mostly with const type\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\s+__read_mostly\b//; } } -# check for needless usb_free_urb() checks - if ($prevline =~ /\bif\s*\(([^\)]*)\)/) { - my $expr = $1; - if ($line =~ /\busb_free_urb\(\Q$expr\E\);/) { - WARN("NEEDLESS_USB_FREE_URB", - "usb_free_urb(NULL) is safe this check is probably not required\n" . $hereprev); + +# don't use __constant_<foo> functions outside of include/uapi/ + if ($realfile !~ m@^include/uapi/@ && + $line =~ /(__constant_(?:htons|ntohs|[bl]e(?:16|32|64)_to_cpu|cpu_to_[bl]e(?:16|32|64)))\s*\(/) { + my $constant_func = $1; + my $func = $constant_func; + $func =~ s/^__constant_//; + if (WARN("CONSTANT_CONVERSION", + "$constant_func should be $func\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b$constant_func\b/$func/g; } } # prefer usleep_range over udelay - if ($line =~ /\budelay\s*\(\s*(\w+)\s*\)/) { + if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) { + my $delay = $1; # ignore udelay's < 10, however - if (! (($1 =~ /(\d+)/) && ($1 < 10)) ) { + if (! ($delay < 10) ) { CHK("USLEEP_RANGE", - "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $line); + "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst\n" . $herecurr); + } + if ($delay > 2000) { + WARN("LONG_UDELAY", + "long udelay - prefer mdelay; see arch/arm/include/asm/delay.h\n" . $herecurr); } } @@ -3017,10 +6585,22 @@ sub process { if ($line =~ /\bmsleep\s*\((\d+)\);/) { if ($1 < 20) { WARN("MSLEEP", - "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $line); + "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.rst\n" . $herecurr); } } +# check for comparisons of jiffies + if ($line =~ /\bjiffies\s*$Compare|$Compare\s*jiffies\b/) { + WARN("JIFFIES_COMPARISON", + "Comparing jiffies is almost always wrong; prefer time_after, time_before and friends\n" . $herecurr); + } + +# check for comparisons of get_jiffies_64() + if ($line =~ /\bget_jiffies_64\s*\(\s*\)\s*$Compare|$Compare\s*get_jiffies_64\s*\(\s*\)/) { + WARN("JIFFIES_COMPARISON", + "Comparing get_jiffies_64() is almost always wrong; prefer time_after64, time_before64 and friends\n" . $herecurr); + } + # warn about #ifdefs in C files # if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) { # print "#ifdef in C files should be avoided\n"; @@ -3030,8 +6610,13 @@ sub process { # warn about spacing in #ifdefs if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) { - ERROR("SPACING", - "exactly one space required after that #$1\n" . $herecurr); + if (ERROR("SPACING", + "exactly one space required after that #$1\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/^(.\s*\#\s*(ifdef|ifndef|elif))\s{2,}/$1 /; + } + } # check for spinlock_t definitions without a comment. @@ -3044,22 +6629,77 @@ sub process { } } # check for memory barriers without a comment. - if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) { + + my $barriers = qr{ + mb| + rmb| + wmb + }x; + my $barrier_stems = qr{ + mb__before_atomic| + mb__after_atomic| + store_release| + load_acquire| + store_mb| + (?:$barriers) + }x; + my $all_barriers = qr{ + (?:$barriers)| + smp_(?:$barrier_stems)| + virt_(?:$barrier_stems) + }x; + + if ($line =~ /\b(?:$all_barriers)\s*\(/) { + if (!ctx_has_comment($first_line, $linenr)) { + WARN("MEMORY_BARRIER", + "memory barrier without comment\n" . $herecurr); + } + } + + my $underscore_smp_barriers = qr{__smp_(?:$barrier_stems)}x; + + if ($realfile !~ m@^include/asm-generic/@ && + $realfile !~ m@/barrier\.h$@ && + $line =~ m/\b(?:$underscore_smp_barriers)\s*\(/ && + $line !~ m/^.\s*\#\s*define\s+(?:$underscore_smp_barriers)\s*\(/) { + WARN("MEMORY_BARRIER", + "__smp memory barriers shouldn't be used outside barrier.h and asm-generic\n" . $herecurr); + } + +# check for waitqueue_active without a comment. + if ($line =~ /\bwaitqueue_active\s*\(/) { + if (!ctx_has_comment($first_line, $linenr)) { + WARN("WAITQUEUE_ACTIVE", + "waitqueue_active without comment\n" . $herecurr); + } + } + +# check for data_race without a comment. + if ($line =~ /\bdata_race\s*\(/) { if (!ctx_has_comment($first_line, $linenr)) { - CHK("MEMORY_BARRIER", - "memory barrier without comment\n" . $herecurr); + WARN("DATA_RACE", + "data_race without comment\n" . $herecurr); } } + # check of hardware specific defines if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) { CHK("ARCH_DEFINES", "architecture specific defines should be avoided\n" . $herecurr); } +# check that the storage class is not after a type + if ($line =~ /\b($Type)\s+($Storage)\b/) { + WARN("STORAGE_CLASS", + "storage class '$2' should be located before type '$1'\n" . $herecurr); + } # Check that the storage class is at the beginning of a declaration - if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) { + if ($line =~ /\b$Storage\b/ && + $line !~ /^.\s*$Storage/ && + $line =~ /^.\s*(.+?)\$Storage\s/ && + $1 !~ /[\,\)]\s*$/) { WARN("STORAGE_CLASS", - "storage class should be at the beginning of the declaration\n" . $herecurr) + "storage class should be at the beginning of the declaration\n" . $herecurr); } # check the location of the inline attribute, that it is between @@ -3071,22 +6711,128 @@ sub process { } # Check for __inline__ and __inline, prefer inline - if ($line =~ /\b(__inline__|__inline)\b/) { - WARN("INLINE", - "plain inline is preferred over $1\n" . $herecurr); + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b(__inline__|__inline)\b/) { + if (WARN("INLINE", + "plain inline is preferred over $1\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b(__inline__|__inline)\b/inline/; + + } } -# Check for __attribute__ packed, prefer __packed -# if ($line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/) { -# WARN("PREFER_PACKED", -# "__packed is preferred over __attribute__((packed))\n" . $herecurr); -# } +# Check for compiler attributes + if ($realfile !~ m@\binclude/uapi/@ && + $rawline =~ /\b__attribute__\s*\(\s*($balanced_parens)\s*\)/) { + my $attr = $1; + $attr =~ s/\s*\(\s*(.*)\)\s*/$1/; + + my %attr_list = ( + "alias" => "__alias", + "aligned" => "__aligned", + "always_inline" => "__always_inline", + "assume_aligned" => "__assume_aligned", + "cold" => "__cold", + "const" => "__attribute_const__", + "copy" => "__copy", + "designated_init" => "__designated_init", + "externally_visible" => "__visible", + "format" => "printf|scanf", + "gnu_inline" => "__gnu_inline", + "malloc" => "__malloc", + "mode" => "__mode", + "no_caller_saved_registers" => "__no_caller_saved_registers", + "noclone" => "__noclone", + "noinline" => "noinline", + "nonstring" => "__nonstring", + "noreturn" => "__noreturn", + "packed" => "__packed", + "pure" => "__pure", + "section" => "__section", + "used" => "__used", + "weak" => "__weak" + ); + + while ($attr =~ /\s*(\w+)\s*(${balanced_parens})?/g) { + my $orig_attr = $1; + my $params = ''; + $params = $2 if defined($2); + my $curr_attr = $orig_attr; + $curr_attr =~ s/^[\s_]+|[\s_]+$//g; + if (exists($attr_list{$curr_attr})) { + my $new = $attr_list{$curr_attr}; + if ($curr_attr eq "format" && $params) { + $params =~ /^\s*\(\s*(\w+)\s*,\s*(.*)/; + $new = "__$1\($2"; + } else { + $new = "$new$params"; + } + if (WARN("PREFER_DEFINED_ATTRIBUTE_MACRO", + "Prefer $new over __attribute__(($orig_attr$params))\n" . $herecurr) && + $fix) { + my $remove = "\Q$orig_attr\E" . '\s*' . "\Q$params\E" . '(?:\s*,\s*)?'; + $fixed[$fixlinenr] =~ s/$remove//; + $fixed[$fixlinenr] =~ s/\b__attribute__/$new __attribute__/; + $fixed[$fixlinenr] =~ s/\}\Q$new\E/} $new/; + $fixed[$fixlinenr] =~ s/ __attribute__\s*\(\s*\(\s*\)\s*\)//; + } + } + } -# Check for __attribute__ aligned, prefer __aligned -# if ($line =~ /\b__attribute__\s*\(\s*\(.*aligned/) { -# WARN("PREFER_ALIGNED", -# "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr); -# } + # Check for __attribute__ unused, prefer __always_unused or __maybe_unused + if ($attr =~ /^_*unused/) { + WARN("PREFER_DEFINED_ATTRIBUTE_MACRO", + "__always_unused or __maybe_unused is preferred over __attribute__((__unused__))\n" . $herecurr); + } + } + +# Check for __attribute__ weak, or __weak declarations (may have link issues) + if ($perl_version_ok && + $line =~ /(?:$Declare|$DeclareMisordered)\s*$Ident\s*$balanced_parens\s*(?:$Attribute)?\s*;/ && + ($line =~ /\b__attribute__\s*\(\s*\(.*\bweak\b/ || + $line =~ /\b__weak\b/)) { + ERROR("WEAK_DECLARATION", + "Using weak declarations can have unintended link defects\n" . $herecurr); + } + +# check for c99 types like uint8_t used outside of uapi/ and tools/ + if ($realfile !~ m@\binclude/uapi/@ && + $realfile !~ m@\btools/@ && + $line =~ /\b($Declare)\s*$Ident\s*[=;,\[]/) { + my $type = $1; + if ($type =~ /\b($typeC99Typedefs)\b/) { + $type = $1; + my $kernel_type = 'u'; + $kernel_type = 's' if ($type =~ /^_*[si]/); + $type =~ /(\d+)/; + $kernel_type .= $1; + if (CHK("PREFER_KERNEL_TYPES", + "Prefer kernel type '$kernel_type' over '$type'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b$type\b/$kernel_type/; + } + } + } + +# check for cast of C90 native int or longer types constants + if ($line =~ /(\(\s*$C90_int_types\s*\)\s*)($Constant)\b/) { + my $cast = $1; + my $const = $2; + my $suffix = ""; + my $newconst = $const; + $newconst =~ s/${Int_type}$//; + $suffix .= 'U' if ($cast =~ /\bunsigned\b/); + if ($cast =~ /\blong\s+long\b/) { + $suffix .= 'LL'; + } elsif ($cast =~ /\blong\b/) { + $suffix .= 'L'; + } + if (WARN("TYPECAST_INT_CONSTANT", + "Unnecessary typecast of c90 int constant - '$cast$const' could be '$const$suffix'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\Q$cast\E$const\b/$newconst$suffix/; + } + } # check for sizeof(&) if ($line =~ /\bsizeof\s*\(\s*\&/) { @@ -3094,156 +6840,573 @@ sub process { "sizeof(& should be avoided\n" . $herecurr); } -# check for line continuations in quoted strings with odd counts of " - if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) { - WARN("LINE_CONTINUATIONS", - "Avoid line continuations in quoted strings\n" . $herecurr); +# check for sizeof without parenthesis + if ($line =~ /\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/) { + if (WARN("SIZEOF_PARENTHESIS", + "sizeof $1 should be sizeof($1)\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/"sizeof(" . trim($1) . ")"/ex; + } } -# check for new externs in .c files. -# if ($realfile =~ /\.c$/ && defined $stat && -# $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s) -# { -# my $function_name = $1; -# my $paren_space = $2; -# -# my $s = $stat; -# if (defined $cond) { -# substr($s, 0, length($cond), ''); -# } -# if ($s =~ /^\s*;/ && -# $function_name ne 'uninitialized_var') -# { -# WARN("AVOID_EXTERNS", -# "externs should be avoided in .c files\n" . $herecurr); +# check for struct spinlock declarations + if ($line =~ /^.\s*\bstruct\s+spinlock\s+\w+\s*;/) { + WARN("USE_SPINLOCK_T", + "struct spinlock should be spinlock_t\n" . $herecurr); + } + +# check for seq_printf uses that could be seq_puts + if ($sline =~ /\bseq_printf\s*\(.*"\s*\)\s*;\s*$/) { + my $fmt = get_quoted_string($line, $rawline); + $fmt =~ s/%%//g; + if ($fmt !~ /%/) { + if (WARN("PREFER_SEQ_PUTS", + "Prefer seq_puts to seq_printf\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bseq_printf\b/seq_puts/; + } + } + } + +# check for vsprintf extension %p<foo> misuses + if ($perl_version_ok && + defined $stat && + $stat =~ /^\+(?![^\{]*\{\s*).*\b(\w+)\s*\(.*$String\s*,/s && + $1 !~ /^_*volatile_*$/) { + my $stat_real; + + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + for (my $count = $linenr; $count <= $lc; $count++) { + my $specifier; + my $extension; + my $qualifier; + my $bad_specifier = ""; + my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0)); + $fmt =~ s/%%//g; + + while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*))/g) { + $specifier = $1; + $extension = $2; + $qualifier = $3; + if ($extension !~ /[4SsBKRraEehMmIiUDdgVCbGNOxtf]/ || + ($extension eq "f" && + defined $qualifier && $qualifier !~ /^w/) || + ($extension eq "4" && + defined $qualifier && $qualifier !~ /^cc/)) { + $bad_specifier = $specifier; + last; + } + if ($extension eq "x" && !defined($stat_real)) { + if (!defined($stat_real)) { + $stat_real = get_stat_real($linenr, $lc); + } + WARN("VSPRINTF_SPECIFIER_PX", + "Using vsprintf specifier '\%px' potentially exposes the kernel memory layout, if you don't really need the address please consider using '\%p'.\n" . "$here\n$stat_real\n"); + } + } + if ($bad_specifier ne "") { + my $stat_real = get_stat_real($linenr, $lc); + my $ext_type = "Invalid"; + my $use = ""; + if ($bad_specifier =~ /p[Ff]/) { + $use = " - use %pS instead"; + $use =~ s/pS/ps/ if ($bad_specifier =~ /pf/); + } + + WARN("VSPRINTF_POINTER_EXTENSION", + "$ext_type vsprintf pointer extension '$bad_specifier'$use\n" . "$here\n$stat_real\n"); + } + } + } + +# Check for misused memsets + if ($perl_version_ok && + defined $stat && + $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/) { + + my $ms_addr = $2; + my $ms_val = $7; + my $ms_size = $12; + + if ($ms_size =~ /^(0x|)0$/i) { + ERROR("MEMSET", + "memset to 0's uses 0 as the 2nd argument, not the 3rd\n" . "$here\n$stat\n"); + } elsif ($ms_size =~ /^(0x|)1$/i) { + WARN("MEMSET", + "single byte memset is suspicious. Swapped 2nd/3rd argument?\n" . "$here\n$stat\n"); + } + } + +# Check for memcpy(foo, bar, ETH_ALEN) that could be ether_addr_copy(foo, bar) +# if ($perl_version_ok && +# defined $stat && +# $stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { +# if (WARN("PREFER_ETHER_ADDR_COPY", +# "Prefer ether_addr_copy() over memcpy() if the Ethernet addresses are __aligned(2)\n" . "$here\n$stat\n") && +# $fix) { +# $fixed[$fixlinenr] =~ s/\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/ether_addr_copy($2, $7)/; # } +# } + +# Check for memcmp(foo, bar, ETH_ALEN) that could be ether_addr_equal*(foo, bar) +# if ($perl_version_ok && +# defined $stat && +# $stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { +# WARN("PREFER_ETHER_ADDR_EQUAL", +# "Prefer ether_addr_equal() or ether_addr_equal_unaligned() over memcmp()\n" . "$here\n$stat\n") +# } + +# check for memset(foo, 0x0, ETH_ALEN) that could be eth_zero_addr +# check for memset(foo, 0xFF, ETH_ALEN) that could be eth_broadcast_addr +# if ($perl_version_ok && +# defined $stat && +# $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { # -# if ($paren_space =~ /\n/) { -# WARN("FUNCTION_ARGUMENTS", -# "arguments for function declarations should follow identifier\n" . $herecurr); -# } +# my $ms_val = $7; # -# } elsif ($realfile =~ /\.c$/ && defined $stat && -# $stat =~ /^.\s*extern\s+/) -# { -# WARN("AVOID_EXTERNS", -# "externs should be avoided in .c files\n" . $herecurr); +# if ($ms_val =~ /^(?:0x|)0+$/i) { +# if (WARN("PREFER_ETH_ZERO_ADDR", +# "Prefer eth_zero_addr over memset()\n" . "$here\n$stat\n") && +# $fix) { +# $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_zero_addr($2)/; +# } +# } elsif ($ms_val =~ /^(?:0xff|255)$/i) { +# if (WARN("PREFER_ETH_BROADCAST_ADDR", +# "Prefer eth_broadcast_addr() over memset()\n" . "$here\n$stat\n") && +# $fix) { +# $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_broadcast_addr($2)/; +# } +# } # } +# strlcpy uses that should likely be strscpy + if ($line =~ /\bstrlcpy\s*\(/) { + WARN("STRLCPY", + "Prefer strscpy over strlcpy - see: https://lore.kernel.org/r/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw\@mail.gmail.com/\n" . $herecurr); + } + +# typecasts on min/max could be min_t/max_t + if ($perl_version_ok && + defined $stat && + $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) { + if (defined $2 || defined $7) { + my $call = $1; + my $cast1 = deparenthesize($2); + my $arg1 = $3; + my $cast2 = deparenthesize($7); + my $arg2 = $8; + my $cast; + + if ($cast1 ne "" && $cast2 ne "" && $cast1 ne $cast2) { + $cast = "$cast1 or $cast2"; + } elsif ($cast1 ne "") { + $cast = $cast1; + } else { + $cast = $cast2; + } + WARN("MINMAX", + "$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . "$here\n$stat\n"); + } + } + +# check usleep_range arguments + if ($perl_version_ok && + defined $stat && + $stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) { + my $min = $1; + my $max = $7; + if ($min eq $max) { + WARN("USLEEP_RANGE", + "usleep_range should not use min == max args; see Documentation/timers/timers-howto.rst\n" . "$here\n$stat\n"); + } elsif ($min =~ /^\d+$/ && $max =~ /^\d+$/ && + $min > $max) { + WARN("USLEEP_RANGE", + "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.rst\n" . "$here\n$stat\n"); + } + } + +# check for naked sscanf + if ($perl_version_ok && + defined $stat && + $line =~ /\bsscanf\b/ && + ($stat !~ /$Ident\s*=\s*sscanf\s*$balanced_parens/ && + $stat !~ /\bsscanf\s*$balanced_parens\s*(?:$Compare)/ && + $stat !~ /(?:$Compare)\s*\bsscanf\s*$balanced_parens/)) { + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + my $stat_real = get_stat_real($linenr, $lc); + WARN("NAKED_SSCANF", + "unchecked sscanf return value\n" . "$here\n$stat_real\n"); + } + +# check for simple sscanf that should be kstrto<foo> + if ($perl_version_ok && + defined $stat && + $line =~ /\bsscanf\b/) { + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + my $stat_real = get_stat_real($linenr, $lc); + if ($stat_real =~ /\bsscanf\b\s*\(\s*$FuncArg\s*,\s*("[^"]+")/) { + my $format = $6; + my $count = $format =~ tr@%@%@; + if ($count == 1 && + $format =~ /^"\%(?i:ll[udxi]|[udxi]ll|ll|[hl]h?[udxi]|[udxi][hl]h?|[hl]h?|[udxi])"$/) { + WARN("SSCANF_TO_KSTRTO", + "Prefer kstrto<type> to single variable sscanf\n" . "$here\n$stat_real\n"); + } + } + } + +# check for new externs in .h files. + if ($realfile =~ /\.h$/ && + $line =~ /^\+\s*(extern\s+)$Type\s*$Ident\s*\(/s) { + if (CHK("AVOID_EXTERNS", + "extern prototypes should be avoided in .h files\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(.*)\bextern\b\s*(.*)/$1$2/; + } + } + +# check for new externs in .c files. + if ($realfile =~ /\.c$/ && defined $stat && + $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s) + { + my $function_name = $1; + my $paren_space = $2; + + my $s = $stat; + if (defined $cond) { + substr($s, 0, length($cond), ''); + } + if ($s =~ /^\s*;/) + { + WARN("AVOID_EXTERNS", + "externs should be avoided in .c files\n" . $herecurr); + } + + if ($paren_space =~ /\n/) { + WARN("FUNCTION_ARGUMENTS", + "arguments for function declarations should follow identifier\n" . $herecurr); + } + + } elsif ($realfile =~ /\.c$/ && defined $stat && + $stat =~ /^.\s*extern\s+/) + { + WARN("AVOID_EXTERNS", + "externs should be avoided in .c files\n" . $herecurr); + } + +# check for function declarations that have arguments without identifier names + if (defined $stat && + $stat =~ /^.\s*(?:extern\s+)?$Type\s*(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*\(\s*([^{]+)\s*\)\s*;/s && + $1 ne "void") { + my $args = trim($1); + while ($args =~ m/\s*($Type\s*(?:$Ident|\(\s*\*\s*$Ident?\s*\)\s*$balanced_parens)?)/g) { + my $arg = trim($1); + if ($arg =~ /^$Type$/ && $arg !~ /enum\s+$Ident$/) { + WARN("FUNCTION_ARGUMENTS", + "function definition argument '$arg' should also have an identifier name\n" . $herecurr); + } + } + } + +# check for function definitions + if ($perl_version_ok && + defined $stat && + $stat =~ /^.\s*(?:$Storage\s+)?$Type\s*($Ident)\s*$balanced_parens\s*{/s) { + $context_function = $1; + +# check for multiline function definition with misplaced open brace + my $ok = 0; + my $cnt = statement_rawlines($stat); + my $herectx = $here . "\n"; + for (my $n = 0; $n < $cnt; $n++) { + my $rl = raw_line($linenr, $n); + $herectx .= $rl . "\n"; + $ok = 1 if ($rl =~ /^[ \+]\{/); + $ok = 1 if ($rl =~ /\{/ && $n == 0); + last if $rl =~ /^[ \+].*\{/; + } + if (!$ok) { + ERROR("OPEN_BRACE", + "open brace '{' following function definitions go on the next line\n" . $herectx); + } + } + # checks for new __setup's if ($rawline =~ /\b__setup\("([^"]*)"/) { my $name = $1; if (!grep(/$name/, @setup_docs)) { CHK("UNDOCUMENTED_SETUP", - "__setup appears un-documented -- check Documentation/kernel-parameters.txt\n" . $herecurr); + "__setup appears un-documented -- check Documentation/admin-guide/kernel-parameters.txt\n" . $herecurr); } } -# check for pointless casting of kmalloc return - if ($line =~ /\*\s*\)\s*[kv][czm]alloc(_node){0,1}\b/) { +# check for pointless casting of alloc functions + if ($line =~ /\*\s*\)\s*$allocFunctions\b/) { WARN("UNNECESSARY_CASTS", "unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr); } +# alloc style +# p = alloc(sizeof(struct foo), ...) should be p = alloc(sizeof(*p), ...) + if ($perl_version_ok && + $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k|v)[mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/) { + CHK("ALLOC_SIZEOF_STRUCT", + "Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr); + } + +# check for (kv|k)[mz]alloc with multiplies that could be kmalloc_array/kvmalloc_array/kvcalloc/kcalloc + if ($perl_version_ok && + defined $stat && + $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) { + my $oldfunc = $3; + my $a1 = $4; + my $a2 = $10; + my $newfunc = "kmalloc_array"; + $newfunc = "kvmalloc_array" if ($oldfunc eq "kvmalloc"); + $newfunc = "kvcalloc" if ($oldfunc eq "kvzalloc"); + $newfunc = "kcalloc" if ($oldfunc eq "kzalloc"); + my $r1 = $a1; + my $r2 = $a2; + if ($a1 =~ /^sizeof\s*\S/) { + $r1 = $a2; + $r2 = $a1; + } + if ($r1 !~ /^sizeof\b/ && $r2 =~ /^sizeof\s*\S/ && + !($r1 =~ /^$Constant$/ || $r1 =~ /^[A-Z_][A-Z0-9_]*$/)) { + my $cnt = statement_rawlines($stat); + my $herectx = get_stat_here($linenr, $cnt, $here); + + if (WARN("ALLOC_WITH_MULTIPLY", + "Prefer $newfunc over $oldfunc with multiply\n" . $herectx) && + $cnt == 1 && + $fix) { + $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . trim($r1) . ', ' . trim($r2)/e; + } + } + } + +# check for krealloc arg reuse + if ($perl_version_ok && + $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*($Lval)\s*,/ && + $1 eq $3) { + WARN("KREALLOC_ARG_REUSE", + "Reusing the krealloc arg is almost always a bug\n" . $herecurr); + } + +# check for alloc argument mismatch + if ($line =~ /\b((?:devm_)?(?:kcalloc|kmalloc_array))\s*\(\s*sizeof\b/) { + WARN("ALLOC_ARRAY_ARGS", + "$1 uses number as first arg, sizeof is generally wrong\n" . $herecurr); + } + # check for multiple semicolons if ($line =~ /;\s*;\s*$/) { - WARN("ONE_SEMICOLON", - "Statements terminations use 1 semicolon\n" . $herecurr); + if (WARN("ONE_SEMICOLON", + "Statements terminations use 1 semicolon\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(\s*;\s*){2,}$/;/g; + } + } + +# check for #defines like: 1 << <digit> that could be BIT(digit), it is not exported to uapi + if ($realfile !~ m@^include/uapi/@ && + $line =~ /#\s*define\s+\w+\s+\(?\s*1\s*([ulUL]*)\s*\<\<\s*(?:\d+|$Ident)\s*\)?/) { + my $ull = ""; + $ull = "_ULL" if (defined($1) && $1 =~ /ll/i); + if (CHK("BIT_MACRO", + "Prefer using the BIT$ull macro\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\(?\s*1\s*[ulUL]*\s*<<\s*(\d+|$Ident)\s*\)?/BIT${ull}($1)/; + } + } + +# check for IS_ENABLED() without CONFIG_<FOO> ($rawline for comments too) + if ($rawline =~ /\bIS_ENABLED\s*\(\s*(\w+)\s*\)/ && $1 !~ /^${CONFIG_}/) { + WARN("IS_ENABLED_CONFIG", + "IS_ENABLED($1) is normally used as IS_ENABLED(${CONFIG_}$1)\n" . $herecurr); + } + +# check for #if defined CONFIG_<FOO> || defined CONFIG_<FOO>_MODULE + if ($line =~ /^\+\s*#\s*if\s+defined(?:\s*\(?\s*|\s+)(${CONFIG_}[A-Z_]+)\s*\)?\s*\|\|\s*defined(?:\s*\(?\s*|\s+)\1_MODULE\s*\)?\s*$/) { + my $config = $1; + if (WARN("PREFER_IS_ENABLED", + "Prefer IS_ENABLED(<FOO>) to ${CONFIG_}<FOO> || ${CONFIG_}<FOO>_MODULE\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] = "\+#if IS_ENABLED($config)"; + } + } + +# check for /* fallthrough */ like comment, prefer fallthrough; + my @fallthroughs = ( + 'fallthrough', + '@fallthrough@', + 'lint -fallthrough[ \t]*', + 'intentional(?:ly)?[ \t]*fall(?:(?:s | |-)[Tt]|t)hr(?:ough|u|ew)', + '(?:else,?\s*)?FALL(?:S | |-)?THR(?:OUGH|U|EW)[ \t.!]*(?:-[^\n\r]*)?', + 'Fall(?:(?:s | |-)[Tt]|t)hr(?:ough|u|ew)[ \t.!]*(?:-[^\n\r]*)?', + 'fall(?:s | |-)?thr(?:ough|u|ew)[ \t.!]*(?:-[^\n\r]*)?', + ); + if ($raw_comment ne '') { + foreach my $ft (@fallthroughs) { + if ($raw_comment =~ /$ft/) { + my $msg_level = \&WARN; + $msg_level = \&CHK if ($file); + &{$msg_level}("PREFER_FALLTHROUGH", + "Prefer 'fallthrough;' over fallthrough comment\n" . $herecurr); + last; + } + } + } + +# check for switch/default statements without a break; + if ($perl_version_ok && + defined $stat && + $stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) { + my $cnt = statement_rawlines($stat); + my $herectx = get_stat_here($linenr, $cnt, $here); + + WARN("DEFAULT_NO_BREAK", + "switch default: should use break\n" . $herectx); } # check for gcc specific __FUNCTION__ - if ($line =~ /__FUNCTION__/) { - WARN("USE_FUNC", - "__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr); + if ($line =~ /\b__FUNCTION__\b/) { + if (WARN("USE_FUNC", + "__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b__FUNCTION__\b/__func__/g; + } + } + +# check for uses of __DATE__, __TIME__, __TIMESTAMP__ + while ($line =~ /\b(__(?:DATE|TIME|TIMESTAMP)__)\b/g) { + ERROR("DATE_TIME", + "Use of the '$1' macro makes the build non-deterministic\n" . $herecurr); + } + +# check for use of yield() + if ($line =~ /\byield\s*\(\s*\)/) { + WARN("YIELD", + "Using yield() is generally wrong. See yield() kernel-doc (sched/core.c)\n" . $herecurr); + } + +# check for comparisons against true and false + if ($line =~ /\+\s*(.*?)\b(true|false|$Lval)\s*(==|\!=)\s*(true|false|$Lval)\b(.*)$/i) { + my $lead = $1; + my $arg = $2; + my $test = $3; + my $otype = $4; + my $trail = $5; + my $op = "!"; + + ($arg, $otype) = ($otype, $arg) if ($arg =~ /^(?:true|false)$/i); + + my $type = lc($otype); + if ($type =~ /^(?:true|false)$/) { + if (("$test" eq "==" && "$type" eq "true") || + ("$test" eq "!=" && "$type" eq "false")) { + $op = ""; + } + + CHK("BOOL_COMPARISON", + "Using comparison to $otype is error prone\n" . $herecurr); + +## maybe suggesting a correct construct would better +## "Using comparison to $otype is error prone. Perhaps use '${lead}${op}${arg}${trail}'\n" . $herecurr); + + } } # check for semaphores initialized locked if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) { WARN("CONSIDER_COMPLETION", "consider using a completion\n" . $herecurr); - } -# recommend kstrto* over simple_strto* - if ($line =~ /\bsimple_(strto.*?)\s*\(/) { + +# recommend kstrto* over simple_strto* and strict_strto* + if ($line =~ /\b((simple|strict)_(strto(l|ll|ul|ull)))\s*\(/) { WARN("CONSIDER_KSTRTO", - "consider using kstrto* in preference to simple_$1\n" . $herecurr); + "$1 is obsolete, use k$3 instead\n" . $herecurr); } -# check for __initcall(), use device_initcall() explicitly please + +# check for __initcall(), use device_initcall() explicitly or more appropriate function please if ($line =~ /^.\s*__initcall\s*\(/) { WARN("USE_DEVICE_INITCALL", - "please use device_initcall() instead of __initcall()\n" . $herecurr); - } -# check for various ops structs, ensure they are const. - my $struct_ops = qr{acpi_dock_ops| - address_space_operations| - backlight_ops| - block_device_operations| - dentry_operations| - dev_pm_ops| - dma_map_ops| - extent_io_ops| - file_lock_operations| - file_operations| - hv_ops| - ide_dma_ops| - intel_dvo_dev_ops| - item_operations| - iwl_ops| - kgdb_arch| - kgdb_io| - kset_uevent_ops| - lock_manager_operations| - microcode_ops| - mtrr_ops| - neigh_ops| - nlmsvc_binding| - pci_raw_ops| - pipe_buf_operations| - platform_hibernation_ops| - platform_suspend_ops| - proto_ops| - rpc_pipe_ops| - seq_operations| - snd_ac97_build_ops| - soc_pcmcia_socket_ops| - stacktrace_ops| - sysfs_ops| - tty_operations| - usb_mon_operations| - wd_ops}x; - if ($line !~ /\bconst\b/ && - $line =~ /\bstruct\s+($struct_ops)\b/) { + "please use device_initcall() or more appropriate function instead of __initcall() (see include/linux/init.h)\n" . $herecurr); + } + +# check for spin_is_locked(), suggest lockdep instead + if ($line =~ /\bspin_is_locked\(/) { + WARN("USE_LOCKDEP", + "Where possible, use lockdep_assert_held instead of assertions based on spin_is_locked\n" . $herecurr); + } + +# check for deprecated apis + if ($line =~ /\b($deprecated_apis_search)\b\s*\(/) { + my $deprecated_api = $1; + my $new_api = $deprecated_apis{$deprecated_api}; + WARN("DEPRECATED_API", + "Deprecated use of '$deprecated_api', prefer '$new_api' instead\n" . $herecurr); + } + +# check for various structs that are normally const (ops, kgdb, device_tree) +# and avoid what seem like struct definitions 'struct foo {' + if (defined($const_structs) && + $line !~ /\bconst\b/ && + $line =~ /\bstruct\s+($const_structs)\b(?!\s*\{)/) { WARN("CONST_STRUCT", - "struct $1 should normally be const\n" . - $herecurr); + "struct $1 should normally be const\n" . $herecurr); } # use of NR_CPUS is usually wrong # ignore definitions of NR_CPUS and usage to define arrays as likely right +# ignore designated initializers using NR_CPUS if ($line =~ /\bNR_CPUS\b/ && $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ && $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ && $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ && $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ && - $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/) + $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/ && + $line !~ /^.\s*\.\w+\s*=\s*.*\bNR_CPUS\b/) { WARN("NR_CPUS", "usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr); } -# check for %L{u,d,i} in strings - my $string; - while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { - $string = substr($rawline, $-[1], $+[1] - $-[1]); - $string =~ s/%%/__/g; - if ($string =~ /(?<!%)%L[udi]/) { - WARN("PRINTF_L", - "\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr); - last; +# Use of __ARCH_HAS_<FOO> or ARCH_HAVE_<BAR> is wrong. + if ($line =~ /\+\s*#\s*define\s+((?:__)?ARCH_(?:HAS|HAVE)\w*)\b/) { + ERROR("DEFINE_ARCH_HAS", + "#define of '$1' is wrong - use Kconfig variables or standard guards instead\n" . $herecurr); + } + +# likely/unlikely comparisons similar to "(likely(foo) > 0)" + if ($perl_version_ok && + $line =~ /\b((?:un)?likely)\s*\(\s*$FuncArg\s*\)\s*$Compare/) { + WARN("LIKELY_MISUSE", + "Using $1 should generally have parentheses around the comparison\n" . $herecurr); + } + +# return sysfs_emit(foo, fmt, ...) fmt without newline + if ($line =~ /\breturn\s+sysfs_emit\s*\(\s*$FuncArg\s*,\s*($String)/ && + substr($rawline, $-[6], $+[6] - $-[6]) !~ /\\n"$/) { + my $offset = $+[6] - 1; + if (WARN("SYSFS_EMIT", + "return sysfs_emit(...) formats should include a terminating newline\n" . $herecurr) && + $fix) { + substr($fixed[$fixlinenr], $offset, 0) = '\\n'; } } +# nested likely/unlikely calls + if ($line =~ /\b(?:(?:un)?likely)\s*\(\s*!?\s*(IS_ERR(?:_OR_NULL|_VALUE)?|WARN)/) { + WARN("LIKELY_MISUSE", + "nested (un)?likely() calls, $1 already uses unlikely() internally\n" . $herecurr); + } + # whine mightly about in_atomic if ($line =~ /\bin_atomic\s*\(/) { if ($realfile =~ m@^drivers/@) { @@ -3266,16 +7429,149 @@ sub process { } } - if ($line =~ /debugfs_create_file.*S_IWUGO/ || - $line =~ /DEVICE_ATTR.*S_IWUGO/ ) { + if ($line =~ /debugfs_create_\w+.*\b$mode_perms_world_writable\b/ || + $line =~ /DEVICE_ATTR.*\b$mode_perms_world_writable\b/) { WARN("EXPORTED_WORLD_WRITABLE", "Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr); } - # Check for memset with swapped arguments - if ($line =~ /memset.*\,(\ |)(0x|)0(\ |0|)\);/) { - ERROR("MEMSET", - "memset size is 3rd argument, not the second.\n" . $herecurr); +# check for DEVICE_ATTR uses that could be DEVICE_ATTR_<FOO> +# and whether or not function naming is typical and if +# DEVICE_ATTR permissions uses are unusual too + if ($perl_version_ok && + defined $stat && + $stat =~ /\bDEVICE_ATTR\s*\(\s*(\w+)\s*,\s*\(?\s*(\s*(?:${multi_mode_perms_string_search}|0[0-7]{3,3})\s*)\s*\)?\s*,\s*(\w+)\s*,\s*(\w+)\s*\)/) { + my $var = $1; + my $perms = $2; + my $show = $3; + my $store = $4; + my $octal_perms = perms_to_octal($perms); + if ($show =~ /^${var}_show$/ && + $store =~ /^${var}_store$/ && + $octal_perms eq "0644") { + if (WARN("DEVICE_ATTR_RW", + "Use DEVICE_ATTR_RW\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*$show\s*,\s*$store\s*\)/DEVICE_ATTR_RW(${var})/; + } + } elsif ($show =~ /^${var}_show$/ && + $store =~ /^NULL$/ && + $octal_perms eq "0444") { + if (WARN("DEVICE_ATTR_RO", + "Use DEVICE_ATTR_RO\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*$show\s*,\s*NULL\s*\)/DEVICE_ATTR_RO(${var})/; + } + } elsif ($show =~ /^NULL$/ && + $store =~ /^${var}_store$/ && + $octal_perms eq "0200") { + if (WARN("DEVICE_ATTR_WO", + "Use DEVICE_ATTR_WO\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*NULL\s*,\s*$store\s*\)/DEVICE_ATTR_WO(${var})/; + } + } elsif ($octal_perms eq "0644" || + $octal_perms eq "0444" || + $octal_perms eq "0200") { + my $newshow = "$show"; + $newshow = "${var}_show" if ($show ne "NULL" && $show ne "${var}_show"); + my $newstore = $store; + $newstore = "${var}_store" if ($store ne "NULL" && $store ne "${var}_store"); + my $rename = ""; + if ($show ne $newshow) { + $rename .= " '$show' to '$newshow'"; + } + if ($store ne $newstore) { + $rename .= " '$store' to '$newstore'"; + } + WARN("DEVICE_ATTR_FUNCTIONS", + "Consider renaming function(s)$rename\n" . $herecurr); + } else { + WARN("DEVICE_ATTR_PERMS", + "DEVICE_ATTR unusual permissions '$perms' used\n" . $herecurr); + } + } + +# Mode permission misuses where it seems decimal should be octal +# This uses a shortcut match to avoid unnecessary uses of a slow foreach loop +# o Ignore module_param*(...) uses with a decimal 0 permission as that has a +# specific definition of not visible in sysfs. +# o Ignore proc_create*(...) uses with a decimal 0 permission as that means +# use the default permissions + if ($perl_version_ok && + defined $stat && + $line =~ /$mode_perms_search/) { + foreach my $entry (@mode_permission_funcs) { + my $func = $entry->[0]; + my $arg_pos = $entry->[1]; + + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + my $stat_real = get_stat_real($linenr, $lc); + + my $skip_args = ""; + if ($arg_pos > 1) { + $arg_pos--; + $skip_args = "(?:\\s*$FuncArg\\s*,\\s*){$arg_pos,$arg_pos}"; + } + my $test = "\\b$func\\s*\\(${skip_args}($FuncArg(?:\\|\\s*$FuncArg)*)\\s*[,\\)]"; + if ($stat =~ /$test/) { + my $val = $1; + $val = $6 if ($skip_args ne ""); + if (!($func =~ /^(?:module_param|proc_create)/ && $val eq "0") && + (($val =~ /^$Int$/ && $val !~ /^$Octal$/) || + ($val =~ /^$Octal$/ && length($val) ne 4))) { + ERROR("NON_OCTAL_PERMISSIONS", + "Use 4 digit octal (0777) not decimal permissions\n" . "$here\n" . $stat_real); + } + if ($val =~ /^$Octal$/ && (oct($val) & 02)) { + ERROR("EXPORTED_WORLD_WRITABLE", + "Exporting writable files is usually an error. Consider more restrictive permissions.\n" . "$here\n" . $stat_real); + } + } + } + } + +# check for uses of S_<PERMS> that could be octal for readability + while ($line =~ m{\b($multi_mode_perms_string_search)\b}g) { + my $oval = $1; + my $octal = perms_to_octal($oval); + if (WARN("SYMBOLIC_PERMS", + "Symbolic permissions '$oval' are not preferred. Consider using octal permissions '$octal'.\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\Q$oval\E/$octal/; + } + } + +# validate content of MODULE_LICENSE against list from include/linux/module.h + if ($line =~ /\bMODULE_LICENSE\s*\(\s*($String)\s*\)/) { + my $extracted_string = get_quoted_string($line, $rawline); + my $valid_licenses = qr{ + GPL| + GPL\ v2| + GPL\ and\ additional\ rights| + Dual\ BSD/GPL| + Dual\ MIT/GPL| + Dual\ MPL/GPL| + Proprietary + }x; + if ($extracted_string !~ /^"(?:$valid_licenses)"$/x) { + WARN("MODULE_LICENSE", + "unknown module license " . $extracted_string . "\n" . $herecurr); + } + if (!$file && $extracted_string eq '"GPL v2"') { + if (WARN("MODULE_LICENSE", + "Prefer \"GPL\" over \"GPL v2\" - see commit bf7fbeeae6db (\"module: Cure the MODULE_LICENSE \"GPL\" vs. \"GPL v2\" bogosity\")\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bMODULE_LICENSE\s*\(\s*"GPL v2"\s*\)/MODULE_LICENSE("GPL")/; + } + } + } + +# check for sysctl duplicate constants + if ($line =~ /\.extra[12]\s*=\s*&(zero|one|int_max)\b/) { + WARN("DUPLICATED_SYSCTL_CONST", + "duplicated sysctl range checking value '$1', consider using the shared one in include/linux/sysctl.h\n" . $herecurr); } } @@ -3291,19 +7587,48 @@ sub process { exit(0); } - # This is not a patch, and we are are in 'no-patch' mode so + # This is not a patch, and we are in 'no-patch' mode so # just keep quiet. if (!$chk_patch && !$is_patch) { exit(0); } - if (!$is_patch) { + if (!$is_patch && $filename !~ /cover-letter\.patch$/) { ERROR("NOT_UNIFIED_DIFF", "Does not appear to be a unified-diff format patch\n"); } - if ($is_patch && $chk_signoff && $signoff == 0) { - ERROR("MISSING_SIGN_OFF", - "Missing Signed-off-by: line(s)\n"); + if ($is_patch && $has_commit_log && $chk_signoff) { + if ($signoff == 0) { + ERROR("MISSING_SIGN_OFF", + "Missing Signed-off-by: line(s)\n"); + } elsif ($authorsignoff != 1) { + # authorsignoff values: + # 0 -> missing sign off + # 1 -> sign off identical + # 2 -> names and addresses match, comments mismatch + # 3 -> addresses match, names different + # 4 -> names match, addresses different + # 5 -> names match, addresses excluding subaddress details (refer RFC 5233) match + + my $sob_msg = "'From: $author' != 'Signed-off-by: $author_sob'"; + + if ($authorsignoff == 0) { + ERROR("NO_AUTHOR_SIGN_OFF", + "Missing Signed-off-by: line by nominal patch author '$author'\n"); + } elsif ($authorsignoff == 2) { + CHK("FROM_SIGN_OFF_MISMATCH", + "From:/Signed-off-by: email comments mismatch: $sob_msg\n"); + } elsif ($authorsignoff == 3) { + WARN("FROM_SIGN_OFF_MISMATCH", + "From:/Signed-off-by: email name mismatch: $sob_msg\n"); + } elsif ($authorsignoff == 4) { + WARN("FROM_SIGN_OFF_MISMATCH", + "From:/Signed-off-by: email address mismatch: $sob_msg\n"); + } elsif ($authorsignoff == 5) { + WARN("FROM_SIGN_OFF_MISMATCH", + "From:/Signed-off-by: email subaddress mismatch: $sob_msg\n"); + } + } } print report_dump(); @@ -3312,40 +7637,75 @@ sub process { print "total: $cnt_error errors, $cnt_warn warnings, " . (($check)? "$cnt_chk checks, " : "") . "$cnt_lines lines checked\n"; - print "\n" if ($quiet == 0); } if ($quiet == 0) { + # If there were any defects found and not already fixing them + if (!$clean and !$fix) { + print << "EOM" + +NOTE: For some of the reported defects, checkpatch may be able to + mechanically convert to the typical style using --fix or --fix-inplace. +EOM + } # If there were whitespace errors which cleanpatch can fix # then suggest that. if ($rpt_cleaners) { - print "NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or\n"; - print " scripts/cleanfile\n\n"; $rpt_cleaners = 0; + print << "EOM" + +NOTE: Whitespace errors detected. + You may wish to use scripts/cleanpatch or scripts/cleanfile +EOM } } - if (keys %ignore_type) { - print "NOTE: Ignored message types:"; - foreach my $ignore (sort keys %ignore_type) { - print " $ignore"; - } - print "\n"; - print "\n" if ($quiet == 0); - } + if ($clean == 0 && $fix && + ("@rawlines" ne "@fixed" || + $#fixed_inserted >= 0 || $#fixed_deleted >= 0)) { + my $newfile = $filename; + $newfile .= ".EXPERIMENTAL-checkpatch-fixes" if (!$fix_inplace); + my $linecount = 0; + my $f; + + @fixed = fix_inserted_deleted_lines(\@fixed, \@fixed_inserted, \@fixed_deleted); + + open($f, '>', $newfile) + or die "$P: Can't open $newfile for write\n"; + foreach my $fixed_line (@fixed) { + $linecount++; + if ($file) { + if ($linecount > 3) { + $fixed_line =~ s/^\+//; + print $f $fixed_line . "\n"; + } + } else { + print $f $fixed_line . "\n"; + } + } + close($f); - if ($clean == 1 && $quiet == 0) { - print "$vname has no obvious style problems and is ready for submission.\n" - } - if ($clean == 0 && $quiet == 0) { - print << "EOM"; -$vname has style problems, please review. + if (!$quiet) { + print << "EOM"; -If any of these errors are false positives, please report -them to the openocd-devel mailing list or prepare a patch -and send it to Gerrit for review. +Wrote EXPERIMENTAL --fix correction(s) to '$newfile' + +Do _NOT_ trust the results written to this file. +Do _NOT_ submit these changes without inspecting them for correctness. + +This EXPERIMENTAL file is simply a convenience to help rewrite patches. +No warranties, expressed or implied... EOM + } } + if ($quiet == 0) { + print "\n"; + if ($clean == 1) { + print "$vname has no obvious style problems and is ready for submission.\n"; + } else { + print "$vname has style problems, please review.\n"; + } + } return $clean; } diff --git a/tools/scripts/const_structs.checkpatch b/tools/scripts/const_structs.checkpatch new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tools/scripts/spdxcheck.py b/tools/scripts/spdxcheck.py new file mode 100755 index 0000000000..f882943790 --- /dev/null +++ b/tools/scripts/spdxcheck.py @@ -0,0 +1,449 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +# Copyright Thomas Gleixner <tglx@linutronix.de> + +from argparse import ArgumentParser +from ply import lex, yacc +import locale +import traceback +import fnmatch +import sys +import git +import re +import os + +class ParserException(Exception): + def __init__(self, tok, txt): + self.tok = tok + self.txt = txt + +class SPDXException(Exception): + def __init__(self, el, txt): + self.el = el + self.txt = txt + +class SPDXdata(object): + def __init__(self): + self.license_files = 0 + self.exception_files = 0 + self.licenses = [ ] + self.exceptions = { } + +class dirinfo(object): + def __init__(self): + self.missing = 0 + self.total = 0 + self.files = [] + + def update(self, fname, basedir, miss): + self.total += 1 + self.missing += miss + if miss: + fname = './' + fname + bdir = os.path.dirname(fname) + if bdir == basedir.rstrip('/'): + self.files.append(fname) + +# Read the spdx data from the LICENSES directory +def read_spdxdata(repo): + + # The subdirectories of LICENSES in the kernel source + # Note: exceptions needs to be parsed as last directory. + # OpenOCD specific: Begin + license_dirs = [ "preferred", "stand-alone", "exceptions" ] + # OpenOCD specific: End + lictree = repo.head.commit.tree['LICENSES'] + + spdx = SPDXdata() + + for d in license_dirs: + for el in lictree[d].traverse(): + if not os.path.isfile(el.path): + continue + + exception = None + for l in open(el.path, encoding="utf-8").readlines(): + if l.startswith('Valid-License-Identifier:'): + lid = l.split(':')[1].strip().upper() + if lid in spdx.licenses: + raise SPDXException(el, 'Duplicate License Identifier: %s' %lid) + else: + spdx.licenses.append(lid) + + elif l.startswith('SPDX-Exception-Identifier:'): + exception = l.split(':')[1].strip().upper() + spdx.exceptions[exception] = [] + + elif l.startswith('SPDX-Licenses:'): + for lic in l.split(':')[1].upper().strip().replace(' ', '').replace('\t', '').split(','): + if not lic in spdx.licenses: + raise SPDXException(None, 'Exception %s missing license %s' %(exception, lic)) + spdx.exceptions[exception].append(lic) + + elif l.startswith("License-Text:"): + if exception: + if not len(spdx.exceptions[exception]): + raise SPDXException(el, 'Exception %s is missing SPDX-Licenses' %exception) + spdx.exception_files += 1 + else: + spdx.license_files += 1 + break + return spdx + +class id_parser(object): + + reserved = [ 'AND', 'OR', 'WITH' ] + tokens = [ 'LPAR', 'RPAR', 'ID', 'EXC' ] + reserved + + precedence = ( ('nonassoc', 'AND', 'OR'), ) + + t_ignore = ' \t' + + def __init__(self, spdx): + self.spdx = spdx + self.lasttok = None + self.lastid = None + self.lexer = lex.lex(module = self, reflags = re.UNICODE) + # Initialize the parser. No debug file and no parser rules stored on disk + # The rules are small enough to be generated on the fly + self.parser = yacc.yacc(module = self, write_tables = False, debug = False) + self.lines_checked = 0 + self.checked = 0 + self.excluded = 0 + self.spdx_valid = 0 + self.spdx_errors = 0 + self.spdx_dirs = {} + self.dirdepth = -1 + self.basedir = '.' + self.curline = 0 + self.deepest = 0 + + def set_dirinfo(self, basedir, dirdepth): + if dirdepth >= 0: + self.basedir = basedir + bdir = basedir.lstrip('./').rstrip('/') + if bdir != '': + parts = bdir.split('/') + else: + parts = [] + self.dirdepth = dirdepth + len(parts) + + # Validate License and Exception IDs + def validate(self, tok): + id = tok.value.upper() + if tok.type == 'ID': + if not id in self.spdx.licenses: + raise ParserException(tok, 'Invalid License ID') + self.lastid = id + elif tok.type == 'EXC': + if id not in self.spdx.exceptions: + raise ParserException(tok, 'Invalid Exception ID') + if self.lastid not in self.spdx.exceptions[id]: + raise ParserException(tok, 'Exception not valid for license %s' %self.lastid) + self.lastid = None + elif tok.type != 'WITH': + self.lastid = None + + # Lexer functions + def t_RPAR(self, tok): + r'\)' + self.lasttok = tok.type + return tok + + def t_LPAR(self, tok): + r'\(' + self.lasttok = tok.type + return tok + + def t_ID(self, tok): + r'[A-Za-z.0-9\-+]+' + + if self.lasttok == 'EXC': + print(tok) + raise ParserException(tok, 'Missing parentheses') + + tok.value = tok.value.strip() + val = tok.value.upper() + + if val in self.reserved: + tok.type = val + elif self.lasttok == 'WITH': + tok.type = 'EXC' + + self.lasttok = tok.type + self.validate(tok) + return tok + + def t_error(self, tok): + raise ParserException(tok, 'Invalid token') + + def p_expr(self, p): + '''expr : ID + | ID WITH EXC + | expr AND expr + | expr OR expr + | LPAR expr RPAR''' + pass + + def p_error(self, p): + if not p: + raise ParserException(None, 'Unfinished license expression') + else: + raise ParserException(p, 'Syntax error') + + def parse(self, expr): + self.lasttok = None + self.lastid = None + self.parser.parse(expr, lexer = self.lexer) + + def parse_lines(self, fd, maxlines, fname): + self.checked += 1 + self.curline = 0 + fail = 1 + try: + for line in fd: + line = line.decode(locale.getpreferredencoding(False), errors='ignore') + self.curline += 1 + if self.curline > maxlines: + break + self.lines_checked += 1 + if line.find("SPDX-License-Identifier:") < 0: + continue + expr = line.split(':')[1].strip() + # Remove trailing comment closure + if line.strip().endswith('*/'): + expr = expr.rstrip('*/').strip() + # Remove trailing xml comment closure + if line.strip().endswith('-->'): + expr = expr.rstrip('-->').strip() + # Special case for SH magic boot code files + if line.startswith('LIST \"'): + expr = expr.rstrip('\"').strip() + self.parse(expr) + self.spdx_valid += 1 + # + # Should we check for more SPDX ids in the same file and + # complain if there are any? + # + fail = 0 + break + + except ParserException as pe: + if pe.tok: + col = line.find(expr) + pe.tok.lexpos + tok = pe.tok.value + sys.stdout.write('%s: %d:%d %s: %s\n' %(fname, self.curline, col, pe.txt, tok)) + else: + sys.stdout.write('%s: %d:0 %s\n' %(fname, self.curline, pe.txt)) + self.spdx_errors += 1 + + if fname == '-': + return + + base = os.path.dirname(fname) + if self.dirdepth > 0: + parts = base.split('/') + i = 0 + base = '.' + while i < self.dirdepth and i < len(parts) and len(parts[i]): + base += '/' + parts[i] + i += 1 + elif self.dirdepth == 0: + base = self.basedir + else: + base = './' + base.rstrip('/') + base += '/' + + di = self.spdx_dirs.get(base, dirinfo()) + di.update(fname, base, fail) + self.spdx_dirs[base] = di + +class pattern(object): + def __init__(self, line): + self.pattern = line + self.match = self.match_file + if line == '.*': + self.match = self.match_dot + elif line.endswith('/'): + self.pattern = line[:-1] + self.match = self.match_dir + elif line.startswith('/'): + self.pattern = line[1:] + self.match = self.match_fn + + def match_dot(self, fpath): + return os.path.basename(fpath).startswith('.') + + def match_file(self, fpath): + return os.path.basename(fpath) == self.pattern + + def match_fn(self, fpath): + return fnmatch.fnmatchcase(fpath, self.pattern) + + def match_dir(self, fpath): + if self.match_fn(os.path.dirname(fpath)): + return True + return fpath.startswith(self.pattern) + +def exclude_file(fpath): + for rule in exclude_rules: + if rule.match(fpath): + return True + return False + +def scan_git_tree(tree, basedir, dirdepth): + parser.set_dirinfo(basedir, dirdepth) + for el in tree.traverse(): + if not os.path.isfile(el.path): + continue + if exclude_file(el.path): + parser.excluded += 1 + continue + with open(el.path, 'rb') as fd: + parser.parse_lines(fd, args.maxlines, el.path) + +def scan_git_subtree(tree, path, dirdepth): + for p in path.strip('/').split('/'): + tree = tree[p] + scan_git_tree(tree, path.strip('/'), dirdepth) + +def read_exclude_file(fname): + rules = [] + if not fname: + return rules + with open(fname) as fd: + for line in fd: + line = line.strip() + if line.startswith('#'): + continue + if not len(line): + continue + rules.append(pattern(line)) + return rules + +if __name__ == '__main__': + + ap = ArgumentParser(description='SPDX expression checker') + ap.add_argument('path', nargs='*', help='Check path or file. If not given full git tree scan. For stdin use "-"') + ap.add_argument('-d', '--dirs', action='store_true', + help='Show [sub]directory statistics.') + ap.add_argument('-D', '--depth', type=int, default=-1, + help='Directory depth for -d statistics. Default: unlimited') + ap.add_argument('-e', '--exclude', + help='File containing file patterns to exclude. Default: scripts/spdxexclude') + ap.add_argument('-f', '--files', action='store_true', + help='Show files without SPDX.') + ap.add_argument('-m', '--maxlines', type=int, default=15, + help='Maximum number of lines to scan in a file. Default 15') + ap.add_argument('-v', '--verbose', action='store_true', help='Verbose statistics output') + args = ap.parse_args() + + # Sanity check path arguments + if '-' in args.path and len(args.path) > 1: + sys.stderr.write('stdin input "-" must be the only path argument\n') + sys.exit(1) + + try: + # Use git to get the valid license expressions + repo = git.Repo(os.getcwd()) + assert not repo.bare + + # Initialize SPDX data + spdx = read_spdxdata(repo) + + # Initialize the parser + parser = id_parser(spdx) + + except SPDXException as se: + if se.el: + sys.stderr.write('%s: %s\n' %(se.el.path, se.txt)) + else: + sys.stderr.write('%s\n' %se.txt) + sys.exit(1) + + except Exception as ex: + sys.stderr.write('FAIL: %s\n' %ex) + sys.stderr.write('%s\n' %traceback.format_exc()) + sys.exit(1) + + try: + fname = args.exclude + if not fname: + fname = os.path.join(os.path.dirname(__file__), 'spdxexclude') + exclude_rules = read_exclude_file(fname) + except Exception as ex: + sys.stderr.write('FAIL: Reading exclude file %s: %s\n' %(fname, ex)) + sys.exit(1) + + try: + if len(args.path) and args.path[0] == '-': + stdin = os.fdopen(sys.stdin.fileno(), 'rb') + parser.parse_lines(stdin, args.maxlines, '-') + else: + if args.path: + for p in args.path: + if os.path.isfile(p): + parser.parse_lines(open(p, 'rb'), args.maxlines, p) + elif os.path.isdir(p): + scan_git_subtree(repo.head.reference.commit.tree, p, + args.depth) + else: + sys.stderr.write('path %s does not exist\n' %p) + sys.exit(1) + else: + # Full git tree scan + scan_git_tree(repo.head.commit.tree, '.', args.depth) + + ndirs = len(parser.spdx_dirs) + dirsok = 0 + if ndirs: + for di in parser.spdx_dirs.values(): + if not di.missing: + dirsok += 1 + + if args.verbose: + sys.stderr.write('\n') + sys.stderr.write('License files: %12d\n' %spdx.license_files) + sys.stderr.write('Exception files: %12d\n' %spdx.exception_files) + sys.stderr.write('License IDs %12d\n' %len(spdx.licenses)) + sys.stderr.write('Exception IDs %12d\n' %len(spdx.exceptions)) + sys.stderr.write('\n') + sys.stderr.write('Files excluded: %12d\n' %parser.excluded) + sys.stderr.write('Files checked: %12d\n' %parser.checked) + sys.stderr.write('Lines checked: %12d\n' %parser.lines_checked) + if parser.checked: + pc = int(100 * parser.spdx_valid / parser.checked) + sys.stderr.write('Files with SPDX: %12d %3d%%\n' %(parser.spdx_valid, pc)) + sys.stderr.write('Files with errors: %12d\n' %parser.spdx_errors) + if ndirs: + sys.stderr.write('\n') + sys.stderr.write('Directories accounted: %8d\n' %ndirs) + pc = int(100 * dirsok / ndirs) + sys.stderr.write('Directories complete: %8d %3d%%\n' %(dirsok, pc)) + + if ndirs and ndirs != dirsok and args.dirs: + if args.verbose: + sys.stderr.write('\n') + sys.stderr.write('Incomplete directories: SPDX in Files\n') + for f in sorted(parser.spdx_dirs.keys()): + di = parser.spdx_dirs[f] + if di.missing: + valid = di.total - di.missing + pc = int(100 * valid / di.total) + sys.stderr.write(' %-80s: %5d of %5d %3d%%\n' %(f, valid, di.total, pc)) + + if ndirs and ndirs != dirsok and args.files: + if args.verbose or args.dirs: + sys.stderr.write('\n') + sys.stderr.write('Files without SPDX:\n') + for f in sorted(parser.spdx_dirs.keys()): + di = parser.spdx_dirs[f] + for f in sorted(di.files): + sys.stderr.write(' %s\n' %f) + + sys.exit(0) + + except Exception as ex: + sys.stderr.write('FAIL: %s\n' %ex) + sys.stderr.write('%s\n' %traceback.format_exc()) + sys.exit(1) diff --git a/tools/scripts/spdxexclude b/tools/scripts/spdxexclude new file mode 100644 index 0000000000..cea346781d --- /dev/null +++ b/tools/scripts/spdxexclude @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Patterns for excluding files and directories + +# Ignore the license directory and the licensing documentation which would +# create lots of noise for no value +LICENSES/ +license-rules.rst + +# Other files without copyrightable content +/NEWS* +testing/ + diff --git a/tools/scripts/spelling.txt b/tools/scripts/spelling.txt new file mode 100644 index 0000000000..8435b99452 --- /dev/null +++ b/tools/scripts/spelling.txt @@ -0,0 +1,1642 @@ +# Originally from Debian's Lintian tool. Various false positives have been +# removed, and various additions have been made as they've been discovered +# in the kernel source. +# +# License: GPLv2 +# +# The format of each line is: +# mistake||correction +# +abandonning||abandoning +abigious||ambiguous +abitrary||arbitrary +abitrate||arbitrate +abnornally||abnormally +abnrormal||abnormal +abord||abort +aboslute||absolute +abov||above +abreviated||abbreviated +absense||absence +absolut||absolute +absoulte||absolute +acccess||access +acceess||access +accelaration||acceleration +acceleratoin||acceleration +accelleration||acceleration +accesing||accessing +accesnt||accent +accessable||accessible +accesss||access +accidentaly||accidentally +accidentually||accidentally +acclerated||accelerated +accoding||according +accomodate||accommodate +accomodates||accommodates +accordign||according +accoring||according +accout||account +accquire||acquire +accquired||acquired +accross||across +accumalate||accumulate +accumalator||accumulator +acessable||accessible +acess||access +acessing||accessing +achitecture||architecture +acient||ancient +acitions||actions +acitve||active +acknowldegement||acknowledgment +acknowledgement||acknowledgment +ackowledge||acknowledge +ackowledged||acknowledged +acording||according +activete||activate +actived||activated +actualy||actually +acumulating||accumulating +acumulative||accumulative +acumulator||accumulator +acutally||actually +adapater||adapter +addional||additional +additionaly||additionally +additonal||additional +addres||address +adddress||address +addreses||addresses +addresss||address +addrress||address +aditional||additional +aditionally||additionally +aditionaly||additionally +adminstrative||administrative +adress||address +adresses||addresses +adrresses||addresses +advertisment||advertisement +adviced||advised +afecting||affecting +againt||against +agaist||against +aggreataon||aggregation +aggreation||aggregation +ajust||adjust +albumns||albums +alegorical||allegorical +algined||aligned +algorith||algorithm +algorithmical||algorithmically +algoritm||algorithm +algoritms||algorithms +algorithmn||algorithm +algorrithm||algorithm +algorritm||algorithm +aligment||alignment +alignement||alignment +allign||align +alligned||aligned +alllocate||allocate +alloated||allocated +allocatote||allocate +allocatrd||allocated +allocte||allocate +allocted||allocated +allpication||application +alocate||allocate +alogirhtms||algorithms +alogrithm||algorithm +alot||a lot +alow||allow +alows||allows +alreay||already +alredy||already +altough||although +alue||value +ambigious||ambiguous +ambigous||ambiguous +amoung||among +amout||amount +amplifer||amplifier +amplifyer||amplifier +an union||a union +an user||a user +an userspace||a userspace +an one||a one +analysator||analyzer +ang||and +anniversery||anniversary +annoucement||announcement +anomolies||anomalies +anomoly||anomaly +anway||anyway +aplication||application +appearence||appearance +applicaion||application +appliction||application +applictions||applications +applys||applies +appplications||applications +appropiate||appropriate +appropriatly||appropriately +approriate||appropriate +approriately||appropriately +apropriate||appropriate +aquainted||acquainted +aquired||acquired +aquisition||acquisition +arbitary||arbitrary +architechture||architecture +arguement||argument +arguements||arguments +arithmatic||arithmetic +aritmetic||arithmetic +arne't||aren't +arraival||arrival +artifical||artificial +artillary||artillery +asign||assign +asser||assert +assertation||assertion +assertting||asserting +assgined||assigned +assiged||assigned +assigment||assignment +assigments||assignments +assistent||assistant +assocaited||associated +assocating||associating +assocation||association +associcated||associated +assotiated||associated +asssert||assert +assum||assume +assumtpion||assumption +asuming||assuming +asycronous||asynchronous +asychronous||asynchronous +asynchnous||asynchronous +asynchronus||asynchronous +asynchromous||asynchronous +asymetric||asymmetric +asymmeric||asymmetric +atleast||at least +atomatically||automatically +atomicly||atomically +atempt||attempt +atrributes||attributes +attachement||attachment +attatch||attach +attched||attached +attemp||attempt +attemps||attempts +attemping||attempting +attepmpt||attempt +attnetion||attention +attruibutes||attributes +authentification||authentication +authenicated||authenticated +automaticaly||automatically +automaticly||automatically +automatize||automate +automatized||automated +automatizes||automates +autonymous||autonomous +auxillary||auxiliary +auxilliary||auxiliary +avaiable||available +avaible||available +availabe||available +availabled||available +availablity||availability +availaible||available +availale||available +availavility||availability +availble||available +availiable||available +availible||available +avalable||available +avaliable||available +aysnc||async +backgroud||background +backword||backward +backwords||backwards +bahavior||behavior +bakup||backup +baloon||balloon +baloons||balloons +bandwith||bandwidth +banlance||balance +batery||battery +battey||battery +beacuse||because +becasue||because +becomming||becoming +becuase||because +beeing||being +befor||before +begining||beginning +beter||better +betweeen||between +bianries||binaries +bitmast||bitmask +bitwiedh||bitwidth +boardcast||broadcast +borad||board +boundry||boundary +brievely||briefly +brigde||bridge +broadcase||broadcast +broadcat||broadcast +bufer||buffer +bufufer||buffer +cacluated||calculated +caculate||calculate +caculation||calculation +cadidate||candidate +cahces||caches +calender||calendar +calescing||coalescing +calle||called +callibration||calibration +callled||called +callser||caller +calucate||calculate +calulate||calculate +cancelation||cancellation +cancle||cancel +cant||can't +cant'||can't +canot||cannot +cann't||can't +capabilites||capabilities +capabilties||capabilities +capabilty||capability +capabitilies||capabilities +capablity||capability +capatibilities||capabilities +capapbilities||capabilities +caputure||capture +carefuly||carefully +cariage||carriage +catagory||category +cehck||check +challange||challenge +challanges||challenges +chache||cache +chanell||channel +changable||changeable +chanined||chained +channle||channel +channnel||channel +charachter||character +charachters||characters +charactor||character +charater||character +charaters||characters +charcter||character +chcek||check +chck||check +checksumed||checksummed +checksuming||checksumming +childern||children +childs||children +chiled||child +chked||checked +chnage||change +chnages||changes +chnnel||channel +choosen||chosen +chouse||chose +circumvernt||circumvent +claread||cleared +clared||cleared +closeing||closing +clustred||clustered +cnfiguration||configuration +coexistance||coexistence +colescing||coalescing +collapsable||collapsible +colorfull||colorful +comand||command +comit||commit +commerical||commercial +comming||coming +comminucation||communication +commited||committed +commiting||committing +committ||commit +commnunication||communication +commoditiy||commodity +comsume||consume +comsumer||consumer +comsuming||consuming +comaptible||compatible +compability||compatibility +compaibility||compatibility +comparsion||comparison +compatability||compatibility +compatable||compatible +compatibililty||compatibility +compatibiliy||compatibility +compatibilty||compatibility +compatiblity||compatibility +competion||completion +compilant||compliant +compleatly||completely +completition||completion +completly||completely +complient||compliant +componnents||components +compoment||component +comppatible||compatible +compres||compress +compresion||compression +compresser||compressor +comression||compression +comsumed||consumed +comunicate||communicate +comunication||communication +conbination||combination +conditionaly||conditionally +conditon||condition +condtion||condition +conected||connected +conector||connector +configration||configuration +configred||configured +configuartion||configuration +configuation||configuration +configued||configured +configuratoin||configuration +configuraton||configuration +configuretion||configuration +configutation||configuration +conider||consider +conjuction||conjunction +connecetd||connected +connectinos||connections +connetor||connector +connnection||connection +connnections||connections +consistancy||consistency +consistant||consistent +containes||contains +containts||contains +contaisn||contains +contant||contact +contence||contents +contiguos||contiguous +continious||continuous +continous||continuous +continously||continuously +continueing||continuing +contraints||constraints +contruct||construct +contol||control +contoller||controller +controled||controlled +controler||controller +controll||control +contruction||construction +contry||country +conuntry||country +convertion||conversion +convertor||converter +convienient||convenient +convinient||convenient +corected||corrected +correponding||corresponding +correponds||corresponds +correspoding||corresponding +cotrol||control +cound||could +couter||counter +coutner||counter +cryptocraphic||cryptographic +cunter||counter +curently||currently +cylic||cyclic +dafault||default +deactive||deactivate +deafult||default +deamon||daemon +debouce||debounce +decendant||descendant +decendants||descendants +decompres||decompress +decsribed||described +decription||description +dectected||detected +defailt||default +deferal||deferral +deffered||deferred +defferred||deferred +definate||definite +definately||definitely +definiation||definition +defintion||definition +defintions||definitions +defualt||default +defult||default +deintializing||deinitializing +deintialize||deinitialize +deintialized||deinitialized +deivce||device +delared||declared +delare||declare +delares||declares +delaring||declaring +delemiter||delimiter +delievered||delivered +demodualtor||demodulator +demension||dimension +dependancies||dependencies +dependancy||dependency +dependant||dependent +dependend||dependent +depreacted||deprecated +depreacte||deprecate +desactivate||deactivate +desciptor||descriptor +desciptors||descriptors +descripto||descriptor +descripton||description +descrition||description +descritptor||descriptor +desctiptor||descriptor +desriptor||descriptor +desriptors||descriptors +desination||destination +destionation||destination +destoried||destroyed +destory||destroy +destoryed||destroyed +destorys||destroys +destroied||destroyed +detabase||database +deteced||detected +detectt||detect +develope||develop +developement||development +developped||developed +developpement||development +developper||developer +developpment||development +deveolpment||development +devided||divided +deviece||device +devision||division +diable||disable +diabled||disabled +dicline||decline +dictionnary||dictionary +didnt||didn't +diferent||different +differrence||difference +diffrent||different +differenciate||differentiate +diffrentiate||differentiate +difinition||definition +digial||digital +dimention||dimension +dimesions||dimensions +diconnected||disconnected +disabed||disabled +disble||disable +disgest||digest +disired||desired +dispalying||displaying +dissable||disable +diplay||display +directon||direction +direcly||directly +direectly||directly +diregard||disregard +disassocation||disassociation +disapear||disappear +disapeared||disappeared +disappared||disappeared +disbale||disable +disbaled||disabled +disble||disable +disbled||disabled +disconnet||disconnect +discontinous||discontinuous +disharge||discharge +disnabled||disabled +dispertion||dispersion +dissapears||disappears +dissconect||disconnect +distiction||distinction +divisable||divisible +divsiors||divisors +dsiabled||disabled +docuentation||documentation +documantation||documentation +documentaion||documentation +documment||document +doesnt||doesn't +donwload||download +donwloading||downloading +dorp||drop +dosen||doesn +downlad||download +downlads||downloads +droped||dropped +droput||dropout +druing||during +dyanmic||dynamic +dynmaic||dynamic +eanable||enable +eanble||enable +easilly||easily +ecspecially||especially +edditable||editable +editting||editing +efective||effective +effectivness||effectiveness +efficently||efficiently +ehther||ether +eigth||eight +elementry||elementary +eletronic||electronic +embeded||embedded +enabledi||enabled +enbale||enable +enble||enable +enchanced||enhanced +encorporating||incorporating +encrupted||encrypted +encrypiton||encryption +encryptio||encryption +endianess||endianness +enpoint||endpoint +enhaced||enhanced +enlightnment||enlightenment +enqueing||enqueuing +entires||entries +entites||entities +entrys||entries +enocded||encoded +enought||enough +enterily||entirely +enviroiment||environment +enviroment||environment +environement||environment +environent||environment +eqivalent||equivalent +equiped||equipped +equivelant||equivalent +equivilant||equivalent +eror||error +errorr||error +errror||error +estbalishment||establishment +etsablishment||establishment +etsbalishment||establishment +evalute||evaluate +evalutes||evaluates +evalution||evaluation +excecutable||executable +exceded||exceeded +exceds||exceeds +exceeed||exceed +excellant||excellent +exchnage||exchange +execeeded||exceeded +execeeds||exceeds +exeed||exceed +exeeds||exceeds +exeuction||execution +existance||existence +existant||existent +exixt||exist +exlcude||exclude +exlcusive||exclusive +exmaple||example +expecially||especially +experies||expires +explicite||explicit +explicitely||explicitly +explict||explicit +explictely||explicitly +explictly||explicitly +expresion||expression +exprimental||experimental +extened||extended +exteneded||extended +extensability||extensibility +extention||extension +extenstion||extension +extracter||extractor +faied||failed +faield||failed +faild||failed +failded||failed +failer||failure +faill||fail +failied||failed +faillure||failure +failue||failure +failuer||failure +failng||failing +faireness||fairness +falied||failed +faliure||failure +fallbck||fallback +familar||familiar +fatser||faster +feauture||feature +feautures||features +fetaure||feature +fetaures||features +fileystem||filesystem +fimrware||firmware +fimware||firmware +firmare||firmware +firmaware||firmware +firware||firmware +firwmare||firmware +finanize||finalize +findn||find +finilizes||finalizes +finsih||finish +flusing||flushing +folloing||following +followign||following +followings||following +follwing||following +fonud||found +forseeable||foreseeable +forse||force +fortan||fortran +forwardig||forwarding +frambuffer||framebuffer +framming||framing +framwork||framework +frequence||frequency +frequncy||frequency +frequancy||frequency +frome||from +fronend||frontend +fucntion||function +fuction||function +fuctions||functions +fullill||fulfill +funcation||function +funcion||function +functionallity||functionality +functionaly||functionally +functionnality||functionality +functonality||functionality +funtion||function +funtions||functions +furthur||further +futhermore||furthermore +futrue||future +gatable||gateable +gateing||gating +gauage||gauge +gaurenteed||guaranteed +generiously||generously +genereate||generate +genereted||generated +genric||generic +globel||global +grabing||grabbing +grahical||graphical +grahpical||graphical +granularty||granularity +grapic||graphic +grranted||granted +guage||gauge +guarenteed||guaranteed +guarentee||guarantee +halfs||halves +hander||handler +handfull||handful +hanlde||handle +hanled||handled +happend||happened +hardare||hardware +harware||hardware +havind||having +heirarchically||hierarchically +heirarchy||hierarchy +helpfull||helpful +hearbeat||heartbeat +heterogenous||heterogeneous +hexdecimal||hexadecimal +hybernate||hibernate +hierachy||hierarchy +hierarchie||hierarchy +homogenous||homogeneous +howver||however +hsould||should +hypervior||hypervisor +hypter||hyper +identidier||identifier +iligal||illegal +illigal||illegal +illgal||illegal +iomaped||iomapped +imblance||imbalance +immeadiately||immediately +immedaite||immediate +immedate||immediate +immediatelly||immediately +immediatly||immediately +immidiate||immediate +immutible||immutable +impelentation||implementation +impementated||implemented +implemantation||implementation +implemenation||implementation +implementaiton||implementation +implementated||implemented +implemention||implementation +implementd||implemented +implemetation||implementation +implemntation||implementation +implentation||implementation +implmentation||implementation +implmenting||implementing +incative||inactive +incomming||incoming +incompaitiblity||incompatibility +incompatabilities||incompatibilities +incompatable||incompatible +incompatble||incompatible +inconsistant||inconsistent +increas||increase +incremeted||incremented +incrment||increment +incuding||including +inculde||include +indendation||indentation +indended||intended +independant||independent +independantly||independently +independed||independent +indiate||indicate +indicat||indicate +inexpect||inexpected +inferface||interface +infinit||infinite +infomation||information +informatiom||information +informations||information +informtion||information +infromation||information +ingore||ignore +inital||initial +initalized||initialized +initalised||initialized +initalise||initialize +initalize||initialize +initation||initiation +initators||initiators +initialiazation||initialization +initializationg||initialization +initializiation||initialization +initialze||initialize +initialzed||initialized +initialzing||initializing +initilization||initialization +initilize||initialize +initliaze||initialize +initilized||initialized +inofficial||unofficial +inrerface||interface +insititute||institute +instace||instance +instal||install +instanciate||instantiate +instanciated||instantiated +instuments||instruments +insufficent||insufficient +inteface||interface +integreated||integrated +integrety||integrity +integrey||integrity +intendet||intended +intented||intended +interanl||internal +interchangable||interchangeable +interferring||interfering +interger||integer +intergrated||integrated +intermittant||intermittent +internel||internal +interoprability||interoperability +interuupt||interrupt +interupt||interrupt +interupts||interrupts +interrface||interface +interrrupt||interrupt +interrup||interrupt +interrups||interrupts +interruptted||interrupted +interupted||interrupted +intiailized||initialized +intial||initial +intialisation||initialisation +intialised||initialised +intialise||initialise +intialization||initialization +intialized||initialized +intialize||initialize +intregral||integral +intrerrupt||interrupt +intrrupt||interrupt +intterrupt||interrupt +intuative||intuitive +inavlid||invalid +invaid||invalid +invaild||invalid +invailid||invalid +invald||invalid +invalde||invalid +invalide||invalid +invalidiate||invalidate +invalud||invalid +invididual||individual +invokation||invocation +invokations||invocations +ireelevant||irrelevant +irrelevent||irrelevant +isnt||isn't +isssue||issue +issus||issues +iteraions||iterations +iternations||iterations +itertation||iteration +itslef||itself +jave||java +jeffies||jiffies +jumpimng||jumping +juse||just +jus||just +kown||known +langage||language +langauage||language +langauge||language +langugage||language +lauch||launch +layed||laid +legnth||length +leightweight||lightweight +lengh||length +lenght||length +lenth||length +lesstiff||lesstif +libaries||libraries +libary||library +librairies||libraries +libraris||libraries +licenceing||licencing +limted||limited +logaritmic||logarithmic +loggging||logging +loggin||login +logile||logfile +loobpack||loopback +loosing||losing +losted||lost +maangement||management +machinary||machinery +maibox||mailbox +maintainance||maintenance +maintainence||maintenance +maintan||maintain +makeing||making +mailformed||malformed +malplaced||misplaced +malplace||misplace +managable||manageable +managament||management +managment||management +mangement||management +manger||manager +manoeuvering||maneuvering +manufaucturing||manufacturing +mappping||mapping +maping||mapping +matchs||matches +mathimatical||mathematical +mathimatic||mathematic +mathimatics||mathematics +maximium||maximum +maxium||maximum +mechamism||mechanism +meetign||meeting +memeory||memory +memmber||member +memoery||memory +memroy||memory +ment||meant +mergable||mergeable +mesage||message +messags||messages +messgaes||messages +messsage||message +messsages||messages +metdata||metadata +micropone||microphone +microprocesspr||microprocessor +migrateable||migratable +millenium||millennium +milliseonds||milliseconds +minium||minimum +minimam||minimum +minimun||minimum +miniumum||minimum +minumum||minimum +misalinged||misaligned +miscelleneous||miscellaneous +misformed||malformed +mispelled||misspelled +mispelt||misspelt +mising||missing +mismactch||mismatch +missign||missing +missmanaged||mismanaged +missmatch||mismatch +misssing||missing +miximum||maximum +mmnemonic||mnemonic +mnay||many +modfiy||modify +modifer||modifier +modul||module +modulues||modules +momery||memory +memomry||memory +monitring||monitoring +monochorome||monochrome +monochromo||monochrome +monocrome||monochrome +mopdule||module +mroe||more +multipler||multiplier +mulitplied||multiplied +multidimensionnal||multidimensional +multipe||multiple +multple||multiple +mumber||number +muticast||multicast +mutilcast||multicast +mutiple||multiple +mutli||multi +nams||names +navagating||navigating +nead||need +neccecary||necessary +neccesary||necessary +neccessary||necessary +necesary||necessary +neded||needed +negaive||negative +negoitation||negotiation +negotation||negotiation +nerver||never +nescessary||necessary +nessessary||necessary +noticable||noticeable +notication||notification +notications||notifications +notifcations||notifications +notifed||notified +notity||notify +nubmer||number +numebr||number +numner||number +nunber||number +obtaion||obtain +obusing||abusing +occassionally||occasionally +occationally||occasionally +occurance||occurrence +occurances||occurrences +occurd||occurred +occured||occurred +occurence||occurrence +occure||occurred +occuring||occurring +offser||offset +offet||offset +offlaod||offload +offloded||offloaded +offseting||offsetting +omited||omitted +omiting||omitting +omitt||omit +ommiting||omitting +ommitted||omitted +onself||oneself +ony||only +openning||opening +operatione||operation +opertaions||operations +opportunies||opportunities +optionnal||optional +optmizations||optimizations +orientatied||orientated +orientied||oriented +orignal||original +originial||original +otherise||otherwise +ouput||output +oustanding||outstanding +overaall||overall +overhread||overhead +overlaping||overlapping +oveflow||overflow +overflw||overflow +overlfow||overflow +overide||override +overrided||overridden +overriden||overridden +overrrun||overrun +overun||overrun +overwritting||overwriting +overwriten||overwritten +pacakge||package +pachage||package +packacge||package +packege||package +packge||package +packtes||packets +pakage||package +paket||packet +pallette||palette +paln||plan +paramameters||parameters +paramaters||parameters +paramater||parameter +parametes||parameters +parametised||parametrised +paramter||parameter +paramters||parameters +parmaters||parameters +particuarly||particularly +particularily||particularly +partion||partition +partions||partitions +partiton||partition +pased||passed +passin||passing +pathes||paths +pattrns||patterns +pecularities||peculiarities +peformance||performance +peforming||performing +peice||piece +pendantic||pedantic +peprocessor||preprocessor +perfomance||performance +perfoming||performing +perfomring||performing +periperal||peripheral +peripherial||peripheral +permissons||permissions +peroid||period +persistance||persistence +persistant||persistent +phoneticly||phonetically +plalform||platform +platfoem||platform +platfrom||platform +plattform||platform +pleaes||please +ploting||plotting +plugable||pluggable +poinnter||pointer +pointeur||pointer +poiter||pointer +posible||possible +positon||position +possibilites||possibilities +potocol||protocol +powerfull||powerful +pramater||parameter +preamle||preamble +preample||preamble +preapre||prepare +preceeded||preceded +preceeding||preceding +preceed||precede +precendence||precedence +precission||precision +preemptable||preemptible +prefered||preferred +prefferably||preferably +prefitler||prefilter +preform||perform +premption||preemption +prepaired||prepared +prepate||prepare +preperation||preparation +preprare||prepare +pressre||pressure +presuambly||presumably +previosuly||previously +previsously||previously +primative||primitive +princliple||principle +priorty||priority +privilaged||privileged +privilage||privilege +priviledge||privilege +priviledges||privileges +privleges||privileges +probaly||probably +procceed||proceed +proccesors||processors +procesed||processed +proces||process +procesing||processing +processessing||processing +processess||processes +processpr||processor +processsed||processed +processsing||processing +procteted||protected +prodecure||procedure +progamming||programming +progams||programs +progess||progress +programable||programmable +programers||programmers +programm||program +programms||programs +progres||progress +progresss||progress +prohibitted||prohibited +prohibitting||prohibiting +promiscous||promiscuous +promps||prompts +pronnounced||pronounced +prononciation||pronunciation +pronouce||pronounce +pronunce||pronounce +propery||property +propigate||propagate +propigation||propagation +propogation||propagation +propogate||propagate +prosess||process +protable||portable +protcol||protocol +protecion||protection +protedcted||protected +protocoll||protocol +promixity||proximity +psudo||pseudo +psuedo||pseudo +psychadelic||psychedelic +purgable||purgeable +pwoer||power +queing||queuing +quering||querying +queus||queues +randomally||randomly +raoming||roaming +reasearcher||researcher +reasearchers||researchers +reasearch||research +receieve||receive +recepient||recipient +recevied||received +receving||receiving +recievd||received +recieved||received +recieve||receive +reciever||receiver +recieves||receives +recieving||receiving +recogniced||recognised +recognizeable||recognizable +recommanded||recommended +recyle||recycle +redircet||redirect +redirectrion||redirection +redundacy||redundancy +reename||rename +refcounf||refcount +refence||reference +refered||referred +referenace||reference +refering||referring +refernces||references +refernnce||reference +refrence||reference +registed||registered +registerd||registered +registeration||registration +registeresd||registered +registerred||registered +registes||registers +registraration||registration +regsiter||register +regster||register +regualar||regular +reguator||regulator +regulamentations||regulations +reigstration||registration +releated||related +relevent||relevant +reloade||reload +remoote||remote +remore||remote +removeable||removable +repectively||respectively +replacable||replaceable +replacments||replacements +replys||replies +reponse||response +representaion||representation +reqeust||request +reqister||register +requed||requeued +requestied||requested +requiere||require +requirment||requirement +requred||required +requried||required +requst||request +requsted||requested +reregisteration||reregistration +reseting||resetting +reseved||reserved +reseverd||reserved +resizeable||resizable +resouce||resource +resouces||resources +resoures||resources +responce||response +resrouce||resource +ressizes||resizes +ressource||resource +ressources||resources +restesting||retesting +resumbmitting||resubmitting +retransmited||retransmitted +retreived||retrieved +retreive||retrieve +retreiving||retrieving +retrive||retrieve +retrived||retrieved +retrun||return +retun||return +retuned||returned +reudce||reduce +reuest||request +reuqest||request +reutnred||returned +revsion||revision +rmeoved||removed +rmeove||remove +rmeoves||removes +rountine||routine +routins||routines +rquest||request +runing||running +runned||ran +runnnig||running +runnning||running +runtine||runtime +sacrifying||sacrificing +safly||safely +safty||safety +savable||saveable +scaleing||scaling +scaned||scanned +scaning||scanning +scarch||search +schdule||schedule +seach||search +searchs||searches +secion||section +secquence||sequence +secund||second +segement||segment +seleted||selected +semaphone||semaphore +senario||scenario +senarios||scenarios +sentivite||sensitive +separatly||separately +sepcify||specify +seperated||separated +seperately||separately +seperate||separate +seperatly||separately +seperator||separator +sepperate||separate +seqeunce||sequence +seqeuncer||sequencer +seqeuencer||sequencer +sequece||sequence +sequemce||sequence +sequencial||sequential +serivce||service +serveral||several +servive||service +setts||sets +settting||setting +shapshot||snapshot +shoft||shift +shotdown||shutdown +shoud||should +shouldnt||shouldn't +shoule||should +shrinked||shrunk +siginificantly||significantly +signabl||signal +significanly||significantly +similary||similarly +similiar||similar +simlar||similar +simliar||similar +simpified||simplified +simultanous||simultaneous +singaled||signaled +singal||signal +singed||signed +sleeped||slept +sliped||slipped +softwade||software +softwares||software +soley||solely +souce||source +speach||speech +specfic||specific +specfield||specified +speciefied||specified +specifc||specific +specifed||specified +specificatin||specification +specificaton||specification +specificed||specified +specifing||specifying +specifiy||specify +specifiying||specifying +speficied||specified +speicify||specify +speling||spelling +spinlcok||spinlock +spinock||spinlock +splitted||split +spreaded||spread +spurrious||spurious +sructure||structure +stablilization||stabilization +staically||statically +staion||station +standardss||standards +standartization||standardization +standart||standard +standy||standby +stardard||standard +staticly||statically +statuss||status +stoped||stopped +stoping||stopping +stoppped||stopped +straming||streaming +struc||struct +structres||structures +stuct||struct +strucuture||structure +stucture||structure +sturcture||structure +subdirectoires||subdirectories +suble||subtle +substract||subtract +submited||submitted +submition||submission +succeded||succeeded +suceed||succeed +succesfully||successfully +succesful||successful +successed||succeeded +successfull||successful +successfuly||successfully +sucessfully||successfully +sucessful||successful +sucess||success +superflous||superfluous +superseeded||superseded +suplied||supplied +suported||supported +suport||support +supportet||supported +suppored||supported +supportin||supporting +suppoted||supported +suppported||supported +suppport||support +supprot||support +supress||suppress +surpressed||suppressed +surpresses||suppresses +susbsystem||subsystem +suspeneded||suspended +suspsend||suspend +suspicously||suspiciously +swaping||swapping +switchs||switches +swith||switch +swithable||switchable +swithc||switch +swithced||switched +swithcing||switching +swithed||switched +swithing||switching +swtich||switch +syfs||sysfs +symetric||symmetric +synax||syntax +synchonized||synchronized +sychronization||synchronization +synchronuously||synchronously +syncronize||synchronize +syncronized||synchronized +syncronizing||synchronizing +syncronus||synchronous +syste||system +sytem||system +sythesis||synthesis +taht||that +tained||tainted +tansmit||transmit +targetted||targeted +targetting||targeting +taskelt||tasklet +teh||the +temorary||temporary +temproarily||temporarily +temperture||temperature +thead||thread +therfore||therefore +thier||their +threds||threads +threee||three +threshhold||threshold +thresold||threshold +throught||through +trackling||tracking +troughput||throughput +trys||tries +thses||these +tiggers||triggers +tiggered||triggered +tipically||typically +timeing||timing +timout||timeout +tmis||this +toogle||toggle +torerable||tolerable +torlence||tolerance +traget||target +traking||tracking +tramsmitted||transmitted +tramsmit||transmit +tranasction||transaction +tranceiver||transceiver +tranfer||transfer +tranmission||transmission +transcevier||transceiver +transciever||transceiver +transferd||transferred +transfered||transferred +transfering||transferring +transision||transition +transistioned||transitioned +transmittd||transmitted +transormed||transformed +trasfer||transfer +trasmission||transmission +treshold||threshold +triggerd||triggered +trigerred||triggered +trigerring||triggering +trun||turn +tunning||tuning +ture||true +tyep||type +udpate||update +uesd||used +uknown||unknown +usccess||success +uncommited||uncommitted +uncompatible||incompatible +unconditionaly||unconditionally +undeflow||underflow +underun||underrun +unecessary||unnecessary +unexecpted||unexpected +unexepected||unexpected +unexpcted||unexpected +unexpectd||unexpected +unexpeted||unexpected +unexpexted||unexpected +unfortunatelly||unfortunately +unifiy||unify +uniterrupted||uninterrupted +uninterruptable||uninterruptible +unintialized||uninitialized +unitialized||uninitialized +unkmown||unknown +unknonw||unknown +unknouwn||unknown +unknow||unknown +unkown||unknown +unamed||unnamed +uneeded||unneeded +unneded||unneeded +unneccecary||unnecessary +unneccesary||unnecessary +unneccessary||unnecessary +unnecesary||unnecessary +unneedingly||unnecessarily +unnsupported||unsupported +unmached||unmatched +unprecise||imprecise +unregester||unregister +unresgister||unregister +unrgesiter||unregister +unsinged||unsigned +unstabel||unstable +unsolicitied||unsolicited +unsuccessfull||unsuccessful +unsuported||unsupported +untill||until +ununsed||unused +unuseful||useless +unvalid||invalid +upate||update +upsupported||unsupported +useable||usable +usefule||useful +usefull||useful +usege||usage +usera||users +usualy||usually +usupported||unsupported +utilites||utilities +utillities||utilities +utilties||utilities +utiltity||utility +utitity||utility +utitlty||utility +vaid||valid +vaild||valid +valide||valid +variantions||variations +varible||variable +varient||variant +vaule||value +verbse||verbose +veify||verify +verfication||verification +veriosn||version +verisons||versions +verison||version +verson||version +vicefersa||vice-versa +virtal||virtual +virtaul||virtual +virtiual||virtual +visiters||visitors +vitual||virtual +vunerable||vulnerable +wakeus||wakeups +was't||wasn't +wathdog||watchdog +wating||waiting +wiat||wait +wether||whether +whataver||whatever +whcih||which +whenver||whenever +wheter||whether +whe||when +wierd||weird +wiil||will +wirte||write +withing||within +wnat||want +wont||won't +workarould||workaround +writeing||writing +writting||writing +wtih||with +zombe||zombie +zomebie||zombie diff --git a/tools/scripts/typedefs.txt b/tools/scripts/typedefs.txt new file mode 100644 index 0000000000..97f330d9dc --- /dev/null +++ b/tools/scripts/typedefs.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +fd_set +Jim_Cmd +Jim_CmdProc +Jim_DelCmdProc +Jim_Interp +Jim_Obj